10Sstevel@tonic-gate /*
28805SJan.Pechanec@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /* crypto/engine/hw_pk11.c */
77616SVladimir.Kotal@Sun.COM /*
87616SVladimir.Kotal@Sun.COM * This product includes software developed by the OpenSSL Project for
90Sstevel@tonic-gate * use in the OpenSSL Toolkit (http://www.openssl.org/).
100Sstevel@tonic-gate *
117616SVladimir.Kotal@Sun.COM * This project also referenced hw_pkcs11-0.9.7b.patch written by
120Sstevel@tonic-gate * Afchine Madjlessi.
130Sstevel@tonic-gate */
147616SVladimir.Kotal@Sun.COM /*
157616SVladimir.Kotal@Sun.COM * ====================================================================
160Sstevel@tonic-gate * Copyright (c) 2000-2001 The OpenSSL Project. All rights reserved.
170Sstevel@tonic-gate *
180Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
190Sstevel@tonic-gate * modification, are permitted provided that the following conditions
200Sstevel@tonic-gate * are met:
210Sstevel@tonic-gate *
220Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
237616SVladimir.Kotal@Sun.COM * notice, this list of conditions and the following disclaimer.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
260Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in
270Sstevel@tonic-gate * the documentation and/or other materials provided with the
280Sstevel@tonic-gate * distribution.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this
310Sstevel@tonic-gate * software must display the following acknowledgment:
320Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
330Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
360Sstevel@tonic-gate * endorse or promote products derived from this software without
370Sstevel@tonic-gate * prior written permission. For written permission, please contact
380Sstevel@tonic-gate * licensing@OpenSSL.org.
390Sstevel@tonic-gate *
400Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL"
410Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written
420Sstevel@tonic-gate * permission of the OpenSSL Project.
430Sstevel@tonic-gate *
440Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following
450Sstevel@tonic-gate * acknowledgment:
460Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
470Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
480Sstevel@tonic-gate *
490Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
500Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
510Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
520Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
530Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
540Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
550Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
560Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
570Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
580Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
590Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
600Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE.
610Sstevel@tonic-gate * ====================================================================
620Sstevel@tonic-gate *
630Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young
640Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim
650Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com).
660Sstevel@tonic-gate *
670Sstevel@tonic-gate */
680Sstevel@tonic-gate
690Sstevel@tonic-gate #include <stdio.h>
700Sstevel@tonic-gate #include <stdlib.h>
710Sstevel@tonic-gate #include <string.h>
720Sstevel@tonic-gate #include <sys/types.h>
730Sstevel@tonic-gate #include <unistd.h>
740Sstevel@tonic-gate
750Sstevel@tonic-gate #include <openssl/e_os2.h>
766847Svk199839 #include <openssl/crypto.h>
770Sstevel@tonic-gate #include <openssl/engine.h>
780Sstevel@tonic-gate #include <openssl/dso.h>
790Sstevel@tonic-gate #include <openssl/err.h>
800Sstevel@tonic-gate #include <openssl/bn.h>
812139Sjp161948 #include <openssl/md5.h>
820Sstevel@tonic-gate #include <openssl/pem.h>
836847Svk199839 #ifndef OPENSSL_NO_RSA
840Sstevel@tonic-gate #include <openssl/rsa.h>
856847Svk199839 #endif
866847Svk199839 #ifndef OPENSSL_NO_DSA
876847Svk199839 #include <openssl/dsa.h>
886847Svk199839 #endif
896847Svk199839 #ifndef OPENSSL_NO_DH
906847Svk199839 #include <openssl/dh.h>
916847Svk199839 #endif
920Sstevel@tonic-gate #include <openssl/rand.h>
930Sstevel@tonic-gate #include <openssl/objects.h>
940Sstevel@tonic-gate #include <openssl/x509.h>
957211Sjp161948 #include <openssl/aes.h>
960Sstevel@tonic-gate #include <cryptlib.h>
977211Sjp161948 #include <dlfcn.h>
987526SVladimir.Kotal@Sun.COM #include <pthread.h>
990Sstevel@tonic-gate
1000Sstevel@tonic-gate #ifndef OPENSSL_NO_HW
1010Sstevel@tonic-gate #ifndef OPENSSL_NO_HW_PK11
1020Sstevel@tonic-gate
1037211Sjp161948 /* label for debug messages printed on stderr */
1047211Sjp161948 #define PK11_DBG "PKCS#11 ENGINE DEBUG"
1057211Sjp161948 /* prints a lot of debug messages on stderr about slot selection process */
1067211Sjp161948 #undef DEBUG_SLOT_SELECTION
1077211Sjp161948 /*
1087211Sjp161948 * Solaris specific code. See comment at check_hw_mechanisms() for more
1097211Sjp161948 * information.
1107211Sjp161948 */
1117211Sjp161948 #define SOLARIS_HW_SLOT_SELECTION
1127211Sjp161948
1137211Sjp161948 /*
1147211Sjp161948 * AES counter mode is not supported in the OpenSSL EVP API yet and neither
1157211Sjp161948 * there are official OIDs for mechanisms based on this mode. With our changes,
1167211Sjp161948 * an application can define its own EVP calls for AES counter mode and then
1177211Sjp161948 * it can make use of hardware acceleration through this engine. However, it's
1187211Sjp161948 * better if we keep AES CTR support code under ifdef's.
1197211Sjp161948 */
1207211Sjp161948 #define SOLARIS_AES_CTR
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate #include "security/cryptoki.h"
1230Sstevel@tonic-gate #include "security/pkcs11.h"
1240Sstevel@tonic-gate #include "hw_pk11_err.c"
1250Sstevel@tonic-gate
1267211Sjp161948 #ifdef SOLARIS_AES_CTR
1277211Sjp161948 /*
1287211Sjp161948 * NIDs for AES counter mode that will be defined during the engine
1297211Sjp161948 * initialization.
1307211Sjp161948 */
1317211Sjp161948 int NID_aes_128_ctr = NID_undef;
1327211Sjp161948 int NID_aes_192_ctr = NID_undef;
1337211Sjp161948 int NID_aes_256_ctr = NID_undef;
1347211Sjp161948 #endif /* SOLARIS_AES_CTR */
1357211Sjp161948
1367211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
1377211Sjp161948 /*
1387211Sjp161948 * Tables for symmetric ciphers and digest mechs found in the pkcs11_kernel
1397211Sjp161948 * library. See comment at check_hw_mechanisms() for more information.
1407211Sjp161948 */
1417211Sjp161948 int *hw_cnids;
1427211Sjp161948 int *hw_dnids;
1437211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
1447211Sjp161948
1457526SVladimir.Kotal@Sun.COM /* PKCS#11 session caches and their locks for all operation types */
1467526SVladimir.Kotal@Sun.COM static PK11_CACHE session_cache[OP_MAX];
1477526SVladimir.Kotal@Sun.COM
1487211Sjp161948 /*
1497526SVladimir.Kotal@Sun.COM * As stated in v2.20, 11.7 Object Management Function, in section for
1507526SVladimir.Kotal@Sun.COM * C_FindObjectsInit(), at most one search operation may be active at a given
1517526SVladimir.Kotal@Sun.COM * time in a given session. Therefore, C_Find{,Init,Final}Objects() should be
1527526SVladimir.Kotal@Sun.COM * grouped together to form one atomic search operation. This is already
1537526SVladimir.Kotal@Sun.COM * ensured by the property of unique PKCS#11 session handle used for each
1547526SVladimir.Kotal@Sun.COM * PK11_SESSION object.
1557526SVladimir.Kotal@Sun.COM *
1567526SVladimir.Kotal@Sun.COM * This is however not the biggest concern - maintaining consistency of the
1577526SVladimir.Kotal@Sun.COM * underlying object store is more important. The same section of the spec also
1587526SVladimir.Kotal@Sun.COM * says that one thread can be in the middle of a search operation while another
1597526SVladimir.Kotal@Sun.COM * thread destroys the object matching the search template which would result in
1607526SVladimir.Kotal@Sun.COM * invalid handle returned from the search operation.
1617526SVladimir.Kotal@Sun.COM *
1627526SVladimir.Kotal@Sun.COM * Hence, the following locks are used for both protection of the object stores.
1637526SVladimir.Kotal@Sun.COM * They are also used for active list protection.
1647211Sjp161948 */
1657526SVladimir.Kotal@Sun.COM pthread_mutex_t *find_lock[OP_MAX] = { NULL };
1667526SVladimir.Kotal@Sun.COM
1677526SVladimir.Kotal@Sun.COM /*
1687526SVladimir.Kotal@Sun.COM * lists of asymmetric key handles which are active (referenced by at least one
1697526SVladimir.Kotal@Sun.COM * PK11_SESSION structure, either held by a thread or present in free_session
1707526SVladimir.Kotal@Sun.COM * list) for given algorithm type
1717526SVladimir.Kotal@Sun.COM */
1727526SVladimir.Kotal@Sun.COM PK11_active *active_list[OP_MAX] = { NULL };
1737526SVladimir.Kotal@Sun.COM
1747526SVladimir.Kotal@Sun.COM /*
1757526SVladimir.Kotal@Sun.COM * Create all secret key objects in a global session so that they are available
1760Sstevel@tonic-gate * to use for other sessions. These other sessions may be opened or closed
1777526SVladimir.Kotal@Sun.COM * without losing the secret key objects.
1787526SVladimir.Kotal@Sun.COM */
1790Sstevel@tonic-gate static CK_SESSION_HANDLE global_session = CK_INVALID_HANDLE;
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /* ENGINE level stuff */
1820Sstevel@tonic-gate static int pk11_init(ENGINE *e);
1830Sstevel@tonic-gate static int pk11_library_init(ENGINE *e);
1840Sstevel@tonic-gate static int pk11_finish(ENGINE *e);
1850Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
1860Sstevel@tonic-gate static int pk11_destroy(ENGINE *e);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /* RAND stuff */
1890Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num);
1900Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add_entropy);
1910Sstevel@tonic-gate static void pk11_rand_cleanup(void);
1920Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num);
1930Sstevel@tonic-gate static int pk11_rand_status(void);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /* These functions are also used in other files */
1967211Sjp161948 PK11_SESSION *pk11_get_session(PK11_OPTYPE optype);
1977211Sjp161948 void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype);
1986847Svk199839
1997526SVladimir.Kotal@Sun.COM /* active list manipulation functions used in this file */
2007526SVladimir.Kotal@Sun.COM extern int pk11_active_delete(CK_OBJECT_HANDLE h, PK11_OPTYPE type);
2017526SVladimir.Kotal@Sun.COM extern void pk11_free_active_list(PK11_OPTYPE type);
2026847Svk199839
2036847Svk199839 #ifndef OPENSSL_NO_RSA
2040Sstevel@tonic-gate int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
2056847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2066847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2076847Svk199839 #endif
2086847Svk199839 #ifndef OPENSSL_NO_DSA
2090Sstevel@tonic-gate int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
2106847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2116847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2126847Svk199839 #endif
2136847Svk199839 #ifndef OPENSSL_NO_DH
2140Sstevel@tonic-gate int pk11_destroy_dh_key_objects(PK11_SESSION *session);
2156847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *session, CK_BBOOL uselock);
2166847Svk199839 #endif
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate /* Local helper functions */
2197211Sjp161948 static int pk11_free_all_sessions(void);
2207526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype);
2217211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype);
2220Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session);
2236847Svk199839 static int pk11_destroy_object(CK_SESSION_HANDLE session,
2240Sstevel@tonic-gate CK_OBJECT_HANDLE oh);
2250Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void);
2260Sstevel@tonic-gate static void free_PK11_LIBNAME(void);
2270Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name);
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /* Symmetric cipher and digest support functions */
2300Sstevel@tonic-gate static int cipher_nid_to_pk11(int nid);
2317211Sjp161948 #ifdef SOLARIS_AES_CTR
2327211Sjp161948 static int pk11_add_NID(char *sn, char *ln);
2337211Sjp161948 static int pk11_add_aes_ctr_NIDs(void);
2347211Sjp161948 #endif /* SOLARIS_AES_CTR */
2350Sstevel@tonic-gate static int pk11_usable_ciphers(const int **nids);
2360Sstevel@tonic-gate static int pk11_usable_digests(const int **nids);
2370Sstevel@tonic-gate static int pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
2380Sstevel@tonic-gate const unsigned char *iv, int enc);
2390Sstevel@tonic-gate static int pk11_cipher_final(PK11_SESSION *sp);
2400Sstevel@tonic-gate static int pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
2410Sstevel@tonic-gate const unsigned char *in, unsigned int inl);
2420Sstevel@tonic-gate static int pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx);
2430Sstevel@tonic-gate static int pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
2440Sstevel@tonic-gate const int **nids, int nid);
2450Sstevel@tonic-gate static int pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
2460Sstevel@tonic-gate const int **nids, int nid);
2477616SVladimir.Kotal@Sun.COM static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
2480Sstevel@tonic-gate const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp);
2497211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
2507211Sjp161948 int key_len);
2510Sstevel@tonic-gate static int md_nid_to_pk11(int nid);
2520Sstevel@tonic-gate static int pk11_digest_init(EVP_MD_CTX *ctx);
2537616SVladimir.Kotal@Sun.COM static int pk11_digest_update(EVP_MD_CTX *ctx, const void *data,
2542139Sjp161948 size_t count);
2557616SVladimir.Kotal@Sun.COM static int pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md);
2567616SVladimir.Kotal@Sun.COM static int pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from);
2570Sstevel@tonic-gate static int pk11_digest_cleanup(EVP_MD_CTX *ctx);
2580Sstevel@tonic-gate
2597211Sjp161948 static int pk11_choose_slots(int *any_slot_found);
2607211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
2617211Sjp161948 CK_SLOT_ID current_slot, int *current_slot_n_cipher,
2627211Sjp161948 int *local_cipher_nids);
2637211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
2647211Sjp161948 CK_SLOT_ID current_slot, int *current_slot_n_digest,
2657211Sjp161948 int *local_digest_nids);
2667211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR, int slot_id,
2677211Sjp161948 CK_MECHANISM_TYPE mech, int *current_slot_n_cipher, int *local_cipher_nids,
2687211Sjp161948 int id);
2697211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
2707211Sjp161948 CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
2717211Sjp161948 int id);
2727211Sjp161948
2737526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void);
2747526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void);
2757526SVladimir.Kotal@Sun.COM
2767211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
2777211Sjp161948 static int check_hw_mechanisms(void);
2787211Sjp161948 static int nid_in_table(int nid, int *nid_table);
2797211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /* Index for the supported ciphers */
2827211Sjp161948 enum pk11_cipher_id {
2837211Sjp161948 PK11_DES_CBC,
2847211Sjp161948 PK11_DES3_CBC,
2857211Sjp161948 PK11_DES_ECB,
2867211Sjp161948 PK11_DES3_ECB,
2877211Sjp161948 PK11_RC4,
2887211Sjp161948 PK11_AES_128_CBC,
2897211Sjp161948 PK11_AES_192_CBC,
2907211Sjp161948 PK11_AES_256_CBC,
2917211Sjp161948 PK11_AES_128_ECB,
2927211Sjp161948 PK11_AES_192_ECB,
2937211Sjp161948 PK11_AES_256_ECB,
2947211Sjp161948 PK11_BLOWFISH_CBC,
2957211Sjp161948 #ifdef SOLARIS_AES_CTR
2967211Sjp161948 PK11_AES_128_CTR,
2977211Sjp161948 PK11_AES_192_CTR,
2987211Sjp161948 PK11_AES_256_CTR,
2997211Sjp161948 #endif /* SOLARIS_AES_CTR */
3007211Sjp161948 PK11_CIPHER_MAX
3017211Sjp161948 };
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /* Index for the supported digests */
3047211Sjp161948 enum pk11_digest_id {
3057211Sjp161948 PK11_MD5,
3067211Sjp161948 PK11_SHA1,
3077211Sjp161948 PK11_SHA224,
3087211Sjp161948 PK11_SHA256,
3097211Sjp161948 PK11_SHA384,
3107211Sjp161948 PK11_SHA512,
3117211Sjp161948 PK11_DIGEST_MAX
3127211Sjp161948 };
3130Sstevel@tonic-gate
3147526SVladimir.Kotal@Sun.COM #define TRY_OBJ_DESTROY(sess_hdl, obj_hdl, retval, uselock, alg_type) \
3156847Svk199839 { \
3166847Svk199839 if (uselock) \
3177526SVladimir.Kotal@Sun.COM LOCK_OBJSTORE(alg_type); \
3187526SVladimir.Kotal@Sun.COM if (pk11_active_delete(obj_hdl, alg_type) == 1) \
3196847Svk199839 { \
3206847Svk199839 retval = pk11_destroy_object(sess_hdl, obj_hdl); \
3216847Svk199839 } \
3226847Svk199839 if (uselock) \
3237526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(alg_type); \
3246847Svk199839 }
3256847Svk199839
3260Sstevel@tonic-gate static int cipher_nids[PK11_CIPHER_MAX];
3270Sstevel@tonic-gate static int digest_nids[PK11_DIGEST_MAX];
3280Sstevel@tonic-gate static int cipher_count = 0;
3290Sstevel@tonic-gate static int digest_count = 0;
3300Sstevel@tonic-gate static CK_BBOOL pk11_have_rsa = CK_FALSE;
3310Sstevel@tonic-gate static CK_BBOOL pk11_have_dsa = CK_FALSE;
3320Sstevel@tonic-gate static CK_BBOOL pk11_have_dh = CK_FALSE;
3330Sstevel@tonic-gate static CK_BBOOL pk11_have_random = CK_FALSE;
3340Sstevel@tonic-gate
3357616SVladimir.Kotal@Sun.COM typedef struct PK11_CIPHER_st
3360Sstevel@tonic-gate {
3377211Sjp161948 enum pk11_cipher_id id;
3384320Sjp161948 int nid;
3397211Sjp161948 int iv_len;
3408805SJan.Pechanec@Sun.COM int min_key_len;
3418805SJan.Pechanec@Sun.COM int max_key_len;
3424320Sjp161948 CK_KEY_TYPE key_type;
3434320Sjp161948 CK_MECHANISM_TYPE mech_type;
3440Sstevel@tonic-gate } PK11_CIPHER;
3450Sstevel@tonic-gate
3467616SVladimir.Kotal@Sun.COM static PK11_CIPHER ciphers[] =
3470Sstevel@tonic-gate {
3488805SJan.Pechanec@Sun.COM { PK11_DES_CBC, NID_des_cbc, 8, 8, 8,
3497616SVladimir.Kotal@Sun.COM CKK_DES, CKM_DES_CBC, },
3508805SJan.Pechanec@Sun.COM { PK11_DES3_CBC, NID_des_ede3_cbc, 8, 24, 24,
3517616SVladimir.Kotal@Sun.COM CKK_DES3, CKM_DES3_CBC, },
3528805SJan.Pechanec@Sun.COM { PK11_DES_ECB, NID_des_ecb, 0, 8, 8,
3537616SVladimir.Kotal@Sun.COM CKK_DES, CKM_DES_ECB, },
3548805SJan.Pechanec@Sun.COM { PK11_DES3_ECB, NID_des_ede3_ecb, 0, 24, 24,
3557616SVladimir.Kotal@Sun.COM CKK_DES3, CKM_DES3_ECB, },
3568805SJan.Pechanec@Sun.COM { PK11_RC4, NID_rc4, 0, 16, 256,
3577616SVladimir.Kotal@Sun.COM CKK_RC4, CKM_RC4, },
3588805SJan.Pechanec@Sun.COM { PK11_AES_128_CBC, NID_aes_128_cbc, 16, 16, 16,
3597616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CBC, },
3608805SJan.Pechanec@Sun.COM { PK11_AES_192_CBC, NID_aes_192_cbc, 16, 24, 24,
3617616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CBC, },
3628805SJan.Pechanec@Sun.COM { PK11_AES_256_CBC, NID_aes_256_cbc, 16, 32, 32,
3637616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CBC, },
3648805SJan.Pechanec@Sun.COM { PK11_AES_128_ECB, NID_aes_128_ecb, 0, 16, 16,
3657616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_ECB, },
3668805SJan.Pechanec@Sun.COM { PK11_AES_192_ECB, NID_aes_192_ecb, 0, 24, 24,
3677616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_ECB, },
3688805SJan.Pechanec@Sun.COM { PK11_AES_256_ECB, NID_aes_256_ecb, 0, 32, 32,
3697616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_ECB, },
3708805SJan.Pechanec@Sun.COM { PK11_BLOWFISH_CBC, NID_bf_cbc, 8, 16, 16,
3717616SVladimir.Kotal@Sun.COM CKK_BLOWFISH, CKM_BLOWFISH_CBC, },
3727211Sjp161948 #ifdef SOLARIS_AES_CTR
3737211Sjp161948 /* we don't know the correct NIDs until the engine is initialized */
3748805SJan.Pechanec@Sun.COM { PK11_AES_128_CTR, NID_undef, 16, 16, 16,
3757616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CTR, },
3768805SJan.Pechanec@Sun.COM { PK11_AES_192_CTR, NID_undef, 16, 24, 24,
3777616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CTR, },
3788805SJan.Pechanec@Sun.COM { PK11_AES_256_CTR, NID_undef, 16, 32, 32,
3797616SVladimir.Kotal@Sun.COM CKK_AES, CKM_AES_CTR, },
3807211Sjp161948 #endif /* SOLARIS_AES_CTR */
3810Sstevel@tonic-gate };
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate typedef struct PK11_DIGEST_st
3840Sstevel@tonic-gate {
3857211Sjp161948 enum pk11_digest_id id;
3864320Sjp161948 int nid;
3874320Sjp161948 CK_MECHANISM_TYPE mech_type;
3880Sstevel@tonic-gate } PK11_DIGEST;
3890Sstevel@tonic-gate
3907616SVladimir.Kotal@Sun.COM static PK11_DIGEST digests[] =
3910Sstevel@tonic-gate {
3924320Sjp161948 {PK11_MD5, NID_md5, CKM_MD5, },
3934320Sjp161948 {PK11_SHA1, NID_sha1, CKM_SHA_1, },
3947211Sjp161948 {PK11_SHA224, NID_sha224, CKM_SHA224, },
3957211Sjp161948 {PK11_SHA256, NID_sha256, CKM_SHA256, },
3967211Sjp161948 {PK11_SHA384, NID_sha384, CKM_SHA384, },
3977211Sjp161948 {PK11_SHA512, NID_sha512, CKM_SHA512, },
3984320Sjp161948 {0, NID_undef, 0xFFFF, },
3990Sstevel@tonic-gate };
4000Sstevel@tonic-gate
4017616SVladimir.Kotal@Sun.COM /*
4027616SVladimir.Kotal@Sun.COM * Structure to be used for the cipher_data/md_data in
4037616SVladimir.Kotal@Sun.COM * EVP_CIPHER_CTX/EVP_MD_CTX structures in order to use the same pk11
4047616SVladimir.Kotal@Sun.COM * session in multiple cipher_update calls
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate typedef struct PK11_CIPHER_STATE_st
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate PK11_SESSION *sp;
4090Sstevel@tonic-gate } PK11_CIPHER_STATE;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate
4127211Sjp161948 /*
4137211Sjp161948 * libcrypto EVP stuff - this is how we get wired to EVP so the engine gets
4147211Sjp161948 * called when libcrypto requests a cipher NID.
4157211Sjp161948 *
4160Sstevel@tonic-gate * Note how the PK11_CIPHER_STATE is used here.
4170Sstevel@tonic-gate */
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate /* DES CBC EVP */
4207616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_des_cbc =
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate NID_des_cbc,
4230Sstevel@tonic-gate 8, 8, 8,
4240Sstevel@tonic-gate EVP_CIPH_CBC_MODE,
4250Sstevel@tonic-gate pk11_cipher_init,
4260Sstevel@tonic-gate pk11_cipher_do_cipher,
4270Sstevel@tonic-gate pk11_cipher_cleanup,
4287616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
4290Sstevel@tonic-gate EVP_CIPHER_set_asn1_iv,
4300Sstevel@tonic-gate EVP_CIPHER_get_asn1_iv,
4310Sstevel@tonic-gate NULL
4320Sstevel@tonic-gate };
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /* 3DES CBC EVP */
4357616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_3des_cbc =
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate NID_des_ede3_cbc,
4380Sstevel@tonic-gate 8, 24, 8,
4390Sstevel@tonic-gate EVP_CIPH_CBC_MODE,
4400Sstevel@tonic-gate pk11_cipher_init,
4410Sstevel@tonic-gate pk11_cipher_do_cipher,
4420Sstevel@tonic-gate pk11_cipher_cleanup,
4437616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
4440Sstevel@tonic-gate EVP_CIPHER_set_asn1_iv,
4450Sstevel@tonic-gate EVP_CIPHER_get_asn1_iv,
4460Sstevel@tonic-gate NULL
4470Sstevel@tonic-gate };
4480Sstevel@tonic-gate
4497211Sjp161948 /*
4507211Sjp161948 * ECB modes don't use an Initial Vector so that's why set_asn1_parameters and
4517211Sjp161948 * get_asn1_parameters fields are set to NULL.
4527211Sjp161948 */
4537616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_des_ecb =
4547211Sjp161948 {
4557211Sjp161948 NID_des_ecb,
4567211Sjp161948 8, 8, 8,
4577211Sjp161948 EVP_CIPH_ECB_MODE,
4587211Sjp161948 pk11_cipher_init,
4597211Sjp161948 pk11_cipher_do_cipher,
4607211Sjp161948 pk11_cipher_cleanup,
4617616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
4627211Sjp161948 NULL,
4637211Sjp161948 NULL,
4647211Sjp161948 NULL
4657211Sjp161948 };
4667211Sjp161948
4677616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_3des_ecb =
4687211Sjp161948 {
4697211Sjp161948 NID_des_ede3_ecb,
4707211Sjp161948 8, 24, 8,
4717211Sjp161948 EVP_CIPH_ECB_MODE,
4727211Sjp161948 pk11_cipher_init,
4737211Sjp161948 pk11_cipher_do_cipher,
4747211Sjp161948 pk11_cipher_cleanup,
4757616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
4767211Sjp161948 NULL,
4777211Sjp161948 NULL,
4787211Sjp161948 NULL
4797211Sjp161948 };
4807211Sjp161948
4817211Sjp161948
4827616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_128_cbc =
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate NID_aes_128_cbc,
4850Sstevel@tonic-gate 16, 16, 16,
4860Sstevel@tonic-gate EVP_CIPH_CBC_MODE,
4870Sstevel@tonic-gate pk11_cipher_init,
4880Sstevel@tonic-gate pk11_cipher_do_cipher,
4890Sstevel@tonic-gate pk11_cipher_cleanup,
4907616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
4910Sstevel@tonic-gate EVP_CIPHER_set_asn1_iv,
4920Sstevel@tonic-gate EVP_CIPHER_get_asn1_iv,
4930Sstevel@tonic-gate NULL
4940Sstevel@tonic-gate };
4950Sstevel@tonic-gate
4967616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_192_cbc =
4977211Sjp161948 {
4987211Sjp161948 NID_aes_192_cbc,
4997211Sjp161948 16, 24, 16,
5007211Sjp161948 EVP_CIPH_CBC_MODE,
5017211Sjp161948 pk11_cipher_init,
5027211Sjp161948 pk11_cipher_do_cipher,
5037211Sjp161948 pk11_cipher_cleanup,
5047616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5057211Sjp161948 EVP_CIPHER_set_asn1_iv,
5067211Sjp161948 EVP_CIPHER_get_asn1_iv,
5077211Sjp161948 NULL
5087211Sjp161948 };
5097211Sjp161948
5107616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_256_cbc =
5117211Sjp161948 {
5127211Sjp161948 NID_aes_256_cbc,
5137211Sjp161948 16, 32, 16,
5147211Sjp161948 EVP_CIPH_CBC_MODE,
5157211Sjp161948 pk11_cipher_init,
5167211Sjp161948 pk11_cipher_do_cipher,
5177211Sjp161948 pk11_cipher_cleanup,
5187616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5197211Sjp161948 EVP_CIPHER_set_asn1_iv,
5207211Sjp161948 EVP_CIPHER_get_asn1_iv,
5217211Sjp161948 NULL
5227211Sjp161948 };
5237211Sjp161948
5247211Sjp161948 /*
5257211Sjp161948 * ECB modes don't use IV so that's why set_asn1_parameters and
5267211Sjp161948 * get_asn1_parameters are set to NULL.
5277211Sjp161948 */
5287616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_128_ecb =
5297211Sjp161948 {
5307211Sjp161948 NID_aes_128_ecb,
5317211Sjp161948 16, 16, 0,
5327211Sjp161948 EVP_CIPH_ECB_MODE,
5337211Sjp161948 pk11_cipher_init,
5347211Sjp161948 pk11_cipher_do_cipher,
5357211Sjp161948 pk11_cipher_cleanup,
5367616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5377211Sjp161948 NULL,
5387211Sjp161948 NULL,
5397211Sjp161948 NULL
5407211Sjp161948 };
5417211Sjp161948
5427616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_192_ecb =
5437211Sjp161948 {
5447211Sjp161948 NID_aes_192_ecb,
5457211Sjp161948 16, 24, 0,
5467211Sjp161948 EVP_CIPH_ECB_MODE,
5477211Sjp161948 pk11_cipher_init,
5487211Sjp161948 pk11_cipher_do_cipher,
5497211Sjp161948 pk11_cipher_cleanup,
5507616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5517211Sjp161948 NULL,
5527211Sjp161948 NULL,
5537211Sjp161948 NULL
5547211Sjp161948 };
5557211Sjp161948
5567616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_256_ecb =
5577211Sjp161948 {
5587211Sjp161948 NID_aes_256_ecb,
5597211Sjp161948 16, 32, 0,
5607211Sjp161948 EVP_CIPH_ECB_MODE,
5617211Sjp161948 pk11_cipher_init,
5627211Sjp161948 pk11_cipher_do_cipher,
5637211Sjp161948 pk11_cipher_cleanup,
5647616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5657211Sjp161948 NULL,
5667211Sjp161948 NULL,
5677211Sjp161948 NULL
5687211Sjp161948 };
5697211Sjp161948
5707211Sjp161948 #ifdef SOLARIS_AES_CTR
5717211Sjp161948 /*
5727211Sjp161948 * NID_undef's will be changed to the AES counter mode NIDs as soon they are
5737211Sjp161948 * created in pk11_library_init(). Note that the need to change these structures
5747211Sjp161948 * is the reason why we don't define them with the const keyword.
5757211Sjp161948 */
5767616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_128_ctr =
5777211Sjp161948 {
5787211Sjp161948 NID_undef,
5797211Sjp161948 16, 16, 16,
5807211Sjp161948 EVP_CIPH_CBC_MODE,
5817211Sjp161948 pk11_cipher_init,
5827211Sjp161948 pk11_cipher_do_cipher,
5837211Sjp161948 pk11_cipher_cleanup,
5847616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5857211Sjp161948 EVP_CIPHER_set_asn1_iv,
5867211Sjp161948 EVP_CIPHER_get_asn1_iv,
5877211Sjp161948 NULL
5887211Sjp161948 };
5897211Sjp161948
5907616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_192_ctr =
5917211Sjp161948 {
5927211Sjp161948 NID_undef,
5937211Sjp161948 16, 24, 16,
5947211Sjp161948 EVP_CIPH_CBC_MODE,
5957211Sjp161948 pk11_cipher_init,
5967211Sjp161948 pk11_cipher_do_cipher,
5977211Sjp161948 pk11_cipher_cleanup,
5987616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
5997211Sjp161948 EVP_CIPHER_set_asn1_iv,
6007211Sjp161948 EVP_CIPHER_get_asn1_iv,
6017211Sjp161948 NULL
6027211Sjp161948 };
6037211Sjp161948
6047616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_256_ctr =
6057211Sjp161948 {
6067211Sjp161948 NID_undef,
6077211Sjp161948 16, 32, 16,
6087211Sjp161948 EVP_CIPH_CBC_MODE,
6097211Sjp161948 pk11_cipher_init,
6107211Sjp161948 pk11_cipher_do_cipher,
6117211Sjp161948 pk11_cipher_cleanup,
6127616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6137211Sjp161948 EVP_CIPHER_set_asn1_iv,
6147211Sjp161948 EVP_CIPHER_get_asn1_iv,
6157211Sjp161948 NULL
6167211Sjp161948 };
6177211Sjp161948 #endif /* SOLARIS_AES_CTR */
6187211Sjp161948
6197616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_bf_cbc =
6207211Sjp161948 {
6217211Sjp161948 NID_bf_cbc,
6227211Sjp161948 8, 16, 8,
6237211Sjp161948 EVP_CIPH_VARIABLE_LENGTH,
6247211Sjp161948 pk11_cipher_init,
6257211Sjp161948 pk11_cipher_do_cipher,
6267211Sjp161948 pk11_cipher_cleanup,
6277616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6287211Sjp161948 EVP_CIPHER_set_asn1_iv,
6297211Sjp161948 EVP_CIPHER_get_asn1_iv,
6307211Sjp161948 NULL
6317211Sjp161948 };
6327211Sjp161948
6330Sstevel@tonic-gate static const EVP_CIPHER pk11_rc4 =
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate NID_rc4,
6367211Sjp161948 1, 16, 0,
6370Sstevel@tonic-gate EVP_CIPH_VARIABLE_LENGTH,
6380Sstevel@tonic-gate pk11_cipher_init,
6390Sstevel@tonic-gate pk11_cipher_do_cipher,
6400Sstevel@tonic-gate pk11_cipher_cleanup,
6417616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6420Sstevel@tonic-gate NULL,
6430Sstevel@tonic-gate NULL,
6440Sstevel@tonic-gate NULL
6450Sstevel@tonic-gate };
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate static const EVP_MD pk11_md5 =
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate NID_md5,
6500Sstevel@tonic-gate NID_md5WithRSAEncryption,
6510Sstevel@tonic-gate MD5_DIGEST_LENGTH,
6520Sstevel@tonic-gate 0,
6530Sstevel@tonic-gate pk11_digest_init,
6540Sstevel@tonic-gate pk11_digest_update,
6550Sstevel@tonic-gate pk11_digest_final,
6560Sstevel@tonic-gate pk11_digest_copy,
6570Sstevel@tonic-gate pk11_digest_cleanup,
6580Sstevel@tonic-gate EVP_PKEY_RSA_method,
6590Sstevel@tonic-gate MD5_CBLOCK,
6607616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6610Sstevel@tonic-gate };
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate static const EVP_MD pk11_sha1 =
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate NID_sha1,
6660Sstevel@tonic-gate NID_sha1WithRSAEncryption,
6670Sstevel@tonic-gate SHA_DIGEST_LENGTH,
6680Sstevel@tonic-gate 0,
6690Sstevel@tonic-gate pk11_digest_init,
6700Sstevel@tonic-gate pk11_digest_update,
6710Sstevel@tonic-gate pk11_digest_final,
6720Sstevel@tonic-gate pk11_digest_copy,
6730Sstevel@tonic-gate pk11_digest_cleanup,
6740Sstevel@tonic-gate EVP_PKEY_RSA_method,
6750Sstevel@tonic-gate SHA_CBLOCK,
6767616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6770Sstevel@tonic-gate };
6780Sstevel@tonic-gate
6797211Sjp161948 static const EVP_MD pk11_sha224 =
6807211Sjp161948 {
6817211Sjp161948 NID_sha224,
6827211Sjp161948 NID_sha224WithRSAEncryption,
6837211Sjp161948 SHA224_DIGEST_LENGTH,
6847211Sjp161948 0,
6857211Sjp161948 pk11_digest_init,
6867211Sjp161948 pk11_digest_update,
6877211Sjp161948 pk11_digest_final,
6887211Sjp161948 pk11_digest_copy,
6897211Sjp161948 pk11_digest_cleanup,
6907211Sjp161948 EVP_PKEY_RSA_method,
6917211Sjp161948 /* SHA-224 uses the same cblock size as SHA-256 */
6927211Sjp161948 SHA256_CBLOCK,
6937616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
6947211Sjp161948 };
6957211Sjp161948
6967211Sjp161948 static const EVP_MD pk11_sha256 =
6977211Sjp161948 {
6987211Sjp161948 NID_sha256,
6997211Sjp161948 NID_sha256WithRSAEncryption,
7007211Sjp161948 SHA256_DIGEST_LENGTH,
7017211Sjp161948 0,
7027211Sjp161948 pk11_digest_init,
7037211Sjp161948 pk11_digest_update,
7047211Sjp161948 pk11_digest_final,
7057211Sjp161948 pk11_digest_copy,
7067211Sjp161948 pk11_digest_cleanup,
7077211Sjp161948 EVP_PKEY_RSA_method,
7087211Sjp161948 SHA256_CBLOCK,
7097616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
7107211Sjp161948 };
7117211Sjp161948
7127211Sjp161948 static const EVP_MD pk11_sha384 =
7137211Sjp161948 {
7147211Sjp161948 NID_sha384,
7157211Sjp161948 NID_sha384WithRSAEncryption,
7167211Sjp161948 SHA384_DIGEST_LENGTH,
7177211Sjp161948 0,
7187211Sjp161948 pk11_digest_init,
7197211Sjp161948 pk11_digest_update,
7207211Sjp161948 pk11_digest_final,
7217211Sjp161948 pk11_digest_copy,
7227211Sjp161948 pk11_digest_cleanup,
7237211Sjp161948 EVP_PKEY_RSA_method,
7247211Sjp161948 /* SHA-384 uses the same cblock size as SHA-512 */
7257211Sjp161948 SHA512_CBLOCK,
7267616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
7277211Sjp161948 };
7287211Sjp161948
7297211Sjp161948 static const EVP_MD pk11_sha512 =
7307211Sjp161948 {
7317211Sjp161948 NID_sha512,
7327211Sjp161948 NID_sha512WithRSAEncryption,
7337211Sjp161948 SHA512_DIGEST_LENGTH,
7347211Sjp161948 0,
7357211Sjp161948 pk11_digest_init,
7367211Sjp161948 pk11_digest_update,
7377211Sjp161948 pk11_digest_final,
7387211Sjp161948 pk11_digest_copy,
7397211Sjp161948 pk11_digest_cleanup,
7407211Sjp161948 EVP_PKEY_RSA_method,
7417211Sjp161948 SHA512_CBLOCK,
7427616SVladimir.Kotal@Sun.COM sizeof (PK11_CIPHER_STATE),
7437211Sjp161948 };
7447211Sjp161948
7457616SVladimir.Kotal@Sun.COM /*
7467616SVladimir.Kotal@Sun.COM * Initialization function. Sets up various PKCS#11 library components.
7477616SVladimir.Kotal@Sun.COM * The definitions for control commands specific to this engine
7480Sstevel@tonic-gate */
7497616SVladimir.Kotal@Sun.COM #define PK11_CMD_SO_PATH ENGINE_CMD_BASE
7500Sstevel@tonic-gate static const ENGINE_CMD_DEFN pk11_cmd_defns[] =
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate PK11_CMD_SO_PATH,
7540Sstevel@tonic-gate "SO_PATH",
7550Sstevel@tonic-gate "Specifies the path to the 'pkcs#11' shared library",
7560Sstevel@tonic-gate ENGINE_CMD_FLAG_STRING
7570Sstevel@tonic-gate },
7580Sstevel@tonic-gate {0, NULL, NULL, 0}
7590Sstevel@tonic-gate };
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate static RAND_METHOD pk11_random =
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate pk11_rand_seed,
7650Sstevel@tonic-gate pk11_rand_bytes,
7660Sstevel@tonic-gate pk11_rand_cleanup,
7670Sstevel@tonic-gate pk11_rand_add,
7680Sstevel@tonic-gate pk11_rand_bytes,
7690Sstevel@tonic-gate pk11_rand_status
7700Sstevel@tonic-gate };
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate
7737616SVladimir.Kotal@Sun.COM /* Constants used when creating the ENGINE */
7740Sstevel@tonic-gate static const char *engine_pk11_id = "pkcs11";
7750Sstevel@tonic-gate static const char *engine_pk11_name = "PKCS #11 engine support";
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate CK_FUNCTION_LIST_PTR pFuncList = NULL;
7780Sstevel@tonic-gate static const char PK11_GET_FUNCTION_LIST[] = "C_GetFunctionList";
7790Sstevel@tonic-gate
7807616SVladimir.Kotal@Sun.COM /*
7817616SVladimir.Kotal@Sun.COM * These are the static string constants for the DSO file name and the function
7827211Sjp161948 * symbol names to bind to.
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
7850Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/64/libpkcs11.so.1";
7860Sstevel@tonic-gate #else
7870Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/libpkcs11.so.1";
7880Sstevel@tonic-gate #endif
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate static CK_BBOOL true = TRUE;
7910Sstevel@tonic-gate static CK_BBOOL false = FALSE;
7927211Sjp161948 static CK_SLOT_ID pubkey_SLOTID = 0;
7937211Sjp161948 static CK_SLOT_ID rand_SLOTID = 0;
7940Sstevel@tonic-gate static CK_SLOT_ID SLOTID = 0;
7957526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_library_initialized = FALSE;
7967526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_atfork_initialized = FALSE;
7977211Sjp161948 static int pk11_pid = 0;
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate static DSO *pk11_dso = NULL;
8000Sstevel@tonic-gate
8017526SVladimir.Kotal@Sun.COM /* allocate and initialize all locks used by the engine itself */
pk11_init_all_locks(void)8027526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void)
8037526SVladimir.Kotal@Sun.COM {
8047526SVladimir.Kotal@Sun.COM int type;
8057526SVladimir.Kotal@Sun.COM
8067526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
8077526SVladimir.Kotal@Sun.COM find_lock[OP_RSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8087526SVladimir.Kotal@Sun.COM if (find_lock[OP_RSA] == NULL)
8097526SVladimir.Kotal@Sun.COM goto malloc_err;
8107526SVladimir.Kotal@Sun.COM (void) pthread_mutex_init(find_lock[OP_RSA], NULL);
8117526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
8127526SVladimir.Kotal@Sun.COM
8137526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
8147526SVladimir.Kotal@Sun.COM find_lock[OP_DSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8157526SVladimir.Kotal@Sun.COM if (find_lock[OP_DSA] == NULL)
8167526SVladimir.Kotal@Sun.COM goto malloc_err;
8177526SVladimir.Kotal@Sun.COM (void) pthread_mutex_init(find_lock[OP_DSA], NULL);
8187526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
8197526SVladimir.Kotal@Sun.COM
8207526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
8217526SVladimir.Kotal@Sun.COM find_lock[OP_DH] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8227526SVladimir.Kotal@Sun.COM if (find_lock[OP_DH] == NULL)
8237526SVladimir.Kotal@Sun.COM goto malloc_err;
8247526SVladimir.Kotal@Sun.COM (void) pthread_mutex_init(find_lock[OP_DH], NULL);
8257526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
8267526SVladimir.Kotal@Sun.COM
8277526SVladimir.Kotal@Sun.COM for (type = 0; type < OP_MAX; type++)
8287526SVladimir.Kotal@Sun.COM {
8297526SVladimir.Kotal@Sun.COM session_cache[type].lock =
8307526SVladimir.Kotal@Sun.COM OPENSSL_malloc(sizeof (pthread_mutex_t));
8317526SVladimir.Kotal@Sun.COM if (session_cache[type].lock == NULL)
8327526SVladimir.Kotal@Sun.COM goto malloc_err;
8337526SVladimir.Kotal@Sun.COM (void) pthread_mutex_init(session_cache[type].lock, NULL);
8347526SVladimir.Kotal@Sun.COM }
8357526SVladimir.Kotal@Sun.COM
8367526SVladimir.Kotal@Sun.COM return (1);
8377526SVladimir.Kotal@Sun.COM
8387526SVladimir.Kotal@Sun.COM malloc_err:
8397526SVladimir.Kotal@Sun.COM pk11_free_all_locks();
8407526SVladimir.Kotal@Sun.COM PK11err(PK11_F_INIT_ALL_LOCKS, PK11_R_MALLOC_FAILURE);
8417526SVladimir.Kotal@Sun.COM return (0);
8427526SVladimir.Kotal@Sun.COM }
8437526SVladimir.Kotal@Sun.COM
pk11_free_all_locks(void)8447526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void)
8457526SVladimir.Kotal@Sun.COM {
8467526SVladimir.Kotal@Sun.COM int type;
8477526SVladimir.Kotal@Sun.COM
8487526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
8497526SVladimir.Kotal@Sun.COM if (find_lock[OP_RSA] != NULL)
8507526SVladimir.Kotal@Sun.COM {
8517526SVladimir.Kotal@Sun.COM (void) pthread_mutex_destroy(find_lock[OP_RSA]);
8527526SVladimir.Kotal@Sun.COM OPENSSL_free(find_lock[OP_RSA]);
8537526SVladimir.Kotal@Sun.COM find_lock[OP_RSA] = NULL;
8547526SVladimir.Kotal@Sun.COM }
8557526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
8567526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
8577526SVladimir.Kotal@Sun.COM if (find_lock[OP_DSA] != NULL)
8587526SVladimir.Kotal@Sun.COM {
8597526SVladimir.Kotal@Sun.COM (void) pthread_mutex_destroy(find_lock[OP_DSA]);
8607526SVladimir.Kotal@Sun.COM OPENSSL_free(find_lock[OP_DSA]);
8617526SVladimir.Kotal@Sun.COM find_lock[OP_DSA] = NULL;
8627526SVladimir.Kotal@Sun.COM }
8637526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
8647526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
8657526SVladimir.Kotal@Sun.COM if (find_lock[OP_DH] != NULL)
8667526SVladimir.Kotal@Sun.COM {
8677526SVladimir.Kotal@Sun.COM (void) pthread_mutex_destroy(find_lock[OP_DH]);
8687526SVladimir.Kotal@Sun.COM OPENSSL_free(find_lock[OP_DH]);
8697526SVladimir.Kotal@Sun.COM find_lock[OP_DH] = NULL;
8707526SVladimir.Kotal@Sun.COM }
8717526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
8727526SVladimir.Kotal@Sun.COM
8737526SVladimir.Kotal@Sun.COM for (type = 0; type < OP_MAX; type++)
8747526SVladimir.Kotal@Sun.COM {
8757526SVladimir.Kotal@Sun.COM if (session_cache[type].lock != NULL)
8767526SVladimir.Kotal@Sun.COM {
8777526SVladimir.Kotal@Sun.COM (void) pthread_mutex_destroy(session_cache[type].lock);
8787526SVladimir.Kotal@Sun.COM OPENSSL_free(session_cache[type].lock);
8797526SVladimir.Kotal@Sun.COM session_cache[type].lock = NULL;
8807526SVladimir.Kotal@Sun.COM }
8817526SVladimir.Kotal@Sun.COM }
8827526SVladimir.Kotal@Sun.COM }
8837526SVladimir.Kotal@Sun.COM
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate * This internal function is used by ENGINE_pk11() and "dynamic" ENGINE support.
8860Sstevel@tonic-gate */
bind_pk11(ENGINE * e)8870Sstevel@tonic-gate static int bind_pk11(ENGINE *e)
8880Sstevel@tonic-gate {
8896847Svk199839 #ifndef OPENSSL_NO_RSA
8900Sstevel@tonic-gate const RSA_METHOD *rsa = NULL;
8910Sstevel@tonic-gate RSA_METHOD *pk11_rsa = PK11_RSA();
8927211Sjp161948 #endif /* OPENSSL_NO_RSA */
8930Sstevel@tonic-gate if (!pk11_library_initialized)
8947628SVladimir.Kotal@Sun.COM if (!pk11_library_init(e))
8957628SVladimir.Kotal@Sun.COM return (0);
8960Sstevel@tonic-gate
8977616SVladimir.Kotal@Sun.COM if (!ENGINE_set_id(e, engine_pk11_id) ||
8987616SVladimir.Kotal@Sun.COM !ENGINE_set_name(e, engine_pk11_name) ||
8997616SVladimir.Kotal@Sun.COM !ENGINE_set_ciphers(e, pk11_engine_ciphers) ||
9007616SVladimir.Kotal@Sun.COM !ENGINE_set_digests(e, pk11_engine_digests))
9017616SVladimir.Kotal@Sun.COM return (0);
9020Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
9037616SVladimir.Kotal@Sun.COM if (pk11_have_rsa == CK_TRUE)
9040Sstevel@tonic-gate {
9057616SVladimir.Kotal@Sun.COM if (!ENGINE_set_RSA(e, PK11_RSA()) ||
9067616SVladimir.Kotal@Sun.COM !ENGINE_set_load_privkey_function(e, pk11_load_privkey) ||
9077616SVladimir.Kotal@Sun.COM !ENGINE_set_load_pubkey_function(e, pk11_load_pubkey))
9087616SVladimir.Kotal@Sun.COM return (0);
9097211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
9107211Sjp161948 fprintf(stderr, "%s: registered RSA\n", PK11_DBG);
9117211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
9120Sstevel@tonic-gate }
9137211Sjp161948 #endif /* OPENSSL_NO_RSA */
9140Sstevel@tonic-gate #ifndef OPENSSL_NO_DSA
9157616SVladimir.Kotal@Sun.COM if (pk11_have_dsa == CK_TRUE)
9167616SVladimir.Kotal@Sun.COM {
9177616SVladimir.Kotal@Sun.COM if (!ENGINE_set_DSA(e, PK11_DSA()))
9187616SVladimir.Kotal@Sun.COM return (0);
9197211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
9207211Sjp161948 fprintf(stderr, "%s: registered DSA\n", PK11_DBG);
9217211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
9227616SVladimir.Kotal@Sun.COM }
9237211Sjp161948 #endif /* OPENSSL_NO_DSA */
9240Sstevel@tonic-gate #ifndef OPENSSL_NO_DH
9257616SVladimir.Kotal@Sun.COM if (pk11_have_dh == CK_TRUE)
9260Sstevel@tonic-gate {
9277616SVladimir.Kotal@Sun.COM if (!ENGINE_set_DH(e, PK11_DH()))
9287616SVladimir.Kotal@Sun.COM return (0);
9297211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
9307211Sjp161948 fprintf(stderr, "%s: registered DH\n", PK11_DBG);
9317211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
9327616SVladimir.Kotal@Sun.COM }
9337211Sjp161948 #endif /* OPENSSL_NO_DH */
9347616SVladimir.Kotal@Sun.COM if (pk11_have_random)
9350Sstevel@tonic-gate {
9367616SVladimir.Kotal@Sun.COM if (!ENGINE_set_RAND(e, &pk11_random))
9377616SVladimir.Kotal@Sun.COM return (0);
9387211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
9397211Sjp161948 fprintf(stderr, "%s: registered random\n", PK11_DBG);
9407211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
9410Sstevel@tonic-gate }
9427616SVladimir.Kotal@Sun.COM if (!ENGINE_set_init_function(e, pk11_init) ||
9437616SVladimir.Kotal@Sun.COM !ENGINE_set_destroy_function(e, pk11_destroy) ||
9447616SVladimir.Kotal@Sun.COM !ENGINE_set_finish_function(e, pk11_finish) ||
9457616SVladimir.Kotal@Sun.COM !ENGINE_set_ctrl_function(e, pk11_ctrl) ||
9467616SVladimir.Kotal@Sun.COM !ENGINE_set_cmd_defns(e, pk11_cmd_defns))
9477616SVladimir.Kotal@Sun.COM return (0);
9487616SVladimir.Kotal@Sun.COM
9497616SVladimir.Kotal@Sun.COM /*
9507616SVladimir.Kotal@Sun.COM * Apache calls OpenSSL function RSA_blinding_on() once during startup
9510Sstevel@tonic-gate * which in turn calls bn_mod_exp. Since we do not implement bn_mod_exp
9527616SVladimir.Kotal@Sun.COM * here, we wire it back to the OpenSSL software implementation.
9537616SVladimir.Kotal@Sun.COM * Since it is used only once, performance is not a concern.
9547616SVladimir.Kotal@Sun.COM */
9550Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
9567616SVladimir.Kotal@Sun.COM rsa = RSA_PKCS1_SSLeay();
9577616SVladimir.Kotal@Sun.COM pk11_rsa->rsa_mod_exp = rsa->rsa_mod_exp;
9587616SVladimir.Kotal@Sun.COM pk11_rsa->bn_mod_exp = rsa->bn_mod_exp;
9597211Sjp161948 #endif /* OPENSSL_NO_RSA */
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate /* Ensure the pk11 error handling is set up */
9620Sstevel@tonic-gate ERR_load_pk11_strings();
9637616SVladimir.Kotal@Sun.COM
9647616SVladimir.Kotal@Sun.COM return (1);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate
9677616SVladimir.Kotal@Sun.COM /* Dynamic engine support is disabled at a higher level for Solaris */
9687211Sjp161948 #ifdef ENGINE_DYNAMIC_SUPPORT
bind_helper(ENGINE * e,const char * id)9690Sstevel@tonic-gate static int bind_helper(ENGINE *e, const char *id)
9700Sstevel@tonic-gate {
9710Sstevel@tonic-gate if (id && (strcmp(id, engine_pk11_id) != 0))
9727616SVladimir.Kotal@Sun.COM return (0);
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate if (!bind_pk11(e))
9757616SVladimir.Kotal@Sun.COM return (0);
9767616SVladimir.Kotal@Sun.COM
9777616SVladimir.Kotal@Sun.COM return (1);
9787616SVladimir.Kotal@Sun.COM }
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate IMPLEMENT_DYNAMIC_CHECK_FN()
9810Sstevel@tonic-gate IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate #else
9840Sstevel@tonic-gate static ENGINE *engine_pk11(void)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate ENGINE *ret = ENGINE_new();
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate if (!ret)
9897616SVladimir.Kotal@Sun.COM return (NULL);
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate if (!bind_pk11(ret))
9920Sstevel@tonic-gate {
993*11411SSurya.Prakki@Sun.COM (void) ENGINE_free(ret);
9947616SVladimir.Kotal@Sun.COM return (NULL);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate
9977616SVladimir.Kotal@Sun.COM return (ret);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate
10007616SVladimir.Kotal@Sun.COM void
10017616SVladimir.Kotal@Sun.COM ENGINE_load_pk11(void)
10020Sstevel@tonic-gate {
10030Sstevel@tonic-gate ENGINE *e_pk11 = NULL;
10040Sstevel@tonic-gate
10057616SVladimir.Kotal@Sun.COM /*
10067616SVladimir.Kotal@Sun.COM * Do not use dynamic PKCS#11 library on Solaris due to
10077616SVladimir.Kotal@Sun.COM * security reasons. We will link it in statically.
10080Sstevel@tonic-gate */
10097616SVladimir.Kotal@Sun.COM /* Attempt to load PKCS#11 library */
10100Sstevel@tonic-gate if (!pk11_dso)
10110Sstevel@tonic-gate pk11_dso = DSO_load(NULL, get_PK11_LIBNAME(), NULL, 0);
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate if (pk11_dso == NULL)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate PK11err(PK11_F_LOAD, PK11_R_DSO_FAILURE);
10160Sstevel@tonic-gate return;
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate e_pk11 = engine_pk11();
10207616SVladimir.Kotal@Sun.COM if (!e_pk11)
10210Sstevel@tonic-gate {
1022*11411SSurya.Prakki@Sun.COM (void) DSO_free(pk11_dso);
10230Sstevel@tonic-gate pk11_dso = NULL;
10240Sstevel@tonic-gate return;
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate
10277616SVladimir.Kotal@Sun.COM /*
10287616SVladimir.Kotal@Sun.COM * At this point, the pk11 shared library is either dynamically
10297616SVladimir.Kotal@Sun.COM * loaded or statically linked in. So, initialize the pk11
10307616SVladimir.Kotal@Sun.COM * library before calling ENGINE_set_default since the latter
10310Sstevel@tonic-gate * needs cipher and digest algorithm information
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate if (!pk11_library_init(e_pk11))
10340Sstevel@tonic-gate {
1035*11411SSurya.Prakki@Sun.COM (void) DSO_free(pk11_dso);
10360Sstevel@tonic-gate pk11_dso = NULL;
1037*11411SSurya.Prakki@Sun.COM (void) ENGINE_free(e_pk11);
10380Sstevel@tonic-gate return;
10390Sstevel@tonic-gate }
10400Sstevel@tonic-gate
1041*11411SSurya.Prakki@Sun.COM (void) ENGINE_add(e_pk11);
1042*11411SSurya.Prakki@Sun.COM
1043*11411SSurya.Prakki@Sun.COM (void) ENGINE_free(e_pk11);
10440Sstevel@tonic-gate ERR_clear_error();
10450Sstevel@tonic-gate }
10467211Sjp161948 #endif /* ENGINE_DYNAMIC_SUPPORT */
10470Sstevel@tonic-gate
10487616SVladimir.Kotal@Sun.COM /*
10497616SVladimir.Kotal@Sun.COM * These are the static string constants for the DSO file name and
10507616SVladimir.Kotal@Sun.COM * the function symbol names to bind to.
10510Sstevel@tonic-gate */
10520Sstevel@tonic-gate static const char *PK11_LIBNAME = NULL;
10530Sstevel@tonic-gate
get_PK11_LIBNAME(void)10540Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate if (PK11_LIBNAME)
10577616SVladimir.Kotal@Sun.COM return (PK11_LIBNAME);
10587616SVladimir.Kotal@Sun.COM
10597616SVladimir.Kotal@Sun.COM return (def_PK11_LIBNAME);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
free_PK11_LIBNAME(void)10620Sstevel@tonic-gate static void free_PK11_LIBNAME(void)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate if (PK11_LIBNAME)
10650Sstevel@tonic-gate OPENSSL_free((void*)PK11_LIBNAME);
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate PK11_LIBNAME = NULL;
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate
set_PK11_LIBNAME(const char * name)10700Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name)
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate free_PK11_LIBNAME();
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate return ((PK11_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10777526SVladimir.Kotal@Sun.COM /* acquire all engine specific mutexes before fork */
pk11_fork_prepare(void)10787526SVladimir.Kotal@Sun.COM static void pk11_fork_prepare(void)
10797526SVladimir.Kotal@Sun.COM {
10807526SVladimir.Kotal@Sun.COM int i;
10817526SVladimir.Kotal@Sun.COM
10827560SVladimir.Kotal@Sun.COM if (!pk11_library_initialized)
10837560SVladimir.Kotal@Sun.COM return;
10847560SVladimir.Kotal@Sun.COM
10857526SVladimir.Kotal@Sun.COM LOCK_OBJSTORE(OP_RSA);
10867526SVladimir.Kotal@Sun.COM LOCK_OBJSTORE(OP_DSA);
10877526SVladimir.Kotal@Sun.COM LOCK_OBJSTORE(OP_DH);
10887526SVladimir.Kotal@Sun.COM for (i = 0; i < OP_MAX; i++)
10897526SVladimir.Kotal@Sun.COM {
10907526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(session_cache[i].lock);
10917526SVladimir.Kotal@Sun.COM }
10927526SVladimir.Kotal@Sun.COM }
10937526SVladimir.Kotal@Sun.COM
10947526SVladimir.Kotal@Sun.COM /* release all engine specific mutexes */
pk11_fork_parent(void)10957526SVladimir.Kotal@Sun.COM static void pk11_fork_parent(void)
10967526SVladimir.Kotal@Sun.COM {
10977526SVladimir.Kotal@Sun.COM int i;
10987526SVladimir.Kotal@Sun.COM
10997560SVladimir.Kotal@Sun.COM if (!pk11_library_initialized)
11007560SVladimir.Kotal@Sun.COM return;
11017560SVladimir.Kotal@Sun.COM
11027526SVladimir.Kotal@Sun.COM for (i = OP_MAX - 1; i >= 0; i--)
11037526SVladimir.Kotal@Sun.COM {
11047526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[i].lock);
11057526SVladimir.Kotal@Sun.COM }
11067526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_DH);
11077526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_DSA);
11087526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_RSA);
11097526SVladimir.Kotal@Sun.COM }
11107526SVladimir.Kotal@Sun.COM
11117526SVladimir.Kotal@Sun.COM /*
11127526SVladimir.Kotal@Sun.COM * same situation as in parent - we need to unlock all locks to make them
11137526SVladimir.Kotal@Sun.COM * accessible to all threads.
11147526SVladimir.Kotal@Sun.COM */
pk11_fork_child(void)11157526SVladimir.Kotal@Sun.COM static void pk11_fork_child(void)
11167526SVladimir.Kotal@Sun.COM {
11177526SVladimir.Kotal@Sun.COM int i;
11187526SVladimir.Kotal@Sun.COM
11197560SVladimir.Kotal@Sun.COM if (!pk11_library_initialized)
11207560SVladimir.Kotal@Sun.COM return;
11217560SVladimir.Kotal@Sun.COM
11227526SVladimir.Kotal@Sun.COM for (i = OP_MAX - 1; i >= 0; i--)
11237526SVladimir.Kotal@Sun.COM {
11247526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[i].lock);
11257526SVladimir.Kotal@Sun.COM }
11267526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_DH);
11277526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_DSA);
11287526SVladimir.Kotal@Sun.COM UNLOCK_OBJSTORE(OP_RSA);
11297526SVladimir.Kotal@Sun.COM }
11307526SVladimir.Kotal@Sun.COM
11310Sstevel@tonic-gate /* Initialization function for the pk11 engine */
pk11_init(ENGINE * e)11320Sstevel@tonic-gate static int pk11_init(ENGINE *e)
11330Sstevel@tonic-gate {
11347616SVladimir.Kotal@Sun.COM return (pk11_library_init(e));
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate
11377616SVladimir.Kotal@Sun.COM /*
11387616SVladimir.Kotal@Sun.COM * Initialization function. Sets up various PKCS#11 library components.
11390Sstevel@tonic-gate * It selects a slot based on predefined critiera. In the process, it also
11400Sstevel@tonic-gate * count how many ciphers and digests to support. Since the cipher and
11410Sstevel@tonic-gate * digest information is needed when setting default engine, this function
11420Sstevel@tonic-gate * needs to be called before calling ENGINE_set_default.
11430Sstevel@tonic-gate */
11447534SVladimir.Kotal@Sun.COM /* ARGSUSED */
pk11_library_init(ENGINE * e)11450Sstevel@tonic-gate static int pk11_library_init(ENGINE *e)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate CK_C_GetFunctionList p;
11480Sstevel@tonic-gate CK_RV rv = CKR_OK;
11490Sstevel@tonic-gate CK_INFO info;
11500Sstevel@tonic-gate CK_ULONG ul_state_len;
11517211Sjp161948 int any_slot_found;
11527526SVladimir.Kotal@Sun.COM int i;
11537211Sjp161948
11547211Sjp161948 /*
11557211Sjp161948 * pk11_library_initialized is set to 0 in pk11_finish() which is called
11567211Sjp161948 * from ENGINE_finish(). However, if there is still at least one
11577211Sjp161948 * existing functional reference to the engine (see engine(3) for more
11587211Sjp161948 * information), pk11_finish() is skipped. For example, this can happen
11597211Sjp161948 * if an application forgets to clear one cipher context. In case of a
11607211Sjp161948 * fork() when the application is finishing the engine so that it can be
11617211Sjp161948 * reinitialized in the child, forgotten functional reference causes
11627211Sjp161948 * pk11_library_initialized to stay 1. In that case we need the PID
11637211Sjp161948 * check so that we properly initialize the engine again.
11647211Sjp161948 */
11650Sstevel@tonic-gate if (pk11_library_initialized)
11667211Sjp161948 {
11677211Sjp161948 if (pk11_pid == getpid())
11687526SVladimir.Kotal@Sun.COM {
11697616SVladimir.Kotal@Sun.COM return (1);
11707526SVladimir.Kotal@Sun.COM }
11717211Sjp161948 else
11727526SVladimir.Kotal@Sun.COM {
11737211Sjp161948 global_session = CK_INVALID_HANDLE;
11747526SVladimir.Kotal@Sun.COM /*
11757526SVladimir.Kotal@Sun.COM * free the locks first to prevent memory leak in case
11767526SVladimir.Kotal@Sun.COM * the application calls fork() without finishing the
11777526SVladimir.Kotal@Sun.COM * engine first.
11787526SVladimir.Kotal@Sun.COM */
11797526SVladimir.Kotal@Sun.COM pk11_free_all_locks();
11807526SVladimir.Kotal@Sun.COM }
11817211Sjp161948 }
11827616SVladimir.Kotal@Sun.COM
11830Sstevel@tonic-gate if (pk11_dso == NULL)
11840Sstevel@tonic-gate {
11850Sstevel@tonic-gate PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
11860Sstevel@tonic-gate goto err;
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate
11897211Sjp161948 #ifdef SOLARIS_AES_CTR
11907211Sjp161948 /*
11917211Sjp161948 * We must do this before we start working with slots since we need all
11927211Sjp161948 * NIDs there.
11937211Sjp161948 */
11947211Sjp161948 if (pk11_add_aes_ctr_NIDs() == 0)
11957211Sjp161948 goto err;
11967211Sjp161948 #endif /* SOLARIS_AES_CTR */
11977211Sjp161948
11987211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
11997211Sjp161948 if (check_hw_mechanisms() == 0)
12007211Sjp161948 goto err;
12017211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
12027211Sjp161948
12037616SVladimir.Kotal@Sun.COM /* get the C_GetFunctionList function from the loaded library */
12047616SVladimir.Kotal@Sun.COM p = (CK_C_GetFunctionList)DSO_bind_func(pk11_dso,
12050Sstevel@tonic-gate PK11_GET_FUNCTION_LIST);
12067616SVladimir.Kotal@Sun.COM if (!p)
12070Sstevel@tonic-gate {
12080Sstevel@tonic-gate PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
12090Sstevel@tonic-gate goto err;
12100Sstevel@tonic-gate }
12117616SVladimir.Kotal@Sun.COM
12127616SVladimir.Kotal@Sun.COM /* get the full function list from the loaded library */
12130Sstevel@tonic-gate rv = p(&pFuncList);
12140Sstevel@tonic-gate if (rv != CKR_OK)
12150Sstevel@tonic-gate {
12167211Sjp161948 PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE, rv);
12170Sstevel@tonic-gate goto err;
12180Sstevel@tonic-gate }
12197616SVladimir.Kotal@Sun.COM
12200Sstevel@tonic-gate rv = pFuncList->C_Initialize(NULL_PTR);
12210Sstevel@tonic-gate if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
12220Sstevel@tonic-gate {
12237211Sjp161948 PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_INITIALIZE, rv);
12240Sstevel@tonic-gate goto err;
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate rv = pFuncList->C_GetInfo(&info);
12287616SVladimir.Kotal@Sun.COM if (rv != CKR_OK)
12290Sstevel@tonic-gate {
12307211Sjp161948 PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_GETINFO, rv);
12310Sstevel@tonic-gate goto err;
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate
12347211Sjp161948 if (pk11_choose_slots(&any_slot_found) == 0)
12350Sstevel@tonic-gate goto err;
12360Sstevel@tonic-gate
12377211Sjp161948 /*
12387211Sjp161948 * The library we use, set in def_PK11_LIBNAME, may not offer any
12397211Sjp161948 * slot(s). In that case, we must not proceed but we must not return an
12407211Sjp161948 * error. The reason is that applications that try to set up the PKCS#11
12417211Sjp161948 * engine don't exit on error during the engine initialization just
12427211Sjp161948 * because no slot was present.
12437211Sjp161948 */
12447211Sjp161948 if (any_slot_found == 0)
12457616SVladimir.Kotal@Sun.COM return (1);
12467211Sjp161948
12470Sstevel@tonic-gate if (global_session == CK_INVALID_HANDLE)
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate /* Open the global_session for the new process */
12500Sstevel@tonic-gate rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
12510Sstevel@tonic-gate NULL_PTR, NULL_PTR, &global_session);
12520Sstevel@tonic-gate if (rv != CKR_OK)
12530Sstevel@tonic-gate {
12547211Sjp161948 PK11err_add_data(PK11_F_LIBRARY_INIT,
12557211Sjp161948 PK11_R_OPENSESSION, rv);
12560Sstevel@tonic-gate goto err;
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate
12607616SVladimir.Kotal@Sun.COM /*
12617616SVladimir.Kotal@Sun.COM * Disable digest if C_GetOperationState is not supported since
12627616SVladimir.Kotal@Sun.COM * this function is required by OpenSSL digest copy function
12637616SVladimir.Kotal@Sun.COM */
12640Sstevel@tonic-gate if (pFuncList->C_GetOperationState(global_session, NULL, &ul_state_len)
12657211Sjp161948 == CKR_FUNCTION_NOT_SUPPORTED) {
12667211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
12677211Sjp161948 fprintf(stderr, "%s: C_GetOperationState() not supported, "
12687211Sjp161948 "setting digest_count to 0\n", PK11_DBG);
12697211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
12700Sstevel@tonic-gate digest_count = 0;
12717211Sjp161948 }
12720Sstevel@tonic-gate
12737526SVladimir.Kotal@Sun.COM pk11_library_initialized = TRUE;
12747211Sjp161948 pk11_pid = getpid();
12757526SVladimir.Kotal@Sun.COM /*
12767526SVladimir.Kotal@Sun.COM * if initialization of the locks fails pk11_init_all_locks()
12777526SVladimir.Kotal@Sun.COM * will do the cleanup.
12787526SVladimir.Kotal@Sun.COM */
12797526SVladimir.Kotal@Sun.COM if (!pk11_init_all_locks())
12807526SVladimir.Kotal@Sun.COM goto err;
12817526SVladimir.Kotal@Sun.COM for (i = 0; i < OP_MAX; i++)
12827526SVladimir.Kotal@Sun.COM session_cache[i].head = NULL;
12837526SVladimir.Kotal@Sun.COM /*
12847526SVladimir.Kotal@Sun.COM * initialize active lists. We only use active lists
12857526SVladimir.Kotal@Sun.COM * for asymmetric ciphers.
12867526SVladimir.Kotal@Sun.COM */
12877526SVladimir.Kotal@Sun.COM for (i = 0; i < OP_MAX; i++)
12887526SVladimir.Kotal@Sun.COM active_list[i] = NULL;
12897526SVladimir.Kotal@Sun.COM
12907526SVladimir.Kotal@Sun.COM if (!pk11_atfork_initialized)
12917526SVladimir.Kotal@Sun.COM {
12927526SVladimir.Kotal@Sun.COM if (pthread_atfork(pk11_fork_prepare, pk11_fork_parent,
12937526SVladimir.Kotal@Sun.COM pk11_fork_child) != 0)
12947526SVladimir.Kotal@Sun.COM {
12957526SVladimir.Kotal@Sun.COM PK11err(PK11_F_LIBRARY_INIT, PK11_R_ATFORK_FAILED);
12967526SVladimir.Kotal@Sun.COM goto err;
12977526SVladimir.Kotal@Sun.COM }
12987526SVladimir.Kotal@Sun.COM pk11_atfork_initialized = TRUE;
12997526SVladimir.Kotal@Sun.COM }
13007526SVladimir.Kotal@Sun.COM
13017616SVladimir.Kotal@Sun.COM return (1);
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate err:
13047616SVladimir.Kotal@Sun.COM return (0);
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate
13077616SVladimir.Kotal@Sun.COM /* Destructor (complements the "ENGINE_pk11()" constructor) */
13087534SVladimir.Kotal@Sun.COM /* ARGSUSED */
pk11_destroy(ENGINE * e)13090Sstevel@tonic-gate static int pk11_destroy(ENGINE *e)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate free_PK11_LIBNAME();
13120Sstevel@tonic-gate ERR_unload_pk11_strings();
13137616SVladimir.Kotal@Sun.COM return (1);
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate
13167616SVladimir.Kotal@Sun.COM /*
13177616SVladimir.Kotal@Sun.COM * Termination function to clean up the session, the token, and the pk11
13187616SVladimir.Kotal@Sun.COM * library.
13190Sstevel@tonic-gate */
13207534SVladimir.Kotal@Sun.COM /* ARGSUSED */
pk11_finish(ENGINE * e)13210Sstevel@tonic-gate static int pk11_finish(ENGINE *e)
13220Sstevel@tonic-gate {
13237526SVladimir.Kotal@Sun.COM int i;
13247526SVladimir.Kotal@Sun.COM
13250Sstevel@tonic-gate if (pk11_dso == NULL)
13260Sstevel@tonic-gate {
13270Sstevel@tonic-gate PK11err(PK11_F_FINISH, PK11_R_NOT_LOADED);
13280Sstevel@tonic-gate goto err;
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate
13316847Svk199839 OPENSSL_assert(pFuncList != NULL);
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate if (pk11_free_all_sessions() == 0)
13340Sstevel@tonic-gate goto err;
13350Sstevel@tonic-gate
13367526SVladimir.Kotal@Sun.COM /* free all active lists */
13377526SVladimir.Kotal@Sun.COM for (i = 0; i < OP_MAX; i++)
13387526SVladimir.Kotal@Sun.COM pk11_free_active_list(i);
13397526SVladimir.Kotal@Sun.COM
13400Sstevel@tonic-gate pFuncList->C_CloseSession(global_session);
13417211Sjp161948 global_session = CK_INVALID_HANDLE;
13427211Sjp161948
13437211Sjp161948 /*
13447211Sjp161948 * Since we are part of a library (libcrypto.so), calling this function
13457211Sjp161948 * may have side-effects.
13467211Sjp161948 */
13477211Sjp161948 #if 0
13480Sstevel@tonic-gate pFuncList->C_Finalize(NULL);
13497211Sjp161948 #endif
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate if (!DSO_free(pk11_dso))
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate PK11err(PK11_F_FINISH, PK11_R_DSO_FAILURE);
13540Sstevel@tonic-gate goto err;
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate pk11_dso = NULL;
13570Sstevel@tonic-gate pFuncList = NULL;
13587526SVladimir.Kotal@Sun.COM pk11_library_initialized = FALSE;
13597211Sjp161948 pk11_pid = 0;
13607560SVladimir.Kotal@Sun.COM /*
13617560SVladimir.Kotal@Sun.COM * There is no way how to unregister atfork handlers (other than
13627560SVladimir.Kotal@Sun.COM * unloading the library) so we just free the locks. For this reason
13637560SVladimir.Kotal@Sun.COM * the atfork handlers check if the engine is initialized and bail out
13647560SVladimir.Kotal@Sun.COM * immediately if not. This is necessary in case a process finishes
13657560SVladimir.Kotal@Sun.COM * the engine before calling fork().
13667560SVladimir.Kotal@Sun.COM */
13677526SVladimir.Kotal@Sun.COM pk11_free_all_locks();
13680Sstevel@tonic-gate
13697616SVladimir.Kotal@Sun.COM return (1);
13700Sstevel@tonic-gate
13710Sstevel@tonic-gate err:
13727616SVladimir.Kotal@Sun.COM return (0);
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate /* Standard engine interface function to set the dynamic library path */
13767534SVladimir.Kotal@Sun.COM /* ARGSUSED */
pk11_ctrl(ENGINE * e,int cmd,long i,void * p,void (* f)())13770Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
13780Sstevel@tonic-gate {
13790Sstevel@tonic-gate int initialized = ((pk11_dso == NULL) ? 0 : 1);
13800Sstevel@tonic-gate
13817616SVladimir.Kotal@Sun.COM switch (cmd)
13820Sstevel@tonic-gate {
13830Sstevel@tonic-gate case PK11_CMD_SO_PATH:
13840Sstevel@tonic-gate if (p == NULL)
13850Sstevel@tonic-gate {
13860Sstevel@tonic-gate PK11err(PK11_F_CTRL, ERR_R_PASSED_NULL_PARAMETER);
13877616SVladimir.Kotal@Sun.COM return (0);
13880Sstevel@tonic-gate }
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate if (initialized)
13910Sstevel@tonic-gate {
13920Sstevel@tonic-gate PK11err(PK11_F_CTRL, PK11_R_ALREADY_LOADED);
13937616SVladimir.Kotal@Sun.COM return (0);
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate
13967616SVladimir.Kotal@Sun.COM return (set_PK11_LIBNAME((const char *)p));
13970Sstevel@tonic-gate default:
13980Sstevel@tonic-gate break;
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate
14017616SVladimir.Kotal@Sun.COM PK11err(PK11_F_CTRL, PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED);
14027616SVladimir.Kotal@Sun.COM
14037616SVladimir.Kotal@Sun.COM return (0);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate
14060Sstevel@tonic-gate
14077616SVladimir.Kotal@Sun.COM /* Required function by the engine random interface. It does nothing here */
pk11_rand_cleanup(void)14080Sstevel@tonic-gate static void pk11_rand_cleanup(void)
14090Sstevel@tonic-gate {
14100Sstevel@tonic-gate return;
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate
14137534SVladimir.Kotal@Sun.COM /* ARGSUSED */
pk11_rand_add(const void * buf,int num,double add)14140Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add)
14150Sstevel@tonic-gate {
14160Sstevel@tonic-gate PK11_SESSION *sp;
14170Sstevel@tonic-gate
14187211Sjp161948 if ((sp = pk11_get_session(OP_RAND)) == NULL)
14190Sstevel@tonic-gate return;
14200Sstevel@tonic-gate
14217616SVladimir.Kotal@Sun.COM /*
14227616SVladimir.Kotal@Sun.COM * Ignore any errors (e.g. CKR_RANDOM_SEED_NOT_SUPPORTED) since
14230Sstevel@tonic-gate * the calling functions do not care anyway
14240Sstevel@tonic-gate */
14250Sstevel@tonic-gate pFuncList->C_SeedRandom(sp->session, (unsigned char *) buf, num);
14267211Sjp161948 pk11_return_session(sp, OP_RAND);
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate return;
14290Sstevel@tonic-gate }
14300Sstevel@tonic-gate
pk11_rand_seed(const void * buf,int num)14310Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num)
14320Sstevel@tonic-gate {
14330Sstevel@tonic-gate pk11_rand_add(buf, num, 0);
14340Sstevel@tonic-gate }
14350Sstevel@tonic-gate
pk11_rand_bytes(unsigned char * buf,int num)14360Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate CK_RV rv;
14390Sstevel@tonic-gate PK11_SESSION *sp;
14407616SVladimir.Kotal@Sun.COM
14417211Sjp161948 if ((sp = pk11_get_session(OP_RAND)) == NULL)
14427616SVladimir.Kotal@Sun.COM return (0);
14437616SVladimir.Kotal@Sun.COM
14440Sstevel@tonic-gate rv = pFuncList->C_GenerateRandom(sp->session, buf, num);
14450Sstevel@tonic-gate if (rv != CKR_OK)
14460Sstevel@tonic-gate {
14477211Sjp161948 PK11err_add_data(PK11_F_RAND_BYTES, PK11_R_GENERATERANDOM, rv);
14487211Sjp161948 pk11_return_session(sp, OP_RAND);
14497616SVladimir.Kotal@Sun.COM return (0);
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate
14527211Sjp161948 pk11_return_session(sp, OP_RAND);
14537616SVladimir.Kotal@Sun.COM return (1);
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14567616SVladimir.Kotal@Sun.COM /* Required function by the engine random interface. It does nothing here */
pk11_rand_status(void)14570Sstevel@tonic-gate static int pk11_rand_status(void)
14580Sstevel@tonic-gate {
14597616SVladimir.Kotal@Sun.COM return (1);
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate
14627616SVladimir.Kotal@Sun.COM /* Free all BIGNUM structures from PK11_SESSION. */
pk11_free_nums(PK11_SESSION * sp,PK11_OPTYPE optype)14637526SVladimir.Kotal@Sun.COM static void pk11_free_nums(PK11_SESSION *sp, PK11_OPTYPE optype)
14646847Svk199839 {
14657526SVladimir.Kotal@Sun.COM switch (optype)
14667526SVladimir.Kotal@Sun.COM {
14676847Svk199839 #ifndef OPENSSL_NO_RSA
14687526SVladimir.Kotal@Sun.COM case OP_RSA:
14697526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_n_num != NULL)
14707526SVladimir.Kotal@Sun.COM {
14717526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_n_num);
14727526SVladimir.Kotal@Sun.COM sp->opdata_rsa_n_num = NULL;
14737526SVladimir.Kotal@Sun.COM }
14747526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_e_num != NULL)
14757526SVladimir.Kotal@Sun.COM {
14767526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_e_num);
14777526SVladimir.Kotal@Sun.COM sp->opdata_rsa_e_num = NULL;
14787526SVladimir.Kotal@Sun.COM }
14797526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_d_num != NULL)
14807526SVladimir.Kotal@Sun.COM {
14817526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_d_num);
14827526SVladimir.Kotal@Sun.COM sp->opdata_rsa_d_num = NULL;
14837526SVladimir.Kotal@Sun.COM }
14847526SVladimir.Kotal@Sun.COM break;
14856847Svk199839 #endif
14866847Svk199839 #ifndef OPENSSL_NO_DSA
14877526SVladimir.Kotal@Sun.COM case OP_DSA:
14887526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_pub_num != NULL)
14897526SVladimir.Kotal@Sun.COM {
14907526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dsa_pub_num);
14917526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub_num = NULL;
14927526SVladimir.Kotal@Sun.COM }
14937526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_priv_num != NULL)
14947526SVladimir.Kotal@Sun.COM {
14957526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dsa_priv_num);
14967526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv_num = NULL;
14977526SVladimir.Kotal@Sun.COM }
14987526SVladimir.Kotal@Sun.COM break;
14996847Svk199839 #endif
15006847Svk199839 #ifndef OPENSSL_NO_DH
15017526SVladimir.Kotal@Sun.COM case OP_DH:
15027526SVladimir.Kotal@Sun.COM if (sp->opdata_dh_priv_num != NULL)
15037526SVladimir.Kotal@Sun.COM {
15047526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dh_priv_num);
15057526SVladimir.Kotal@Sun.COM sp->opdata_dh_priv_num = NULL;
15067526SVladimir.Kotal@Sun.COM }
15077526SVladimir.Kotal@Sun.COM break;
15086847Svk199839 #endif
15097526SVladimir.Kotal@Sun.COM default:
15107526SVladimir.Kotal@Sun.COM break;
15117526SVladimir.Kotal@Sun.COM }
15126847Svk199839 }
15130Sstevel@tonic-gate
15146847Svk199839 /*
15156847Svk199839 * Get new PK11_SESSION structure ready for use. Every process must have
15166847Svk199839 * its own freelist of PK11_SESSION structures so handle fork() here
15176847Svk199839 * by destroying the old and creating new freelist.
15186847Svk199839 * The returned PK11_SESSION structure is disconnected from the freelist.
15196847Svk199839 */
15207616SVladimir.Kotal@Sun.COM PK11_SESSION *
pk11_get_session(PK11_OPTYPE optype)15217616SVladimir.Kotal@Sun.COM pk11_get_session(PK11_OPTYPE optype)
15220Sstevel@tonic-gate {
15237526SVladimir.Kotal@Sun.COM PK11_SESSION *sp = NULL, *sp1, *freelist;
15247526SVladimir.Kotal@Sun.COM pthread_mutex_t *freelist_lock;
15250Sstevel@tonic-gate CK_RV rv;
15260Sstevel@tonic-gate
15277211Sjp161948 switch (optype)
15287211Sjp161948 {
15297526SVladimir.Kotal@Sun.COM case OP_RSA:
15307526SVladimir.Kotal@Sun.COM case OP_DSA:
15317526SVladimir.Kotal@Sun.COM case OP_DH:
15327211Sjp161948 case OP_RAND:
15337211Sjp161948 case OP_DIGEST:
15347211Sjp161948 case OP_CIPHER:
15357526SVladimir.Kotal@Sun.COM freelist_lock = session_cache[optype].lock;
15367211Sjp161948 break;
15377211Sjp161948 default:
15387616SVladimir.Kotal@Sun.COM PK11err(PK11_F_GET_SESSION,
15397211Sjp161948 PK11_R_INVALID_OPERATION_TYPE);
15407526SVladimir.Kotal@Sun.COM return (NULL);
15417211Sjp161948 }
15427526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(freelist_lock);
15437526SVladimir.Kotal@Sun.COM freelist = session_cache[optype].head;
15447211Sjp161948 sp = freelist;
15457211Sjp161948
15466847Svk199839 /*
15476847Svk199839 * If the free list is empty, allocate new unitialized (filled
15486847Svk199839 * with zeroes) PK11_SESSION structure otherwise return first
15496847Svk199839 * structure from the freelist.
15506847Svk199839 */
15517211Sjp161948 if (sp == NULL)
15520Sstevel@tonic-gate {
15537616SVladimir.Kotal@Sun.COM if ((sp = OPENSSL_malloc(sizeof (PK11_SESSION))) == NULL)
15540Sstevel@tonic-gate {
15557616SVladimir.Kotal@Sun.COM PK11err(PK11_F_GET_SESSION,
15560Sstevel@tonic-gate PK11_R_MALLOC_FAILURE);
15570Sstevel@tonic-gate goto err;
15580Sstevel@tonic-gate }
15597616SVladimir.Kotal@Sun.COM (void) memset(sp, 0, sizeof (PK11_SESSION));
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate else
15620Sstevel@tonic-gate {
15637211Sjp161948 freelist = sp->next;
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate if (sp->pid != 0 && sp->pid != getpid())
15670Sstevel@tonic-gate {
15686847Svk199839 /*
15696847Svk199839 * We are a new process and thus need to free any inherited
15700Sstevel@tonic-gate * PK11_SESSION objects.
15710Sstevel@tonic-gate */
15727211Sjp161948 while ((sp1 = freelist) != NULL)
15730Sstevel@tonic-gate {
15747211Sjp161948 freelist = sp1->next;
15756847Svk199839 /*
15767211Sjp161948 * NOTE: we do not want to call pk11_free_all_sessions()
15777211Sjp161948 * here because it would close underlying PKCS#11
15787211Sjp161948 * sessions and destroy all objects.
15796847Svk199839 */
15807526SVladimir.Kotal@Sun.COM pk11_free_nums(sp1, optype);
15810Sstevel@tonic-gate OPENSSL_free(sp1);
15820Sstevel@tonic-gate }
15830Sstevel@tonic-gate
15847526SVladimir.Kotal@Sun.COM /* we have to free the active list as well. */
15857526SVladimir.Kotal@Sun.COM pk11_free_active_list(optype);
15867526SVladimir.Kotal@Sun.COM
15870Sstevel@tonic-gate /* Initialize the process */
15880Sstevel@tonic-gate rv = pFuncList->C_Initialize(NULL_PTR);
15890Sstevel@tonic-gate if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
15900Sstevel@tonic-gate {
15917211Sjp161948 PK11err_add_data(PK11_F_GET_SESSION, PK11_R_INITIALIZE,
15927211Sjp161948 rv);
15930Sstevel@tonic-gate OPENSSL_free(sp);
15940Sstevel@tonic-gate sp = NULL;
15950Sstevel@tonic-gate goto err;
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate
15986847Svk199839 /*
15997211Sjp161948 * Choose slot here since the slot table is different on this
16007211Sjp161948 * process. If we are here then we must have found at least one
16017211Sjp161948 * usable slot before so we don't need to check any_slot_found.
16027211Sjp161948 * See pk11_library_init()'s usage of this function for more
16037211Sjp161948 * information.
16040Sstevel@tonic-gate */
16057211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
16067211Sjp161948 if (check_hw_mechanisms() == 0)
16077211Sjp161948 goto err;
16087211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
16097211Sjp161948 if (pk11_choose_slots(NULL) == 0)
16100Sstevel@tonic-gate goto err;
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate /* Open the global_session for the new process */
16130Sstevel@tonic-gate rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
16140Sstevel@tonic-gate NULL_PTR, NULL_PTR, &global_session);
16150Sstevel@tonic-gate if (rv != CKR_OK)
16160Sstevel@tonic-gate {
16177211Sjp161948 PK11err_add_data(PK11_F_GET_SESSION, PK11_R_OPENSESSION,
16187211Sjp161948 rv);
16190Sstevel@tonic-gate OPENSSL_free(sp);
16200Sstevel@tonic-gate sp = NULL;
16210Sstevel@tonic-gate goto err;
16220Sstevel@tonic-gate }
16230Sstevel@tonic-gate
16247616SVladimir.Kotal@Sun.COM /* It is an inherited session and needs re-initialization. */
16257211Sjp161948 if (pk11_setup_session(sp, optype) == 0)
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate OPENSSL_free(sp);
16280Sstevel@tonic-gate sp = NULL;
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate }
16317616SVladimir.Kotal@Sun.COM if (sp->pid == 0)
16320Sstevel@tonic-gate {
16337211Sjp161948 /* It is a new session and needs initialization. */
16347211Sjp161948 if (pk11_setup_session(sp, optype) == 0)
16350Sstevel@tonic-gate {
16360Sstevel@tonic-gate OPENSSL_free(sp);
16370Sstevel@tonic-gate sp = NULL;
16380Sstevel@tonic-gate }
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate
16417526SVladimir.Kotal@Sun.COM /* set new head for the list of PK11_SESSION objects */
16427526SVladimir.Kotal@Sun.COM session_cache[optype].head = freelist;
16437211Sjp161948
16440Sstevel@tonic-gate err:
16456847Svk199839 if (sp != NULL)
16460Sstevel@tonic-gate sp->next = NULL;
16470Sstevel@tonic-gate
16487526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(freelist_lock);
16490Sstevel@tonic-gate
16507616SVladimir.Kotal@Sun.COM return (sp);
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate
16530Sstevel@tonic-gate
16547616SVladimir.Kotal@Sun.COM void
pk11_return_session(PK11_SESSION * sp,PK11_OPTYPE optype)16557616SVladimir.Kotal@Sun.COM pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype)
16560Sstevel@tonic-gate {
16577526SVladimir.Kotal@Sun.COM pthread_mutex_t *freelist_lock;
16587526SVladimir.Kotal@Sun.COM PK11_SESSION *freelist;
16597526SVladimir.Kotal@Sun.COM
16600Sstevel@tonic-gate if (sp == NULL || sp->pid != getpid())
16610Sstevel@tonic-gate return;
16627616SVladimir.Kotal@Sun.COM
16637211Sjp161948 switch (optype)
16647211Sjp161948 {
16657526SVladimir.Kotal@Sun.COM case OP_RSA:
16667526SVladimir.Kotal@Sun.COM case OP_DSA:
16677526SVladimir.Kotal@Sun.COM case OP_DH:
16687211Sjp161948 case OP_RAND:
16697211Sjp161948 case OP_DIGEST:
16707211Sjp161948 case OP_CIPHER:
16717526SVladimir.Kotal@Sun.COM freelist_lock = session_cache[optype].lock;
16727211Sjp161948 break;
16737526SVladimir.Kotal@Sun.COM default:
16747526SVladimir.Kotal@Sun.COM PK11err(PK11_F_RETURN_SESSION,
16757526SVladimir.Kotal@Sun.COM PK11_R_INVALID_OPERATION_TYPE);
16767526SVladimir.Kotal@Sun.COM return;
16777211Sjp161948 }
16780Sstevel@tonic-gate
16797526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(freelist_lock);
16807526SVladimir.Kotal@Sun.COM freelist = session_cache[optype].head;
16817526SVladimir.Kotal@Sun.COM sp->next = freelist;
16827526SVladimir.Kotal@Sun.COM session_cache[optype].head = sp;
16837526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(freelist_lock);
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate
16877616SVladimir.Kotal@Sun.COM /* Destroy all objects. This function is called when the engine is finished */
pk11_free_all_sessions()16880Sstevel@tonic-gate static int pk11_free_all_sessions()
16890Sstevel@tonic-gate {
16907211Sjp161948 int ret = 1;
16917526SVladimir.Kotal@Sun.COM int type;
16920Sstevel@tonic-gate
16936847Svk199839 #ifndef OPENSSL_NO_RSA
16946847Svk199839 (void) pk11_destroy_rsa_key_objects(NULL);
16957211Sjp161948 #endif /* OPENSSL_NO_RSA */
16966847Svk199839 #ifndef OPENSSL_NO_DSA
16976847Svk199839 (void) pk11_destroy_dsa_key_objects(NULL);
16987211Sjp161948 #endif /* OPENSSL_NO_DSA */
16996847Svk199839 #ifndef OPENSSL_NO_DH
17006847Svk199839 (void) pk11_destroy_dh_key_objects(NULL);
17017211Sjp161948 #endif /* OPENSSL_NO_DH */
17026847Svk199839 (void) pk11_destroy_cipher_key_objects(NULL);
17037211Sjp161948
17047211Sjp161948 /*
17057211Sjp161948 * We try to release as much as we can but any error means that we will
17067211Sjp161948 * return 0 on exit.
17077211Sjp161948 */
17087526SVladimir.Kotal@Sun.COM for (type = 0; type < OP_MAX; type++)
17097526SVladimir.Kotal@Sun.COM {
17107526SVladimir.Kotal@Sun.COM if (pk11_free_session_list(type) == 0)
17117526SVladimir.Kotal@Sun.COM ret = 0;
17127526SVladimir.Kotal@Sun.COM }
17137211Sjp161948
17147616SVladimir.Kotal@Sun.COM return (ret);
17157211Sjp161948 }
17167616SVladimir.Kotal@Sun.COM
17177211Sjp161948 /*
17187526SVladimir.Kotal@Sun.COM * Destroy session structures from the linked list specified. Free as many
17197526SVladimir.Kotal@Sun.COM * sessions as possible but any failure in C_CloseSession() means that we
17207526SVladimir.Kotal@Sun.COM * return an error on return.
17217211Sjp161948 */
pk11_free_session_list(PK11_OPTYPE optype)17227526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype)
17237211Sjp161948 {
17247211Sjp161948 CK_RV rv;
17257211Sjp161948 PK11_SESSION *sp = NULL;
17267526SVladimir.Kotal@Sun.COM PK11_SESSION *freelist = NULL;
17277211Sjp161948 pid_t mypid = getpid();
17287526SVladimir.Kotal@Sun.COM pthread_mutex_t *freelist_lock;
17297211Sjp161948 int ret = 1;
17307211Sjp161948
17317526SVladimir.Kotal@Sun.COM switch (optype)
17327526SVladimir.Kotal@Sun.COM {
17337526SVladimir.Kotal@Sun.COM case OP_RSA:
17347526SVladimir.Kotal@Sun.COM case OP_DSA:
17357526SVladimir.Kotal@Sun.COM case OP_DH:
17367526SVladimir.Kotal@Sun.COM case OP_RAND:
17377526SVladimir.Kotal@Sun.COM case OP_DIGEST:
17387526SVladimir.Kotal@Sun.COM case OP_CIPHER:
17397526SVladimir.Kotal@Sun.COM freelist_lock = session_cache[optype].lock;
17407526SVladimir.Kotal@Sun.COM break;
17417526SVladimir.Kotal@Sun.COM default:
17427526SVladimir.Kotal@Sun.COM PK11err(PK11_F_FREE_ALL_SESSIONS,
17437526SVladimir.Kotal@Sun.COM PK11_R_INVALID_OPERATION_TYPE);
17447526SVladimir.Kotal@Sun.COM return (0);
17457526SVladimir.Kotal@Sun.COM }
17467526SVladimir.Kotal@Sun.COM
17477526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(freelist_lock);
17487526SVladimir.Kotal@Sun.COM freelist = session_cache[optype].head;
17497526SVladimir.Kotal@Sun.COM while ((sp = freelist) != NULL)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate if (sp->session != CK_INVALID_HANDLE && sp->pid == mypid)
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate rv = pFuncList->C_CloseSession(sp->session);
17540Sstevel@tonic-gate if (rv != CKR_OK)
17550Sstevel@tonic-gate {
17567616SVladimir.Kotal@Sun.COM PK11err_add_data(PK11_F_FREE_ALL_SESSIONS,
17577211Sjp161948 PK11_R_CLOSESESSION, rv);
17587211Sjp161948 ret = 0;
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate }
17617526SVladimir.Kotal@Sun.COM freelist = sp->next;
17627526SVladimir.Kotal@Sun.COM pk11_free_nums(sp, optype);
17630Sstevel@tonic-gate OPENSSL_free(sp);
17640Sstevel@tonic-gate }
17657211Sjp161948
17667526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(freelist_lock);
17677616SVladimir.Kotal@Sun.COM return (ret);
17680Sstevel@tonic-gate }
17690Sstevel@tonic-gate
17700Sstevel@tonic-gate
pk11_setup_session(PK11_SESSION * sp,PK11_OPTYPE optype)17717211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype)
17720Sstevel@tonic-gate {
17730Sstevel@tonic-gate CK_RV rv;
17747211Sjp161948 CK_SLOT_ID myslot;
17757211Sjp161948
17767211Sjp161948 switch (optype)
17777211Sjp161948 {
17787526SVladimir.Kotal@Sun.COM case OP_RSA:
17797526SVladimir.Kotal@Sun.COM case OP_DSA:
17807526SVladimir.Kotal@Sun.COM case OP_DH:
17817211Sjp161948 myslot = pubkey_SLOTID;
17827211Sjp161948 break;
17837211Sjp161948 case OP_RAND:
17847211Sjp161948 myslot = rand_SLOTID;
17857211Sjp161948 break;
17867211Sjp161948 case OP_DIGEST:
17877211Sjp161948 case OP_CIPHER:
17887211Sjp161948 myslot = SLOTID;
17897211Sjp161948 break;
17907211Sjp161948 default:
17917211Sjp161948 PK11err(PK11_F_SETUP_SESSION,
17927211Sjp161948 PK11_R_INVALID_OPERATION_TYPE);
17937616SVladimir.Kotal@Sun.COM return (0);
17947211Sjp161948 }
17957211Sjp161948
17960Sstevel@tonic-gate sp->session = CK_INVALID_HANDLE;
17977211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
17987211Sjp161948 fprintf(stderr, "%s: myslot=%d optype=%d\n", PK11_DBG, myslot, optype);
17997211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
18007211Sjp161948 rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
18010Sstevel@tonic-gate NULL_PTR, NULL_PTR, &sp->session);
18020Sstevel@tonic-gate if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate /*
18050Sstevel@tonic-gate * We are probably a child process so force the
18060Sstevel@tonic-gate * reinitialize of the session
18070Sstevel@tonic-gate */
18087526SVladimir.Kotal@Sun.COM pk11_library_initialized = FALSE;
18097628SVladimir.Kotal@Sun.COM if (!pk11_library_init(NULL))
18107628SVladimir.Kotal@Sun.COM return (0);
18117211Sjp161948 rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
18120Sstevel@tonic-gate NULL_PTR, NULL_PTR, &sp->session);
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate if (rv != CKR_OK)
18150Sstevel@tonic-gate {
18167211Sjp161948 PK11err_add_data(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION, rv);
18177616SVladimir.Kotal@Sun.COM return (0);
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate
18207526SVladimir.Kotal@Sun.COM sp->pid = getpid();
18217526SVladimir.Kotal@Sun.COM
18227526SVladimir.Kotal@Sun.COM switch (optype)
18230Sstevel@tonic-gate {
18246847Svk199839 #ifndef OPENSSL_NO_RSA
18257526SVladimir.Kotal@Sun.COM case OP_RSA:
18267526SVladimir.Kotal@Sun.COM sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
18277526SVladimir.Kotal@Sun.COM sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
18287526SVladimir.Kotal@Sun.COM sp->opdata_rsa_pub = NULL;
18297526SVladimir.Kotal@Sun.COM sp->opdata_rsa_n_num = NULL;
18307526SVladimir.Kotal@Sun.COM sp->opdata_rsa_e_num = NULL;
18317526SVladimir.Kotal@Sun.COM sp->opdata_rsa_priv = NULL;
18327526SVladimir.Kotal@Sun.COM sp->opdata_rsa_d_num = NULL;
18337526SVladimir.Kotal@Sun.COM break;
18347211Sjp161948 #endif /* OPENSSL_NO_RSA */
18356847Svk199839 #ifndef OPENSSL_NO_DSA
18367526SVladimir.Kotal@Sun.COM case OP_DSA:
18377526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
18387526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
18397526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub = NULL;
18407526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub_num = NULL;
18417526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv = NULL;
18427526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv_num = NULL;
18437526SVladimir.Kotal@Sun.COM break;
18447211Sjp161948 #endif /* OPENSSL_NO_DSA */
18456847Svk199839 #ifndef OPENSSL_NO_DH
18467526SVladimir.Kotal@Sun.COM case OP_DH:
18477526SVladimir.Kotal@Sun.COM sp->opdata_dh_key = CK_INVALID_HANDLE;
18487526SVladimir.Kotal@Sun.COM sp->opdata_dh = NULL;
18497526SVladimir.Kotal@Sun.COM sp->opdata_dh_priv_num = NULL;
18507526SVladimir.Kotal@Sun.COM break;
18517211Sjp161948 #endif /* OPENSSL_NO_DH */
18527526SVladimir.Kotal@Sun.COM case OP_CIPHER:
18537526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key = CK_INVALID_HANDLE;
18547526SVladimir.Kotal@Sun.COM sp->opdata_encrypt = -1;
18557526SVladimir.Kotal@Sun.COM break;
18567526SVladimir.Kotal@Sun.COM }
18570Sstevel@tonic-gate
18587616SVladimir.Kotal@Sun.COM return (1);
18590Sstevel@tonic-gate }
18600Sstevel@tonic-gate
18616847Svk199839 #ifndef OPENSSL_NO_RSA
18626847Svk199839 /* Destroy RSA public key from single session. */
18637616SVladimir.Kotal@Sun.COM int
pk11_destroy_rsa_object_pub(PK11_SESSION * sp,CK_BBOOL uselock)18647616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
18656847Svk199839 {
18666847Svk199839 int ret = 0;
18676847Svk199839
18687526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_pub_key != CK_INVALID_HANDLE)
18696847Svk199839 {
18707526SVladimir.Kotal@Sun.COM TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_pub_key,
18717526SVladimir.Kotal@Sun.COM ret, uselock, OP_RSA);
18727526SVladimir.Kotal@Sun.COM sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
18737526SVladimir.Kotal@Sun.COM sp->opdata_rsa_pub = NULL;
18747526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_n_num != NULL)
18757526SVladimir.Kotal@Sun.COM {
18767526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_n_num);
18777526SVladimir.Kotal@Sun.COM sp->opdata_rsa_n_num = NULL;
18787526SVladimir.Kotal@Sun.COM }
18797526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_e_num != NULL)
18807526SVladimir.Kotal@Sun.COM {
18817526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_e_num);
18827526SVladimir.Kotal@Sun.COM sp->opdata_rsa_e_num = NULL;
18837526SVladimir.Kotal@Sun.COM }
18846847Svk199839 }
18856847Svk199839
18866847Svk199839 return (ret);
18876847Svk199839 }
18886847Svk199839
18896847Svk199839 /* Destroy RSA private key from single session. */
18907616SVladimir.Kotal@Sun.COM int
pk11_destroy_rsa_object_priv(PK11_SESSION * sp,CK_BBOOL uselock)18917616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
18920Sstevel@tonic-gate {
18930Sstevel@tonic-gate int ret = 0;
18946847Svk199839
18957526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_priv_key != CK_INVALID_HANDLE)
18966847Svk199839 {
18977526SVladimir.Kotal@Sun.COM TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_priv_key,
18987526SVladimir.Kotal@Sun.COM ret, uselock, OP_RSA);
18997526SVladimir.Kotal@Sun.COM sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
19007526SVladimir.Kotal@Sun.COM sp->opdata_rsa_priv = NULL;
19017526SVladimir.Kotal@Sun.COM if (sp->opdata_rsa_d_num != NULL)
19027526SVladimir.Kotal@Sun.COM {
19037526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_rsa_d_num);
19047526SVladimir.Kotal@Sun.COM sp->opdata_rsa_d_num = NULL;
19057526SVladimir.Kotal@Sun.COM }
19066847Svk199839 }
19076847Svk199839
19086847Svk199839 return (ret);
19096847Svk199839 }
19106847Svk199839
19116847Svk199839 /*
19127211Sjp161948 * Destroy RSA key object wrapper. If session is NULL, try to destroy all
19137211Sjp161948 * objects in the free list.
19146847Svk199839 */
19157616SVladimir.Kotal@Sun.COM int
pk11_destroy_rsa_key_objects(PK11_SESSION * session)19167616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_key_objects(PK11_SESSION *session)
19176847Svk199839 {
19186847Svk199839 int ret = 1;
19190Sstevel@tonic-gate PK11_SESSION *sp = NULL;
19200Sstevel@tonic-gate PK11_SESSION *local_free_session;
19216847Svk199839 CK_BBOOL uselock = TRUE;
19220Sstevel@tonic-gate
19236847Svk199839 if (session != NULL)
19240Sstevel@tonic-gate local_free_session = session;
19250Sstevel@tonic-gate else
19266847Svk199839 {
19277526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(session_cache[OP_RSA].lock);
19287526SVladimir.Kotal@Sun.COM local_free_session = session_cache[OP_RSA].head;
19296847Svk199839 uselock = FALSE;
19306847Svk199839 }
19310Sstevel@tonic-gate
19326847Svk199839 /*
19336847Svk199839 * go through the list of sessions and delete key objects
19346847Svk199839 */
19350Sstevel@tonic-gate while ((sp = local_free_session) != NULL)
19360Sstevel@tonic-gate {
19370Sstevel@tonic-gate local_free_session = sp->next;
19380Sstevel@tonic-gate
19396847Svk199839 /*
19406847Svk199839 * Do not terminate list traversal if one of the
19416847Svk199839 * destroy operations fails.
19426847Svk199839 */
19436847Svk199839 if (pk11_destroy_rsa_object_pub(sp, uselock) == 0)
19440Sstevel@tonic-gate {
19456847Svk199839 ret = 0;
19466847Svk199839 continue;
19470Sstevel@tonic-gate }
19486847Svk199839 if (pk11_destroy_rsa_object_priv(sp, uselock) == 0)
19496847Svk199839 {
19506847Svk199839 ret = 0;
19516847Svk199839 continue;
19526847Svk199839 }
19536847Svk199839 }
19540Sstevel@tonic-gate
19556847Svk199839 if (session == NULL)
19567526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[OP_RSA].lock);
19570Sstevel@tonic-gate
19587616SVladimir.Kotal@Sun.COM return (ret);
19590Sstevel@tonic-gate }
19607211Sjp161948 #endif /* OPENSSL_NO_RSA */
19610Sstevel@tonic-gate
19626847Svk199839 #ifndef OPENSSL_NO_DSA
19636847Svk199839 /* Destroy DSA public key from single session. */
19647616SVladimir.Kotal@Sun.COM int
pk11_destroy_dsa_object_pub(PK11_SESSION * sp,CK_BBOOL uselock)19657616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate int ret = 0;
19686847Svk199839
19697526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_pub_key != CK_INVALID_HANDLE)
19706847Svk199839 {
19717526SVladimir.Kotal@Sun.COM TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_pub_key,
19727526SVladimir.Kotal@Sun.COM ret, uselock, OP_DSA);
19737526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
19747526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub = NULL;
19757526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_pub_num != NULL)
19767526SVladimir.Kotal@Sun.COM {
19777526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dsa_pub_num);
19787526SVladimir.Kotal@Sun.COM sp->opdata_dsa_pub_num = NULL;
19797526SVladimir.Kotal@Sun.COM }
19806847Svk199839 }
19816847Svk199839
19826847Svk199839 return (ret);
19836847Svk199839 }
19846847Svk199839
19856847Svk199839 /* Destroy DSA private key from single session. */
19867616SVladimir.Kotal@Sun.COM int
pk11_destroy_dsa_object_priv(PK11_SESSION * sp,CK_BBOOL uselock)19877616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
19886847Svk199839 {
19896847Svk199839 int ret = 0;
19906847Svk199839
19917526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_priv_key != CK_INVALID_HANDLE)
19926847Svk199839 {
19937526SVladimir.Kotal@Sun.COM TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_priv_key,
19947526SVladimir.Kotal@Sun.COM ret, uselock, OP_DSA);
19957526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
19967526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv = NULL;
19977526SVladimir.Kotal@Sun.COM if (sp->opdata_dsa_priv_num != NULL)
19987526SVladimir.Kotal@Sun.COM {
19997526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dsa_priv_num);
20007526SVladimir.Kotal@Sun.COM sp->opdata_dsa_priv_num = NULL;
20017526SVladimir.Kotal@Sun.COM }
20026847Svk199839 }
20036847Svk199839
20046847Svk199839 return (ret);
20056847Svk199839 }
20066847Svk199839
20076847Svk199839 /*
20087211Sjp161948 * Destroy DSA key object wrapper. If session is NULL, try to destroy all
20097211Sjp161948 * objects in the free list.
20106847Svk199839 */
20117616SVladimir.Kotal@Sun.COM int
pk11_destroy_dsa_key_objects(PK11_SESSION * session)20127616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_key_objects(PK11_SESSION *session)
20136847Svk199839 {
20146847Svk199839 int ret = 1;
20150Sstevel@tonic-gate PK11_SESSION *sp = NULL;
20160Sstevel@tonic-gate PK11_SESSION *local_free_session;
20176847Svk199839 CK_BBOOL uselock = TRUE;
20180Sstevel@tonic-gate
20196847Svk199839 if (session != NULL)
20200Sstevel@tonic-gate local_free_session = session;
20210Sstevel@tonic-gate else
20226847Svk199839 {
20237526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(session_cache[OP_DSA].lock);
20247526SVladimir.Kotal@Sun.COM local_free_session = session_cache[OP_DSA].head;
20256847Svk199839 uselock = FALSE;
20266847Svk199839 }
20276847Svk199839
20286847Svk199839 /*
20296847Svk199839 * go through the list of sessions and delete key objects
20306847Svk199839 */
20310Sstevel@tonic-gate while ((sp = local_free_session) != NULL)
20320Sstevel@tonic-gate {
20330Sstevel@tonic-gate local_free_session = sp->next;
20340Sstevel@tonic-gate
20356847Svk199839 /*
20366847Svk199839 * Do not terminate list traversal if one of the
20376847Svk199839 * destroy operations fails.
20386847Svk199839 */
20396847Svk199839 if (pk11_destroy_dsa_object_pub(sp, uselock) == 0)
20400Sstevel@tonic-gate {
20416847Svk199839 ret = 0;
20426847Svk199839 continue;
20430Sstevel@tonic-gate }
20446847Svk199839 if (pk11_destroy_dsa_object_priv(sp, uselock) == 0)
20456847Svk199839 {
20466847Svk199839 ret = 0;
20476847Svk199839 continue;
20486847Svk199839 }
20490Sstevel@tonic-gate }
20506847Svk199839
20516847Svk199839 if (session == NULL)
20527526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[OP_DSA].lock);
20530Sstevel@tonic-gate
20547616SVladimir.Kotal@Sun.COM return (ret);
20550Sstevel@tonic-gate }
20567211Sjp161948 #endif /* OPENSSL_NO_DSA */
20576847Svk199839
20586847Svk199839 #ifndef OPENSSL_NO_DH
20596847Svk199839 /* Destroy DH key from single session. */
20607616SVladimir.Kotal@Sun.COM int
pk11_destroy_dh_object(PK11_SESSION * sp,CK_BBOOL uselock)20617616SVladimir.Kotal@Sun.COM pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock)
20626847Svk199839 {
20636847Svk199839 int ret = 0;
20646847Svk199839
20657526SVladimir.Kotal@Sun.COM if (sp->opdata_dh_key != CK_INVALID_HANDLE)
20666847Svk199839 {
20677526SVladimir.Kotal@Sun.COM TRY_OBJ_DESTROY(sp->session, sp->opdata_dh_key,
20687526SVladimir.Kotal@Sun.COM ret, uselock, OP_DH);
20697526SVladimir.Kotal@Sun.COM sp->opdata_dh_key = CK_INVALID_HANDLE;
20707526SVladimir.Kotal@Sun.COM sp->opdata_dh = NULL;
20717526SVladimir.Kotal@Sun.COM if (sp->opdata_dh_priv_num != NULL)
20727526SVladimir.Kotal@Sun.COM {
20737526SVladimir.Kotal@Sun.COM BN_free(sp->opdata_dh_priv_num);
20747526SVladimir.Kotal@Sun.COM sp->opdata_dh_priv_num = NULL;
20757526SVladimir.Kotal@Sun.COM }
20766847Svk199839 }
20776847Svk199839
20786847Svk199839 return (ret);
20796847Svk199839 }
20806847Svk199839
20816847Svk199839 /*
20826847Svk199839 * Destroy DH key object wrapper.
20836847Svk199839 *
20846847Svk199839 * arg0: pointer to PKCS#11 engine session structure
20856847Svk199839 * if session is NULL, try to destroy all objects in the free list
20866847Svk199839 */
20877616SVladimir.Kotal@Sun.COM int
pk11_destroy_dh_key_objects(PK11_SESSION * session)20887616SVladimir.Kotal@Sun.COM pk11_destroy_dh_key_objects(PK11_SESSION *session)
20896847Svk199839 {
20906847Svk199839 int ret = 1;
20916847Svk199839 PK11_SESSION *sp = NULL;
20926847Svk199839 PK11_SESSION *local_free_session;
20936847Svk199839 CK_BBOOL uselock = TRUE;
20946847Svk199839
20956847Svk199839 if (session != NULL)
20966847Svk199839 local_free_session = session;
20976847Svk199839 else
20986847Svk199839 {
20997526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(session_cache[OP_DH].lock);
21007526SVladimir.Kotal@Sun.COM local_free_session = session_cache[OP_DH].head;
21016847Svk199839 uselock = FALSE;
21026847Svk199839 }
21036847Svk199839
21046847Svk199839 while ((sp = local_free_session) != NULL)
21056847Svk199839 {
21066847Svk199839 local_free_session = sp->next;
21076847Svk199839
21086847Svk199839 /*
21096847Svk199839 * Do not terminate list traversal if one of the
21106847Svk199839 * destroy operations fails.
21116847Svk199839 */
21126847Svk199839 if (pk11_destroy_dh_object(sp, uselock) == 0)
21136847Svk199839 {
21146847Svk199839 ret = 0;
21156847Svk199839 continue;
21166847Svk199839 }
21176847Svk199839 }
21186847Svk199839 err:
21196847Svk199839 if (session == NULL)
21207526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[OP_DH].lock);
21216847Svk199839
21227616SVladimir.Kotal@Sun.COM return (ret);
21236847Svk199839 }
21247211Sjp161948 #endif /* OPENSSL_NO_DH */
21250Sstevel@tonic-gate
pk11_destroy_object(CK_SESSION_HANDLE session,CK_OBJECT_HANDLE oh)21260Sstevel@tonic-gate static int pk11_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE oh)
21270Sstevel@tonic-gate {
21280Sstevel@tonic-gate CK_RV rv;
21290Sstevel@tonic-gate rv = pFuncList->C_DestroyObject(session, oh);
21300Sstevel@tonic-gate if (rv != CKR_OK)
21310Sstevel@tonic-gate {
21327211Sjp161948 PK11err_add_data(PK11_F_DESTROY_OBJECT, PK11_R_DESTROYOBJECT,
21337211Sjp161948 rv);
21347616SVladimir.Kotal@Sun.COM return (0);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate
21377616SVladimir.Kotal@Sun.COM return (1);
21380Sstevel@tonic-gate }
21390Sstevel@tonic-gate
21400Sstevel@tonic-gate
21417616SVladimir.Kotal@Sun.COM /* Symmetric ciphers and digests support functions */
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate static int
cipher_nid_to_pk11(int nid)21440Sstevel@tonic-gate cipher_nid_to_pk11(int nid)
21450Sstevel@tonic-gate {
21460Sstevel@tonic-gate int i;
21470Sstevel@tonic-gate
21480Sstevel@tonic-gate for (i = 0; i < PK11_CIPHER_MAX; i++)
21490Sstevel@tonic-gate if (ciphers[i].nid == nid)
21500Sstevel@tonic-gate return (ciphers[i].id);
21510Sstevel@tonic-gate return (-1);
21520Sstevel@tonic-gate }
21530Sstevel@tonic-gate
21540Sstevel@tonic-gate static int
pk11_usable_ciphers(const int ** nids)21550Sstevel@tonic-gate pk11_usable_ciphers(const int **nids)
21560Sstevel@tonic-gate {
21570Sstevel@tonic-gate if (cipher_count > 0)
21580Sstevel@tonic-gate *nids = cipher_nids;
21590Sstevel@tonic-gate else
21600Sstevel@tonic-gate *nids = NULL;
21610Sstevel@tonic-gate return (cipher_count);
21620Sstevel@tonic-gate }
21630Sstevel@tonic-gate
21640Sstevel@tonic-gate static int
pk11_usable_digests(const int ** nids)21650Sstevel@tonic-gate pk11_usable_digests(const int **nids)
21660Sstevel@tonic-gate {
21670Sstevel@tonic-gate if (digest_count > 0)
21680Sstevel@tonic-gate *nids = digest_nids;
21690Sstevel@tonic-gate else
21700Sstevel@tonic-gate *nids = NULL;
21710Sstevel@tonic-gate return (digest_count);
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate
21747211Sjp161948 /*
21757211Sjp161948 * Init context for encryption or decryption using a symmetric key.
21767211Sjp161948 */
pk11_init_symmetric(EVP_CIPHER_CTX * ctx,PK11_CIPHER * pcipher,PK11_SESSION * sp,CK_MECHANISM_PTR pmech)21777211Sjp161948 static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_CIPHER *pcipher,
21787211Sjp161948 PK11_SESSION *sp, CK_MECHANISM_PTR pmech)
21797211Sjp161948 {
21807211Sjp161948 CK_RV rv;
21817211Sjp161948 #ifdef SOLARIS_AES_CTR
21827211Sjp161948 CK_AES_CTR_PARAMS ctr_params;
21837211Sjp161948 #endif /* SOLARIS_AES_CTR */
21847616SVladimir.Kotal@Sun.COM
21857211Sjp161948 /*
21867211Sjp161948 * We expect pmech->mechanism to be already set and
21877211Sjp161948 * pParameter/ulParameterLen initialized to NULL/0 before
21887211Sjp161948 * pk11_init_symetric() is called.
21897211Sjp161948 */
21907211Sjp161948 OPENSSL_assert(pmech->mechanism != NULL);
21917211Sjp161948 OPENSSL_assert(pmech->pParameter == NULL);
21927211Sjp161948 OPENSSL_assert(pmech->ulParameterLen == 0);
21937211Sjp161948
21947211Sjp161948 #ifdef SOLARIS_AES_CTR
21957211Sjp161948 if (ctx->cipher->nid == NID_aes_128_ctr ||
21967211Sjp161948 ctx->cipher->nid == NID_aes_192_ctr ||
21977211Sjp161948 ctx->cipher->nid == NID_aes_256_ctr)
21987211Sjp161948 {
21997211Sjp161948 pmech->pParameter = (void *)(&ctr_params);
22007616SVladimir.Kotal@Sun.COM pmech->ulParameterLen = sizeof (ctr_params);
22017211Sjp161948 /*
22027211Sjp161948 * For now, we are limited to the fixed length of the counter,
22037211Sjp161948 * it covers the whole counter block. That's what RFC 4344
22047211Sjp161948 * needs. For more information on internal structure of the
22057211Sjp161948 * counter block, see RFC 3686. If needed in the future, we can
22067211Sjp161948 * add code so that the counter length can be set via
22077211Sjp161948 * ENGINE_ctrl() function.
22087211Sjp161948 */
22097211Sjp161948 ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
22107211Sjp161948 OPENSSL_assert(pcipher->iv_len == AES_BLOCK_SIZE);
22117534SVladimir.Kotal@Sun.COM (void) memcpy(ctr_params.cb, ctx->iv, AES_BLOCK_SIZE);
22127211Sjp161948 }
22137211Sjp161948 else
22147211Sjp161948 #endif /* SOLARIS_AES_CTR */
22157211Sjp161948 {
22167211Sjp161948 if (pcipher->iv_len > 0)
22177211Sjp161948 {
22187211Sjp161948 pmech->pParameter = (void *)ctx->iv;
22197211Sjp161948 pmech->ulParameterLen = pcipher->iv_len;
22207211Sjp161948 }
22217211Sjp161948 }
22227211Sjp161948
22237211Sjp161948 /* if we get here, the encryption needs to be reinitialized */
22247211Sjp161948 if (ctx->encrypt)
22257526SVladimir.Kotal@Sun.COM rv = pFuncList->C_EncryptInit(sp->session, pmech,
22267526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key);
22277211Sjp161948 else
22287526SVladimir.Kotal@Sun.COM rv = pFuncList->C_DecryptInit(sp->session, pmech,
22297526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key);
22307211Sjp161948
22317211Sjp161948 if (rv != CKR_OK)
22327211Sjp161948 {
22337211Sjp161948 PK11err_add_data(PK11_F_CIPHER_INIT, ctx->encrypt ?
22347211Sjp161948 PK11_R_ENCRYPTINIT : PK11_R_DECRYPTINIT, rv);
22357211Sjp161948 pk11_return_session(sp, OP_CIPHER);
22367211Sjp161948 return (0);
22377211Sjp161948 }
22387211Sjp161948
22397211Sjp161948 return (1);
22407211Sjp161948 }
22417211Sjp161948
22427534SVladimir.Kotal@Sun.COM /* ARGSUSED */
22430Sstevel@tonic-gate static int
pk11_cipher_init(EVP_CIPHER_CTX * ctx,const unsigned char * key,const unsigned char * iv,int enc)22440Sstevel@tonic-gate pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
22450Sstevel@tonic-gate const unsigned char *iv, int enc)
22460Sstevel@tonic-gate {
22474320Sjp161948 CK_MECHANISM mech;
22480Sstevel@tonic-gate int index;
22490Sstevel@tonic-gate PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
22500Sstevel@tonic-gate PK11_SESSION *sp;
22517211Sjp161948 PK11_CIPHER *p_ciph_table_row;
22527616SVladimir.Kotal@Sun.COM
22530Sstevel@tonic-gate state->sp = NULL;
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate index = cipher_nid_to_pk11(ctx->cipher->nid);
22560Sstevel@tonic-gate if (index < 0 || index >= PK11_CIPHER_MAX)
22577616SVladimir.Kotal@Sun.COM return (0);
22580Sstevel@tonic-gate
22597211Sjp161948 p_ciph_table_row = &ciphers[index];
22607211Sjp161948 /*
22617211Sjp161948 * iv_len in the ctx->cipher structure is the maximum IV length for the
22627211Sjp161948 * current cipher and it must be less or equal to the IV length in our
22638805SJan.Pechanec@Sun.COM * ciphers table. The key length must be in the allowed interval. From
22648805SJan.Pechanec@Sun.COM * all cipher modes that the PKCS#11 engine supports only RC4 allows a
22658805SJan.Pechanec@Sun.COM * key length to be in some range, all other NIDs have a precise key
22668805SJan.Pechanec@Sun.COM * length. Every application can define its own EVP functions so this
22678805SJan.Pechanec@Sun.COM * code serves as a sanity check.
22687211Sjp161948 *
22697211Sjp161948 * Note that the reason why the IV length in ctx->cipher might be
22707211Sjp161948 * greater than the actual length is that OpenSSL uses BLOCK_CIPHER_defs
22717211Sjp161948 * macro to define functions that return EVP structures for all DES
22727211Sjp161948 * modes. So, even ECB modes get 8 byte IV.
22737211Sjp161948 */
22747211Sjp161948 if (ctx->cipher->iv_len < p_ciph_table_row->iv_len ||
22758805SJan.Pechanec@Sun.COM ctx->key_len < p_ciph_table_row->min_key_len ||
22768805SJan.Pechanec@Sun.COM ctx->key_len > p_ciph_table_row->max_key_len) {
22777211Sjp161948 PK11err(PK11_F_CIPHER_INIT, PK11_R_KEY_OR_IV_LEN_PROBLEM);
22787616SVladimir.Kotal@Sun.COM return (0);
22798805SJan.Pechanec@Sun.COM }
22807211Sjp161948
22817211Sjp161948 if ((sp = pk11_get_session(OP_CIPHER)) == NULL)
22827616SVladimir.Kotal@Sun.COM return (0);
22830Sstevel@tonic-gate
22844320Sjp161948 /* if applicable, the mechanism parameter is used for IV */
22857211Sjp161948 mech.mechanism = p_ciph_table_row->mech_type;
22864320Sjp161948 mech.pParameter = NULL;
22874320Sjp161948 mech.ulParameterLen = 0;
22884320Sjp161948
22897616SVladimir.Kotal@Sun.COM /* The key object is destroyed here if it is not the current key. */
22908805SJan.Pechanec@Sun.COM (void) check_new_cipher_key(sp, key, ctx->key_len);
22917616SVladimir.Kotal@Sun.COM
22927616SVladimir.Kotal@Sun.COM /*
22937616SVladimir.Kotal@Sun.COM * If the key is the same and the encryption is also the same, then
22947616SVladimir.Kotal@Sun.COM * just reuse it. However, we must not forget to reinitialize the
22956847Svk199839 * context that was finalized in pk11_cipher_cleanup().
22960Sstevel@tonic-gate */
22977526SVladimir.Kotal@Sun.COM if (sp->opdata_cipher_key != CK_INVALID_HANDLE &&
22987526SVladimir.Kotal@Sun.COM sp->opdata_encrypt == ctx->encrypt)
22990Sstevel@tonic-gate {
23000Sstevel@tonic-gate state->sp = sp;
23017211Sjp161948 if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
23026847Svk199839 return (0);
23036847Svk199839
23046847Svk199839 return (1);
23050Sstevel@tonic-gate }
23060Sstevel@tonic-gate
23077616SVladimir.Kotal@Sun.COM /*
23087616SVladimir.Kotal@Sun.COM * Check if the key has been invalidated. If so, a new key object
23090Sstevel@tonic-gate * needs to be created.
23100Sstevel@tonic-gate */
23117526SVladimir.Kotal@Sun.COM if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
23120Sstevel@tonic-gate {
23137526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key = pk11_get_cipher_key(
23147211Sjp161948 ctx, key, p_ciph_table_row->key_type, sp);
23150Sstevel@tonic-gate }
23160Sstevel@tonic-gate
23177526SVladimir.Kotal@Sun.COM if (sp->opdata_encrypt != ctx->encrypt && sp->opdata_encrypt != -1)
23180Sstevel@tonic-gate {
23197616SVladimir.Kotal@Sun.COM /*
23207616SVladimir.Kotal@Sun.COM * The previous encryption/decryption is different. Need to
23217616SVladimir.Kotal@Sun.COM * terminate the previous * active encryption/decryption here.
23220Sstevel@tonic-gate */
23230Sstevel@tonic-gate if (!pk11_cipher_final(sp))
23240Sstevel@tonic-gate {
23257211Sjp161948 pk11_return_session(sp, OP_CIPHER);
23267616SVladimir.Kotal@Sun.COM return (0);
23270Sstevel@tonic-gate }
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate
23307526SVladimir.Kotal@Sun.COM if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
23310Sstevel@tonic-gate {
23327211Sjp161948 pk11_return_session(sp, OP_CIPHER);
23337616SVladimir.Kotal@Sun.COM return (0);
23340Sstevel@tonic-gate }
23350Sstevel@tonic-gate
23366847Svk199839 /* now initialize the context with a new key */
23377211Sjp161948 if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
23386847Svk199839 return (0);
23390Sstevel@tonic-gate
23407526SVladimir.Kotal@Sun.COM sp->opdata_encrypt = ctx->encrypt;
23410Sstevel@tonic-gate state->sp = sp;
23420Sstevel@tonic-gate
23437616SVladimir.Kotal@Sun.COM return (1);
23440Sstevel@tonic-gate }
23450Sstevel@tonic-gate
23467616SVladimir.Kotal@Sun.COM /*
23477616SVladimir.Kotal@Sun.COM * When reusing the same key in an encryption/decryption session for a
23480Sstevel@tonic-gate * decryption/encryption session, we need to close the active session
23490Sstevel@tonic-gate * and recreate a new one. Note that the key is in the global session so
23500Sstevel@tonic-gate * that it needs not be recreated.
23510Sstevel@tonic-gate *
23520Sstevel@tonic-gate * It is more appropriate to use C_En/DecryptFinish here. At the time of this
23530Sstevel@tonic-gate * development, these two functions in the PKCS#11 libraries used return
23540Sstevel@tonic-gate * unexpected errors when passing in 0 length output. It may be a good
23550Sstevel@tonic-gate * idea to try them again if performance is a problem here and fix
23560Sstevel@tonic-gate * C_En/DecryptFinial if there are bugs there causing the problem.
23570Sstevel@tonic-gate */
23580Sstevel@tonic-gate static int
pk11_cipher_final(PK11_SESSION * sp)23590Sstevel@tonic-gate pk11_cipher_final(PK11_SESSION *sp)
23600Sstevel@tonic-gate {
23610Sstevel@tonic-gate CK_RV rv;
23620Sstevel@tonic-gate
23637526SVladimir.Kotal@Sun.COM rv = pFuncList->C_CloseSession(sp->session);
23640Sstevel@tonic-gate if (rv != CKR_OK)
23650Sstevel@tonic-gate {
23667211Sjp161948 PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_CLOSESESSION, rv);
23677616SVladimir.Kotal@Sun.COM return (0);
23680Sstevel@tonic-gate }
23690Sstevel@tonic-gate
23700Sstevel@tonic-gate rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
23717526SVladimir.Kotal@Sun.COM NULL_PTR, NULL_PTR, &sp->session);
23720Sstevel@tonic-gate if (rv != CKR_OK)
23730Sstevel@tonic-gate {
23747211Sjp161948 PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_OPENSESSION, rv);
23757616SVladimir.Kotal@Sun.COM return (0);
23760Sstevel@tonic-gate }
23770Sstevel@tonic-gate
23787616SVladimir.Kotal@Sun.COM return (1);
23790Sstevel@tonic-gate }
23800Sstevel@tonic-gate
23817616SVladimir.Kotal@Sun.COM /*
23827616SVladimir.Kotal@Sun.COM * An engine interface function. The calling function allocates sufficient
23837616SVladimir.Kotal@Sun.COM * memory for the output buffer "out" to hold the results.
23847616SVladimir.Kotal@Sun.COM */
23850Sstevel@tonic-gate static int
pk11_cipher_do_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,unsigned int inl)23860Sstevel@tonic-gate pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
23870Sstevel@tonic-gate const unsigned char *in, unsigned int inl)
23880Sstevel@tonic-gate {
23890Sstevel@tonic-gate PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
23900Sstevel@tonic-gate PK11_SESSION *sp;
23910Sstevel@tonic-gate CK_RV rv;
23920Sstevel@tonic-gate unsigned long outl = inl;
23930Sstevel@tonic-gate
23940Sstevel@tonic-gate if (state == NULL || state->sp == NULL)
23957616SVladimir.Kotal@Sun.COM return (0);
23960Sstevel@tonic-gate
23970Sstevel@tonic-gate sp = (PK11_SESSION *) state->sp;
23980Sstevel@tonic-gate
23990Sstevel@tonic-gate if (!inl)
24007616SVladimir.Kotal@Sun.COM return (1);
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate /* RC4 is the only stream cipher we support */
24030Sstevel@tonic-gate if (ctx->cipher->nid != NID_rc4 && (inl % ctx->cipher->block_size) != 0)
24047616SVladimir.Kotal@Sun.COM return (0);
24050Sstevel@tonic-gate
24060Sstevel@tonic-gate if (ctx->encrypt)
24070Sstevel@tonic-gate {
24087526SVladimir.Kotal@Sun.COM rv = pFuncList->C_EncryptUpdate(sp->session,
24090Sstevel@tonic-gate (unsigned char *)in, inl, out, &outl);
24100Sstevel@tonic-gate
24110Sstevel@tonic-gate if (rv != CKR_OK)
24120Sstevel@tonic-gate {
24137616SVladimir.Kotal@Sun.COM PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
24147211Sjp161948 PK11_R_ENCRYPTUPDATE, rv);
24157616SVladimir.Kotal@Sun.COM return (0);
24160Sstevel@tonic-gate }
24170Sstevel@tonic-gate }
24180Sstevel@tonic-gate else
24190Sstevel@tonic-gate {
24207526SVladimir.Kotal@Sun.COM rv = pFuncList->C_DecryptUpdate(sp->session,
24210Sstevel@tonic-gate (unsigned char *)in, inl, out, &outl);
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate if (rv != CKR_OK)
24240Sstevel@tonic-gate {
24257211Sjp161948 PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
24267211Sjp161948 PK11_R_DECRYPTUPDATE, rv);
24277616SVladimir.Kotal@Sun.COM return (0);
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate }
24300Sstevel@tonic-gate
24317616SVladimir.Kotal@Sun.COM /*
24327616SVladimir.Kotal@Sun.COM * For DES_CBC, DES3_CBC, AES_CBC, and RC4, the output size is always
24337616SVladimir.Kotal@Sun.COM * the same size of input.
24347616SVladimir.Kotal@Sun.COM * The application has guaranteed to call the block ciphers with
24350Sstevel@tonic-gate * correctly aligned buffers.
24360Sstevel@tonic-gate */
24370Sstevel@tonic-gate if (inl != outl)
24387616SVladimir.Kotal@Sun.COM return (0);
24397616SVladimir.Kotal@Sun.COM
24407616SVladimir.Kotal@Sun.COM return (1);
24410Sstevel@tonic-gate }
24420Sstevel@tonic-gate
24436847Svk199839 /*
24447211Sjp161948 * Return the session to the pool. Calling C_EncryptFinal() and C_DecryptFinal()
24457211Sjp161948 * here is the right thing because in EVP_DecryptFinal_ex(), engine's
24467211Sjp161948 * do_cipher() is not even called, and in EVP_EncryptFinal_ex() it is called but
24477211Sjp161948 * the engine can't find out that it's the finalizing call. We wouldn't
24487211Sjp161948 * necessarily have to finalize the context here since reinitializing it with
24497211Sjp161948 * C_(Encrypt|Decrypt)Init() should be fine but for the sake of correctness,
24507211Sjp161948 * let's do it. Some implementations might leak memory if the previously used
24517211Sjp161948 * context is initialized without finalizing it first.
24520Sstevel@tonic-gate */
24530Sstevel@tonic-gate static int
pk11_cipher_cleanup(EVP_CIPHER_CTX * ctx)24540Sstevel@tonic-gate pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx)
24550Sstevel@tonic-gate {
24566847Svk199839 CK_RV rv;
24577211Sjp161948 CK_ULONG len = EVP_MAX_BLOCK_LENGTH;
24586847Svk199839 CK_BYTE buf[EVP_MAX_BLOCK_LENGTH];
24590Sstevel@tonic-gate PK11_CIPHER_STATE *state = ctx->cipher_data;
24600Sstevel@tonic-gate
24610Sstevel@tonic-gate if (state != NULL && state->sp != NULL)
24620Sstevel@tonic-gate {
24636847Svk199839 /*
24646847Svk199839 * We are not interested in the data here, we just need to get
24656847Svk199839 * rid of the context.
24666847Svk199839 */
24676847Svk199839 if (ctx->encrypt)
24686847Svk199839 rv = pFuncList->C_EncryptFinal(
24697526SVladimir.Kotal@Sun.COM state->sp->session, buf, &len);
24706847Svk199839 else
24716847Svk199839 rv = pFuncList->C_DecryptFinal(
24727526SVladimir.Kotal@Sun.COM state->sp->session, buf, &len);
24736847Svk199839
24746847Svk199839 if (rv != CKR_OK)
24756847Svk199839 {
24767211Sjp161948 PK11err_add_data(PK11_F_CIPHER_CLEANUP, ctx->encrypt ?
24777211Sjp161948 PK11_R_ENCRYPTFINAL : PK11_R_DECRYPTFINAL, rv);
24787211Sjp161948 pk11_return_session(state->sp, OP_CIPHER);
24796847Svk199839 return (0);
24806847Svk199839 }
24816847Svk199839
24827211Sjp161948 pk11_return_session(state->sp, OP_CIPHER);
24830Sstevel@tonic-gate state->sp = NULL;
24840Sstevel@tonic-gate }
24850Sstevel@tonic-gate
24866847Svk199839 return (1);
24876847Svk199839 }
24886847Svk199839
24897616SVladimir.Kotal@Sun.COM /*
24907616SVladimir.Kotal@Sun.COM * Registered by the ENGINE when used to find out how to deal with
24910Sstevel@tonic-gate * a particular NID in the ENGINE. This says what we'll do at the
24920Sstevel@tonic-gate * top level - note, that list is restricted by what we answer with
24930Sstevel@tonic-gate */
24947534SVladimir.Kotal@Sun.COM /* ARGSUSED */
24950Sstevel@tonic-gate static int
pk11_engine_ciphers(ENGINE * e,const EVP_CIPHER ** cipher,const int ** nids,int nid)24960Sstevel@tonic-gate pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
24970Sstevel@tonic-gate const int **nids, int nid)
24980Sstevel@tonic-gate {
24990Sstevel@tonic-gate if (!cipher)
25000Sstevel@tonic-gate return (pk11_usable_ciphers(nids));
25010Sstevel@tonic-gate
25020Sstevel@tonic-gate switch (nid)
25030Sstevel@tonic-gate {
25040Sstevel@tonic-gate case NID_des_ede3_cbc:
25050Sstevel@tonic-gate *cipher = &pk11_3des_cbc;
25060Sstevel@tonic-gate break;
25070Sstevel@tonic-gate case NID_des_cbc:
25080Sstevel@tonic-gate *cipher = &pk11_des_cbc;
25090Sstevel@tonic-gate break;
25107211Sjp161948 case NID_des_ede3_ecb:
25117211Sjp161948 *cipher = &pk11_3des_ecb;
25127211Sjp161948 break;
25137211Sjp161948 case NID_des_ecb:
25147211Sjp161948 *cipher = &pk11_des_ecb;
25157211Sjp161948 break;
25160Sstevel@tonic-gate case NID_aes_128_cbc:
25177211Sjp161948 *cipher = &pk11_aes_128_cbc;
25187211Sjp161948 break;
25197211Sjp161948 case NID_aes_192_cbc:
25207211Sjp161948 *cipher = &pk11_aes_192_cbc;
25217211Sjp161948 break;
25227211Sjp161948 case NID_aes_256_cbc:
25237211Sjp161948 *cipher = &pk11_aes_256_cbc;
25247211Sjp161948 break;
25257211Sjp161948 case NID_aes_128_ecb:
25267211Sjp161948 *cipher = &pk11_aes_128_ecb;
25277211Sjp161948 break;
25287211Sjp161948 case NID_aes_192_ecb:
25297211Sjp161948 *cipher = &pk11_aes_192_ecb;
25307211Sjp161948 break;
25317211Sjp161948 case NID_aes_256_ecb:
25327211Sjp161948 *cipher = &pk11_aes_256_ecb;
25337211Sjp161948 break;
25347211Sjp161948 case NID_bf_cbc:
25357211Sjp161948 *cipher = &pk11_bf_cbc;
25360Sstevel@tonic-gate break;
25370Sstevel@tonic-gate case NID_rc4:
25380Sstevel@tonic-gate *cipher = &pk11_rc4;
25390Sstevel@tonic-gate break;
25400Sstevel@tonic-gate default:
25417211Sjp161948 #ifdef SOLARIS_AES_CTR
25427211Sjp161948 /*
25437211Sjp161948 * These can't be in separated cases because the NIDs
25447211Sjp161948 * here are not constants.
25457211Sjp161948 */
25467211Sjp161948 if (nid == NID_aes_128_ctr)
25477211Sjp161948 *cipher = &pk11_aes_128_ctr;
25487211Sjp161948 else if (nid == NID_aes_192_ctr)
25497211Sjp161948 *cipher = &pk11_aes_192_ctr;
25507211Sjp161948 else if (nid == NID_aes_256_ctr)
25517211Sjp161948 *cipher = &pk11_aes_256_ctr;
25527211Sjp161948 else
25537211Sjp161948 #endif /* SOLARIS_AES_CTR */
25540Sstevel@tonic-gate *cipher = NULL;
25550Sstevel@tonic-gate break;
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate return (*cipher != NULL);
25580Sstevel@tonic-gate }
25590Sstevel@tonic-gate
25607534SVladimir.Kotal@Sun.COM /* ARGSUSED */
25610Sstevel@tonic-gate static int
pk11_engine_digests(ENGINE * e,const EVP_MD ** digest,const int ** nids,int nid)25620Sstevel@tonic-gate pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
25630Sstevel@tonic-gate const int **nids, int nid)
25640Sstevel@tonic-gate {
25650Sstevel@tonic-gate if (!digest)
25660Sstevel@tonic-gate return (pk11_usable_digests(nids));
25670Sstevel@tonic-gate
25680Sstevel@tonic-gate switch (nid)
25690Sstevel@tonic-gate {
25700Sstevel@tonic-gate case NID_md5:
25717616SVladimir.Kotal@Sun.COM *digest = &pk11_md5;
25720Sstevel@tonic-gate break;
25730Sstevel@tonic-gate case NID_sha1:
25747616SVladimir.Kotal@Sun.COM *digest = &pk11_sha1;
25750Sstevel@tonic-gate break;
25767211Sjp161948 case NID_sha224:
25777616SVladimir.Kotal@Sun.COM *digest = &pk11_sha224;
25787211Sjp161948 break;
25797211Sjp161948 case NID_sha256:
25807616SVladimir.Kotal@Sun.COM *digest = &pk11_sha256;
25817211Sjp161948 break;
25827211Sjp161948 case NID_sha384:
25837616SVladimir.Kotal@Sun.COM *digest = &pk11_sha384;
25847211Sjp161948 break;
25857211Sjp161948 case NID_sha512:
25867616SVladimir.Kotal@Sun.COM *digest = &pk11_sha512;
25877211Sjp161948 break;
25880Sstevel@tonic-gate default:
25890Sstevel@tonic-gate *digest = NULL;
25900Sstevel@tonic-gate break;
25910Sstevel@tonic-gate }
25920Sstevel@tonic-gate return (*digest != NULL);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25950Sstevel@tonic-gate
25967616SVladimir.Kotal@Sun.COM /* Create a secret key object in a PKCS#11 session */
pk11_get_cipher_key(EVP_CIPHER_CTX * ctx,const unsigned char * key,CK_KEY_TYPE key_type,PK11_SESSION * sp)25977616SVladimir.Kotal@Sun.COM static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
25980Sstevel@tonic-gate const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp)
25990Sstevel@tonic-gate {
26000Sstevel@tonic-gate CK_RV rv;
26010Sstevel@tonic-gate CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
26020Sstevel@tonic-gate CK_OBJECT_CLASS obj_key = CKO_SECRET_KEY;
26030Sstevel@tonic-gate CK_ULONG ul_key_attr_count = 6;
26040Sstevel@tonic-gate
26050Sstevel@tonic-gate CK_ATTRIBUTE a_key_template[] =
26060Sstevel@tonic-gate {
26077616SVladimir.Kotal@Sun.COM {CKA_CLASS, (void*) NULL, sizeof (CK_OBJECT_CLASS)},
26087616SVladimir.Kotal@Sun.COM {CKA_KEY_TYPE, (void*) NULL, sizeof (CK_KEY_TYPE)},
26097616SVladimir.Kotal@Sun.COM {CKA_TOKEN, &false, sizeof (false)},
26107616SVladimir.Kotal@Sun.COM {CKA_ENCRYPT, &true, sizeof (true)},
26117616SVladimir.Kotal@Sun.COM {CKA_DECRYPT, &true, sizeof (true)},
26120Sstevel@tonic-gate {CKA_VALUE, (void*) NULL, 0},
26130Sstevel@tonic-gate };
26140Sstevel@tonic-gate
26157616SVladimir.Kotal@Sun.COM /*
26167616SVladimir.Kotal@Sun.COM * Create secret key object in global_session. All other sessions
26170Sstevel@tonic-gate * can use the key handles. Here is why:
26180Sstevel@tonic-gate * OpenSSL will call EncryptInit and EncryptUpdate using a secret key.
26190Sstevel@tonic-gate * It may then call DecryptInit and DecryptUpdate using the same key.
26200Sstevel@tonic-gate * To use the same key object, we need to call EncryptFinal with
26217616SVladimir.Kotal@Sun.COM * a 0 length message. Currently, this does not work for 3DES
26220Sstevel@tonic-gate * mechanism. To get around this problem, we close the session and
26230Sstevel@tonic-gate * then create a new session to use the same key object. When a session
26247616SVladimir.Kotal@Sun.COM * is closed, all the object handles will be invalid. Thus, create key
26250Sstevel@tonic-gate * objects in a global session, an individual session may be closed to
26260Sstevel@tonic-gate * terminate the active operation.
26270Sstevel@tonic-gate */
26280Sstevel@tonic-gate CK_SESSION_HANDLE session = global_session;
26290Sstevel@tonic-gate a_key_template[0].pValue = &obj_key;
26300Sstevel@tonic-gate a_key_template[1].pValue = &key_type;
26310Sstevel@tonic-gate a_key_template[5].pValue = (void *) key;
26320Sstevel@tonic-gate a_key_template[5].ulValueLen = (unsigned long) ctx->key_len;
26330Sstevel@tonic-gate
26347616SVladimir.Kotal@Sun.COM rv = pFuncList->C_CreateObject(session,
26354602Sjp161948 a_key_template, ul_key_attr_count, &h_key);
26360Sstevel@tonic-gate if (rv != CKR_OK)
26370Sstevel@tonic-gate {
26387211Sjp161948 PK11err_add_data(PK11_F_GET_CIPHER_KEY, PK11_R_CREATEOBJECT,
26397211Sjp161948 rv);
26400Sstevel@tonic-gate goto err;
26410Sstevel@tonic-gate }
26420Sstevel@tonic-gate
26437616SVladimir.Kotal@Sun.COM /*
26447616SVladimir.Kotal@Sun.COM * Save the key information used in this session.
26450Sstevel@tonic-gate * The max can be saved is PK11_KEY_LEN_MAX.
26460Sstevel@tonic-gate */
26477526SVladimir.Kotal@Sun.COM sp->opdata_key_len = ctx->key_len > PK11_KEY_LEN_MAX ?
26480Sstevel@tonic-gate PK11_KEY_LEN_MAX : ctx->key_len;
26497534SVladimir.Kotal@Sun.COM (void) memcpy(sp->opdata_key, key, sp->opdata_key_len);
26500Sstevel@tonic-gate err:
26510Sstevel@tonic-gate
26527616SVladimir.Kotal@Sun.COM return (h_key);
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate
26550Sstevel@tonic-gate static int
md_nid_to_pk11(int nid)26560Sstevel@tonic-gate md_nid_to_pk11(int nid)
26570Sstevel@tonic-gate {
26580Sstevel@tonic-gate int i;
26590Sstevel@tonic-gate
26600Sstevel@tonic-gate for (i = 0; i < PK11_DIGEST_MAX; i++)
26610Sstevel@tonic-gate if (digests[i].nid == nid)
26620Sstevel@tonic-gate return (digests[i].id);
26630Sstevel@tonic-gate return (-1);
26640Sstevel@tonic-gate }
26650Sstevel@tonic-gate
26667616SVladimir.Kotal@Sun.COM static int
pk11_digest_init(EVP_MD_CTX * ctx)26670Sstevel@tonic-gate pk11_digest_init(EVP_MD_CTX *ctx)
26687616SVladimir.Kotal@Sun.COM {
26690Sstevel@tonic-gate CK_RV rv;
26704320Sjp161948 CK_MECHANISM mech;
26710Sstevel@tonic-gate int index;
26720Sstevel@tonic-gate PK11_SESSION *sp;
26730Sstevel@tonic-gate PK11_DIGEST *pdp;
26740Sstevel@tonic-gate PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
26757616SVladimir.Kotal@Sun.COM
26760Sstevel@tonic-gate state->sp = NULL;
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate index = md_nid_to_pk11(ctx->digest->type);
26790Sstevel@tonic-gate if (index < 0 || index >= PK11_DIGEST_MAX)
26807616SVladimir.Kotal@Sun.COM return (0);
26810Sstevel@tonic-gate
26820Sstevel@tonic-gate pdp = &digests[index];
26837211Sjp161948 if ((sp = pk11_get_session(OP_DIGEST)) == NULL)
26847616SVladimir.Kotal@Sun.COM return (0);
26850Sstevel@tonic-gate
26864320Sjp161948 /* at present, no parameter is needed for supported digests */
26874320Sjp161948 mech.mechanism = pdp->mech_type;
26884320Sjp161948 mech.pParameter = NULL;
26894320Sjp161948 mech.ulParameterLen = 0;
26904320Sjp161948
26914320Sjp161948 rv = pFuncList->C_DigestInit(sp->session, &mech);
26920Sstevel@tonic-gate
26930Sstevel@tonic-gate if (rv != CKR_OK)
26940Sstevel@tonic-gate {
26957211Sjp161948 PK11err_add_data(PK11_F_DIGEST_INIT, PK11_R_DIGESTINIT, rv);
26967211Sjp161948 pk11_return_session(sp, OP_DIGEST);
26977616SVladimir.Kotal@Sun.COM return (0);
26980Sstevel@tonic-gate }
26990Sstevel@tonic-gate
27000Sstevel@tonic-gate state->sp = sp;
27010Sstevel@tonic-gate
27027616SVladimir.Kotal@Sun.COM return (1);
27030Sstevel@tonic-gate }
27040Sstevel@tonic-gate
27057616SVladimir.Kotal@Sun.COM static int
pk11_digest_update(EVP_MD_CTX * ctx,const void * data,size_t count)27067616SVladimir.Kotal@Sun.COM pk11_digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
27077616SVladimir.Kotal@Sun.COM {
27080Sstevel@tonic-gate CK_RV rv;
27090Sstevel@tonic-gate PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
27107616SVladimir.Kotal@Sun.COM
27110Sstevel@tonic-gate /* 0 length message will cause a failure in C_DigestFinal */
27120Sstevel@tonic-gate if (count == 0)
27137616SVladimir.Kotal@Sun.COM return (1);
27140Sstevel@tonic-gate
27150Sstevel@tonic-gate if (state == NULL || state->sp == NULL)
27167616SVladimir.Kotal@Sun.COM return (0);
27170Sstevel@tonic-gate
27180Sstevel@tonic-gate rv = pFuncList->C_DigestUpdate(state->sp->session, (CK_BYTE *) data,
27190Sstevel@tonic-gate count);
27200Sstevel@tonic-gate
27210Sstevel@tonic-gate if (rv != CKR_OK)
27220Sstevel@tonic-gate {
27237211Sjp161948 PK11err_add_data(PK11_F_DIGEST_UPDATE, PK11_R_DIGESTUPDATE, rv);
27247211Sjp161948 pk11_return_session(state->sp, OP_DIGEST);
27250Sstevel@tonic-gate state->sp = NULL;
27267616SVladimir.Kotal@Sun.COM return (0);
27270Sstevel@tonic-gate }
27280Sstevel@tonic-gate
27297616SVladimir.Kotal@Sun.COM return (1);
27300Sstevel@tonic-gate }
27310Sstevel@tonic-gate
27327616SVladimir.Kotal@Sun.COM static int
pk11_digest_final(EVP_MD_CTX * ctx,unsigned char * md)27337616SVladimir.Kotal@Sun.COM pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
27347616SVladimir.Kotal@Sun.COM {
27350Sstevel@tonic-gate CK_RV rv;
27360Sstevel@tonic-gate unsigned long len;
27370Sstevel@tonic-gate PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
27380Sstevel@tonic-gate len = ctx->digest->md_size;
27397616SVladimir.Kotal@Sun.COM
27400Sstevel@tonic-gate if (state == NULL || state->sp == NULL)
27417616SVladimir.Kotal@Sun.COM return (0);
27420Sstevel@tonic-gate
27430Sstevel@tonic-gate rv = pFuncList->C_DigestFinal(state->sp->session, md, &len);
27440Sstevel@tonic-gate
27450Sstevel@tonic-gate if (rv != CKR_OK)
27460Sstevel@tonic-gate {
27477211Sjp161948 PK11err_add_data(PK11_F_DIGEST_FINAL, PK11_R_DIGESTFINAL, rv);
27487211Sjp161948 pk11_return_session(state->sp, OP_DIGEST);
27490Sstevel@tonic-gate state->sp = NULL;
27507616SVladimir.Kotal@Sun.COM return (0);
27510Sstevel@tonic-gate }
27520Sstevel@tonic-gate
27530Sstevel@tonic-gate if (ctx->digest->md_size != len)
27547616SVladimir.Kotal@Sun.COM return (0);
27557616SVladimir.Kotal@Sun.COM
27567616SVladimir.Kotal@Sun.COM /*
27577616SVladimir.Kotal@Sun.COM * Final is called and digest is returned, so return the session
27580Sstevel@tonic-gate * to the pool
27590Sstevel@tonic-gate */
27607211Sjp161948 pk11_return_session(state->sp, OP_DIGEST);
27610Sstevel@tonic-gate state->sp = NULL;
27620Sstevel@tonic-gate
27637616SVladimir.Kotal@Sun.COM return (1);
27640Sstevel@tonic-gate }
27650Sstevel@tonic-gate
27667616SVladimir.Kotal@Sun.COM static int
pk11_digest_copy(EVP_MD_CTX * to,const EVP_MD_CTX * from)27677616SVladimir.Kotal@Sun.COM pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
27687616SVladimir.Kotal@Sun.COM {
27690Sstevel@tonic-gate CK_RV rv;
27700Sstevel@tonic-gate int ret = 0;
27710Sstevel@tonic-gate PK11_CIPHER_STATE *state, *state_to;
27720Sstevel@tonic-gate CK_BYTE_PTR pstate = NULL;
27730Sstevel@tonic-gate CK_ULONG ul_state_len;
27747616SVladimir.Kotal@Sun.COM
27750Sstevel@tonic-gate /* The copy-from state */
27760Sstevel@tonic-gate state = (PK11_CIPHER_STATE *) from->md_data;
27770Sstevel@tonic-gate if (state == NULL || state->sp == NULL)
27780Sstevel@tonic-gate goto err;
27790Sstevel@tonic-gate
27800Sstevel@tonic-gate /* Initialize the copy-to state */
27810Sstevel@tonic-gate if (!pk11_digest_init(to))
27820Sstevel@tonic-gate goto err;
27830Sstevel@tonic-gate state_to = (PK11_CIPHER_STATE *) to->md_data;
27840Sstevel@tonic-gate
27850Sstevel@tonic-gate /* Get the size of the operation state of the copy-from session */
27867616SVladimir.Kotal@Sun.COM rv = pFuncList->C_GetOperationState(state->sp->session, NULL,
27870Sstevel@tonic-gate &ul_state_len);
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate if (rv != CKR_OK)
27900Sstevel@tonic-gate {
27917211Sjp161948 PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
27927211Sjp161948 rv);
27930Sstevel@tonic-gate goto err;
27940Sstevel@tonic-gate }
27950Sstevel@tonic-gate if (ul_state_len == 0)
27960Sstevel@tonic-gate {
27970Sstevel@tonic-gate goto err;
27980Sstevel@tonic-gate }
27990Sstevel@tonic-gate
28000Sstevel@tonic-gate pstate = OPENSSL_malloc(ul_state_len);
28010Sstevel@tonic-gate if (pstate == NULL)
28020Sstevel@tonic-gate {
28036847Svk199839 PK11err(PK11_F_DIGEST_COPY, PK11_R_MALLOC_FAILURE);
28040Sstevel@tonic-gate goto err;
28050Sstevel@tonic-gate }
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate /* Get the operation state of the copy-from session */
28087616SVladimir.Kotal@Sun.COM rv = pFuncList->C_GetOperationState(state->sp->session, pstate,
28090Sstevel@tonic-gate &ul_state_len);
28100Sstevel@tonic-gate
28110Sstevel@tonic-gate if (rv != CKR_OK)
28120Sstevel@tonic-gate {
28137211Sjp161948 PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
28147211Sjp161948 rv);
28150Sstevel@tonic-gate goto err;
28160Sstevel@tonic-gate }
28170Sstevel@tonic-gate
28180Sstevel@tonic-gate /* Set the operation state of the copy-to session */
28197616SVladimir.Kotal@Sun.COM rv = pFuncList->C_SetOperationState(state_to->sp->session, pstate,
28200Sstevel@tonic-gate ul_state_len, 0, 0);
28210Sstevel@tonic-gate
28220Sstevel@tonic-gate if (rv != CKR_OK)
28230Sstevel@tonic-gate {
28247616SVladimir.Kotal@Sun.COM PK11err_add_data(PK11_F_DIGEST_COPY,
28257616SVladimir.Kotal@Sun.COM PK11_R_SET_OPERATION_STATE, rv);
28260Sstevel@tonic-gate goto err;
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate
28290Sstevel@tonic-gate ret = 1;
28300Sstevel@tonic-gate err:
28310Sstevel@tonic-gate if (pstate != NULL)
28320Sstevel@tonic-gate OPENSSL_free(pstate);
28330Sstevel@tonic-gate
28347616SVladimir.Kotal@Sun.COM return (ret);
28350Sstevel@tonic-gate }
28360Sstevel@tonic-gate
28370Sstevel@tonic-gate /* Return any pending session state to the pool */
28380Sstevel@tonic-gate static int
pk11_digest_cleanup(EVP_MD_CTX * ctx)28390Sstevel@tonic-gate pk11_digest_cleanup(EVP_MD_CTX *ctx)
28400Sstevel@tonic-gate {
28410Sstevel@tonic-gate PK11_CIPHER_STATE *state = ctx->md_data;
28424602Sjp161948 unsigned char buf[EVP_MAX_MD_SIZE];
28430Sstevel@tonic-gate
28440Sstevel@tonic-gate if (state != NULL && state->sp != NULL)
28450Sstevel@tonic-gate {
28464602Sjp161948 /*
28474602Sjp161948 * If state->sp is not NULL then pk11_digest_final() has not
28484602Sjp161948 * been called yet. We must call it now to free any memory
28494602Sjp161948 * that might have been allocated in the token when
28507628SVladimir.Kotal@Sun.COM * pk11_digest_init() was called. pk11_digest_final()
28517628SVladimir.Kotal@Sun.COM * will return the session to the cache.
28524602Sjp161948 */
28537628SVladimir.Kotal@Sun.COM if (!pk11_digest_final(ctx, buf))
28547628SVladimir.Kotal@Sun.COM return (0);
28550Sstevel@tonic-gate }
28560Sstevel@tonic-gate
28577616SVladimir.Kotal@Sun.COM return (1);
28580Sstevel@tonic-gate }
28590Sstevel@tonic-gate
28606847Svk199839 /*
28617211Sjp161948 * Check if the new key is the same as the key object in the session. If the key
28627211Sjp161948 * is the same, no need to create a new key object. Otherwise, the old key
28637211Sjp161948 * object needs to be destroyed and a new one will be created. Return 1 for
28647211Sjp161948 * cache hit, 0 for cache miss. Note that we must check the key length first
28657211Sjp161948 * otherwise we could end up reusing a different, longer key with the same
28667211Sjp161948 * prefix.
28670Sstevel@tonic-gate */
check_new_cipher_key(PK11_SESSION * sp,const unsigned char * key,int key_len)28687211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
28697211Sjp161948 int key_len)
28700Sstevel@tonic-gate {
28717526SVladimir.Kotal@Sun.COM if (sp->opdata_key_len != key_len ||
28727526SVladimir.Kotal@Sun.COM memcmp(sp->opdata_key, key, key_len) != 0)
28736847Svk199839 {
28747211Sjp161948 (void) pk11_destroy_cipher_key_objects(sp);
28756847Svk199839 return (0);
28766847Svk199839 }
28776847Svk199839 return (1);
28780Sstevel@tonic-gate }
28790Sstevel@tonic-gate
28807616SVladimir.Kotal@Sun.COM /* Destroy one or more secret key objects. */
pk11_destroy_cipher_key_objects(PK11_SESSION * session)28810Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session)
28820Sstevel@tonic-gate {
28830Sstevel@tonic-gate int ret = 0;
28840Sstevel@tonic-gate PK11_SESSION *sp = NULL;
28850Sstevel@tonic-gate PK11_SESSION *local_free_session;
28860Sstevel@tonic-gate
28877526SVladimir.Kotal@Sun.COM if (session != NULL)
28880Sstevel@tonic-gate local_free_session = session;
28890Sstevel@tonic-gate else
28907526SVladimir.Kotal@Sun.COM {
28917526SVladimir.Kotal@Sun.COM (void) pthread_mutex_lock(session_cache[OP_CIPHER].lock);
28927526SVladimir.Kotal@Sun.COM local_free_session = session_cache[OP_CIPHER].head;
28937526SVladimir.Kotal@Sun.COM }
28947526SVladimir.Kotal@Sun.COM
28950Sstevel@tonic-gate while ((sp = local_free_session) != NULL)
28960Sstevel@tonic-gate {
28970Sstevel@tonic-gate local_free_session = sp->next;
28980Sstevel@tonic-gate
28997526SVladimir.Kotal@Sun.COM if (sp->opdata_cipher_key != CK_INVALID_HANDLE)
29000Sstevel@tonic-gate {
29017616SVladimir.Kotal@Sun.COM /*
29027616SVladimir.Kotal@Sun.COM * The secret key object is created in the
29030Sstevel@tonic-gate * global_session. See pk11_get_cipher_key
29040Sstevel@tonic-gate */
29057616SVladimir.Kotal@Sun.COM if (pk11_destroy_object(global_session,
29067526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key) == 0)
29070Sstevel@tonic-gate goto err;
29087526SVladimir.Kotal@Sun.COM sp->opdata_cipher_key = CK_INVALID_HANDLE;
29090Sstevel@tonic-gate }
29100Sstevel@tonic-gate }
29110Sstevel@tonic-gate ret = 1;
29120Sstevel@tonic-gate err:
29137526SVladimir.Kotal@Sun.COM
29147526SVladimir.Kotal@Sun.COM if (session == NULL)
29157526SVladimir.Kotal@Sun.COM (void) pthread_mutex_unlock(session_cache[OP_CIPHER].lock);
29160Sstevel@tonic-gate
29177616SVladimir.Kotal@Sun.COM return (ret);
29180Sstevel@tonic-gate }
29190Sstevel@tonic-gate
29200Sstevel@tonic-gate
29210Sstevel@tonic-gate /*
29227211Sjp161948 * Public key mechanisms optionally supported
29230Sstevel@tonic-gate *
29240Sstevel@tonic-gate * CKM_RSA_X_509
29250Sstevel@tonic-gate * CKM_RSA_PKCS
29260Sstevel@tonic-gate * CKM_DSA
29270Sstevel@tonic-gate *
29287211Sjp161948 * The first slot that supports at least one of those mechanisms is chosen as a
29297211Sjp161948 * public key slot.
29300Sstevel@tonic-gate *
29310Sstevel@tonic-gate * Symmetric ciphers optionally supported
29320Sstevel@tonic-gate *
29330Sstevel@tonic-gate * CKM_DES3_CBC
29340Sstevel@tonic-gate * CKM_DES_CBC
29350Sstevel@tonic-gate * CKM_AES_CBC
29367211Sjp161948 * CKM_DES3_ECB
29377211Sjp161948 * CKM_DES_ECB
29387211Sjp161948 * CKM_AES_ECB
29397211Sjp161948 * CKM_AES_CTR
29400Sstevel@tonic-gate * CKM_RC4
29417211Sjp161948 * CKM_BLOWFISH_CBC
29420Sstevel@tonic-gate *
29430Sstevel@tonic-gate * Digests optionally supported
29440Sstevel@tonic-gate *
29450Sstevel@tonic-gate * CKM_MD5
29460Sstevel@tonic-gate * CKM_SHA_1
29477211Sjp161948 * CKM_SHA224
29487211Sjp161948 * CKM_SHA256
29497211Sjp161948 * CKM_SHA384
29507211Sjp161948 * CKM_SHA512
29517211Sjp161948 *
29527211Sjp161948 * The output of this function is a set of global variables indicating which
29537211Sjp161948 * mechanisms from RSA, DSA, DH and RAND are present, and also two arrays of
29547211Sjp161948 * mechanisms, one for symmetric ciphers and one for digests. Also, 3 global
29557211Sjp161948 * variables carry information about which slot was chosen for (a) public key
29567211Sjp161948 * mechanisms, (b) random operations, and (c) symmetric ciphers and digests.
29570Sstevel@tonic-gate */
29587616SVladimir.Kotal@Sun.COM static int
pk11_choose_slots(int * any_slot_found)29597211Sjp161948 pk11_choose_slots(int *any_slot_found)
29600Sstevel@tonic-gate {
29610Sstevel@tonic-gate CK_SLOT_ID_PTR pSlotList = NULL_PTR;
29620Sstevel@tonic-gate CK_ULONG ulSlotCount = 0;
29630Sstevel@tonic-gate CK_MECHANISM_INFO mech_info;
29640Sstevel@tonic-gate CK_TOKEN_INFO token_info;
29650Sstevel@tonic-gate int i;
29660Sstevel@tonic-gate CK_RV rv;
29670Sstevel@tonic-gate CK_SLOT_ID best_slot_sofar;
29680Sstevel@tonic-gate CK_BBOOL found_candidate_slot = CK_FALSE;
29690Sstevel@tonic-gate int slot_n_cipher = 0;
29700Sstevel@tonic-gate int slot_n_digest = 0;
29710Sstevel@tonic-gate CK_SLOT_ID current_slot = 0;
29720Sstevel@tonic-gate int current_slot_n_cipher = 0;
29730Sstevel@tonic-gate int current_slot_n_digest = 0;
29740Sstevel@tonic-gate
29750Sstevel@tonic-gate int local_cipher_nids[PK11_CIPHER_MAX];
29760Sstevel@tonic-gate int local_digest_nids[PK11_DIGEST_MAX];
29777211Sjp161948
29787211Sjp161948 /* let's initialize the output parameter */
29797211Sjp161948 if (any_slot_found != NULL)
29807211Sjp161948 *any_slot_found = 0;
29817211Sjp161948
29827211Sjp161948 /* Get slot list for memory allocation */
29830Sstevel@tonic-gate rv = pFuncList->C_GetSlotList(0, NULL_PTR, &ulSlotCount);
29840Sstevel@tonic-gate
29850Sstevel@tonic-gate if (rv != CKR_OK)
29860Sstevel@tonic-gate {
29877211Sjp161948 PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
29887616SVladimir.Kotal@Sun.COM return (0);
29890Sstevel@tonic-gate }
29900Sstevel@tonic-gate
29917211Sjp161948 /* it's not an error if we didn't find any providers */
29927616SVladimir.Kotal@Sun.COM if (ulSlotCount == 0)
29930Sstevel@tonic-gate {
29947211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
29957211Sjp161948 fprintf(stderr, "%s: no crypto providers found\n", PK11_DBG);
29967211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
29977616SVladimir.Kotal@Sun.COM return (1);
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate
30000Sstevel@tonic-gate pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
30010Sstevel@tonic-gate
30027616SVladimir.Kotal@Sun.COM if (pSlotList == NULL)
30030Sstevel@tonic-gate {
30046847Svk199839 PK11err(PK11_F_CHOOSE_SLOT, PK11_R_MALLOC_FAILURE);
30057616SVladimir.Kotal@Sun.COM return (0);
30060Sstevel@tonic-gate }
30070Sstevel@tonic-gate
30080Sstevel@tonic-gate /* Get the slot list for processing */
30090Sstevel@tonic-gate rv = pFuncList->C_GetSlotList(0, pSlotList, &ulSlotCount);
30107616SVladimir.Kotal@Sun.COM if (rv != CKR_OK)
30110Sstevel@tonic-gate {
30127211Sjp161948 PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
30130Sstevel@tonic-gate OPENSSL_free(pSlotList);
30147616SVladimir.Kotal@Sun.COM return (0);
30150Sstevel@tonic-gate }
30160Sstevel@tonic-gate
30177211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30187211Sjp161948 fprintf(stderr, "%s: provider: %s\n", PK11_DBG, def_PK11_LIBNAME);
30197211Sjp161948 fprintf(stderr, "%s: number of slots: %d\n", PK11_DBG, ulSlotCount);
30207211Sjp161948
30217211Sjp161948 fprintf(stderr, "%s: == checking rand slots ==\n", PK11_DBG);
30227211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30237616SVladimir.Kotal@Sun.COM for (i = 0; i < ulSlotCount; i++)
30247211Sjp161948 {
30257211Sjp161948 current_slot = pSlotList[i];
30267211Sjp161948
30277211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30287211Sjp161948 fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
30297211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30307211Sjp161948 /* Check if slot has random support. */
30317211Sjp161948 rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
30327211Sjp161948 if (rv != CKR_OK)
30337211Sjp161948 continue;
30347211Sjp161948
30357211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30367211Sjp161948 fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
30377211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30387211Sjp161948
30397211Sjp161948 if (token_info.flags & CKF_RNG)
30407211Sjp161948 {
30417211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30427211Sjp161948 fprintf(stderr, "%s: this token has CKF_RNG flag\n", PK11_DBG);
30437211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30447211Sjp161948 pk11_have_random = CK_TRUE;
30457962SHuie-Ying.Lee@Sun.COM rand_SLOTID = current_slot;
30467211Sjp161948 break;
30477211Sjp161948 }
30487211Sjp161948 }
30497211Sjp161948
30507211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30517211Sjp161948 fprintf(stderr, "%s: == checking pubkey slots ==\n", PK11_DBG);
30527211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30537962SHuie-Ying.Lee@Sun.COM
30547962SHuie-Ying.Lee@Sun.COM pubkey_SLOTID = pSlotList[0];
30557616SVladimir.Kotal@Sun.COM for (i = 0; i < ulSlotCount; i++)
30560Sstevel@tonic-gate {
30570Sstevel@tonic-gate CK_BBOOL slot_has_rsa = CK_FALSE;
30580Sstevel@tonic-gate CK_BBOOL slot_has_dsa = CK_FALSE;
30590Sstevel@tonic-gate CK_BBOOL slot_has_dh = CK_FALSE;
30600Sstevel@tonic-gate current_slot = pSlotList[i];
30617211Sjp161948
30627211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30637211Sjp161948 fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
30647211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30650Sstevel@tonic-gate rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
30660Sstevel@tonic-gate if (rv != CKR_OK)
30670Sstevel@tonic-gate continue;
30680Sstevel@tonic-gate
30697211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
30707211Sjp161948 fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
30717211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
30727211Sjp161948
30736847Svk199839 #ifndef OPENSSL_NO_RSA
30740Sstevel@tonic-gate /*
30750Sstevel@tonic-gate * Check if this slot is capable of signing and
30760Sstevel@tonic-gate * verifying with CKM_RSA_PKCS.
30770Sstevel@tonic-gate */
30787616SVladimir.Kotal@Sun.COM rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_RSA_PKCS,
30790Sstevel@tonic-gate &mech_info);
30800Sstevel@tonic-gate
30810Sstevel@tonic-gate if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30820Sstevel@tonic-gate (mech_info.flags & CKF_VERIFY)))
30830Sstevel@tonic-gate {
30840Sstevel@tonic-gate /*
30850Sstevel@tonic-gate * Check if this slot is capable of encryption,
30860Sstevel@tonic-gate * decryption, sign, and verify with CKM_RSA_X_509.
30870Sstevel@tonic-gate */
30880Sstevel@tonic-gate rv = pFuncList->C_GetMechanismInfo(current_slot,
30897616SVladimir.Kotal@Sun.COM CKM_RSA_X_509, &mech_info);
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30920Sstevel@tonic-gate (mech_info.flags & CKF_VERIFY) &&
30930Sstevel@tonic-gate (mech_info.flags & CKF_ENCRYPT) &&
30940Sstevel@tonic-gate (mech_info.flags & CKF_VERIFY_RECOVER) &&
30950Sstevel@tonic-gate (mech_info.flags & CKF_DECRYPT)))
30967211Sjp161948 {
30970Sstevel@tonic-gate slot_has_rsa = CK_TRUE;
30987211Sjp161948 }
30990Sstevel@tonic-gate }
31007211Sjp161948 #endif /* OPENSSL_NO_RSA */
31017211Sjp161948
31026847Svk199839 #ifndef OPENSSL_NO_DSA
31030Sstevel@tonic-gate /*
31040Sstevel@tonic-gate * Check if this slot is capable of signing and
31050Sstevel@tonic-gate * verifying with CKM_DSA.
31060Sstevel@tonic-gate */
31077616SVladimir.Kotal@Sun.COM rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_DSA,
31080Sstevel@tonic-gate &mech_info);
31090Sstevel@tonic-gate if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
31100Sstevel@tonic-gate (mech_info.flags & CKF_VERIFY)))
31117211Sjp161948 {
31120Sstevel@tonic-gate slot_has_dsa = CK_TRUE;
31137211Sjp161948 }
31147526SVladimir.Kotal@Sun.COM
31157211Sjp161948 #endif /* OPENSSL_NO_DSA */
31167211Sjp161948
31176847Svk199839 #ifndef OPENSSL_NO_DH
31180Sstevel@tonic-gate /*
31190Sstevel@tonic-gate * Check if this slot is capable of DH key generataion and
31200Sstevel@tonic-gate * derivation.
31210Sstevel@tonic-gate */
31220Sstevel@tonic-gate rv = pFuncList->C_GetMechanismInfo(current_slot,
31237616SVladimir.Kotal@Sun.COM CKM_DH_PKCS_KEY_PAIR_GEN, &mech_info);
31240Sstevel@tonic-gate
31250Sstevel@tonic-gate if (rv == CKR_OK && (mech_info.flags & CKF_GENERATE_KEY_PAIR))
31267616SVladimir.Kotal@Sun.COM {
31270Sstevel@tonic-gate rv = pFuncList->C_GetMechanismInfo(current_slot,
31280Sstevel@tonic-gate CKM_DH_PKCS_DERIVE, &mech_info);
31290Sstevel@tonic-gate if (rv == CKR_OK && (mech_info.flags & CKF_DERIVE))
31307211Sjp161948 {
31310Sstevel@tonic-gate slot_has_dh = CK_TRUE;
31327211Sjp161948 }
31330Sstevel@tonic-gate }
31347211Sjp161948 #endif /* OPENSSL_NO_DH */
31357211Sjp161948
31360Sstevel@tonic-gate if (!found_candidate_slot &&
31370Sstevel@tonic-gate (slot_has_rsa || slot_has_dsa || slot_has_dh))
31380Sstevel@tonic-gate {
31397211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
31400Sstevel@tonic-gate fprintf(stderr,
31417616SVladimir.Kotal@Sun.COM "%s: potential slot: %d\n", PK11_DBG, current_slot);
31427211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
31430Sstevel@tonic-gate best_slot_sofar = current_slot;
31440Sstevel@tonic-gate pk11_have_rsa = slot_has_rsa;
31450Sstevel@tonic-gate pk11_have_dsa = slot_has_dsa;
31460Sstevel@tonic-gate pk11_have_dh = slot_has_dh;
31470Sstevel@tonic-gate found_candidate_slot = CK_TRUE;
31487211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
31497211Sjp161948 fprintf(stderr,
31507616SVladimir.Kotal@Sun.COM "%s: setting found_candidate_slot to CK_TRUE\n",
31517211Sjp161948 PK11_DBG);
31520Sstevel@tonic-gate fprintf(stderr,
31537616SVladimir.Kotal@Sun.COM "%s: best so far slot: %d\n", PK11_DBG,
31547616SVladimir.Kotal@Sun.COM best_slot_sofar);
31557211Sjp161948 }
31567211Sjp161948 else
31577211Sjp161948 {
31587211Sjp161948 fprintf(stderr,
31597616SVladimir.Kotal@Sun.COM "%s: no rsa/dsa/dh\n", PK11_DBG);
31600Sstevel@tonic-gate }
31617211Sjp161948 #else
31627211Sjp161948 } /* if */
31637211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
31647211Sjp161948 } /* for */
31657211Sjp161948
31667211Sjp161948 if (found_candidate_slot)
31677211Sjp161948 {
31687211Sjp161948 pubkey_SLOTID = best_slot_sofar;
31697211Sjp161948 }
31707211Sjp161948
31717211Sjp161948 found_candidate_slot = CK_FALSE;
31727211Sjp161948 best_slot_sofar = 0;
31737211Sjp161948
31747211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
31757211Sjp161948 fprintf(stderr, "%s: == checking cipher/digest ==\n", PK11_DBG);
31767211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
31777962SHuie-Ying.Lee@Sun.COM
31787962SHuie-Ying.Lee@Sun.COM SLOTID = pSlotList[0];
31797616SVladimir.Kotal@Sun.COM for (i = 0; i < ulSlotCount; i++)
31807211Sjp161948 {
31817211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
31827211Sjp161948 fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
31837211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
31847211Sjp161948
31857211Sjp161948 current_slot = pSlotList[i];
31867211Sjp161948 current_slot_n_cipher = 0;
31877211Sjp161948 current_slot_n_digest = 0;
31887616SVladimir.Kotal@Sun.COM (void) memset(local_cipher_nids, 0, sizeof (local_cipher_nids));
31897616SVladimir.Kotal@Sun.COM (void) memset(local_digest_nids, 0, sizeof (local_digest_nids));
31907211Sjp161948
31917211Sjp161948 pk11_find_symmetric_ciphers(pFuncList, current_slot,
31927211Sjp161948 ¤t_slot_n_cipher, local_cipher_nids);
31937211Sjp161948
31947211Sjp161948 pk11_find_digests(pFuncList, current_slot,
31957211Sjp161948 ¤t_slot_n_digest, local_digest_nids);
31967211Sjp161948
31977211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
31987211Sjp161948 fprintf(stderr, "%s: current_slot_n_cipher %d\n", PK11_DBG,
31997211Sjp161948 current_slot_n_cipher);
32007211Sjp161948 fprintf(stderr, "%s: current_slot_n_digest %d\n", PK11_DBG,
32017211Sjp161948 current_slot_n_digest);
32027211Sjp161948 fprintf(stderr, "%s: best so far cipher/digest slot: %d\n",
32037211Sjp161948 PK11_DBG, best_slot_sofar);
32047211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32050Sstevel@tonic-gate
32060Sstevel@tonic-gate /*
32077616SVladimir.Kotal@Sun.COM * If the current slot supports more ciphers/digests than
32087250Sjp161948 * the previous best one we change the current best to this one,
32090Sstevel@tonic-gate * otherwise leave it where it is.
32100Sstevel@tonic-gate */
32117250Sjp161948 if ((current_slot_n_cipher + current_slot_n_digest) >
32127250Sjp161948 (slot_n_cipher + slot_n_digest))
32130Sstevel@tonic-gate {
32147211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32157211Sjp161948 fprintf(stderr,
32167211Sjp161948 "%s: changing best so far slot to %d\n",
32177211Sjp161948 PK11_DBG, current_slot);
32187211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32197211Sjp161948 best_slot_sofar = SLOTID = current_slot;
32207250Sjp161948 cipher_count = slot_n_cipher = current_slot_n_cipher;
32217250Sjp161948 digest_count = slot_n_digest = current_slot_n_digest;
32227534SVladimir.Kotal@Sun.COM (void) memcpy(cipher_nids, local_cipher_nids,
32237526SVladimir.Kotal@Sun.COM sizeof (local_cipher_nids));
32247534SVladimir.Kotal@Sun.COM (void) memcpy(digest_nids, local_digest_nids,
32257526SVladimir.Kotal@Sun.COM sizeof (local_digest_nids));
32260Sstevel@tonic-gate }
32270Sstevel@tonic-gate }
32280Sstevel@tonic-gate
32297211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32307211Sjp161948 fprintf(stderr,
32317526SVladimir.Kotal@Sun.COM "%s: chosen pubkey slot: %d\n", PK11_DBG, pubkey_SLOTID);
32320Sstevel@tonic-gate fprintf(stderr,
32337526SVladimir.Kotal@Sun.COM "%s: chosen rand slot: %d\n", PK11_DBG, rand_SLOTID);
32340Sstevel@tonic-gate fprintf(stderr,
32357526SVladimir.Kotal@Sun.COM "%s: chosen cipher/digest slot: %d\n", PK11_DBG, SLOTID);
32367211Sjp161948 fprintf(stderr,
32377526SVladimir.Kotal@Sun.COM "%s: pk11_have_rsa %d\n", PK11_DBG, pk11_have_rsa);
32380Sstevel@tonic-gate fprintf(stderr,
32397526SVladimir.Kotal@Sun.COM "%s: pk11_have_dsa %d\n", PK11_DBG, pk11_have_dsa);
32407211Sjp161948 fprintf(stderr,
32417526SVladimir.Kotal@Sun.COM "%s: pk11_have_dh %d\n", PK11_DBG, pk11_have_dh);
32420Sstevel@tonic-gate fprintf(stderr,
32437526SVladimir.Kotal@Sun.COM "%s: pk11_have_random %d\n", PK11_DBG, pk11_have_random);
32440Sstevel@tonic-gate fprintf(stderr,
32457526SVladimir.Kotal@Sun.COM "%s: cipher_count %d\n", PK11_DBG, cipher_count);
32467211Sjp161948 fprintf(stderr,
32477526SVladimir.Kotal@Sun.COM "%s: digest_count %d\n", PK11_DBG, digest_count);
32487211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32497616SVladimir.Kotal@Sun.COM
32506847Svk199839 if (pSlotList != NULL)
32516847Svk199839 OPENSSL_free(pSlotList);
32520Sstevel@tonic-gate
32537211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
32547211Sjp161948 OPENSSL_free(hw_cnids);
32557211Sjp161948 OPENSSL_free(hw_dnids);
32567211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
32577211Sjp161948
32587211Sjp161948 if (any_slot_found != NULL)
32597211Sjp161948 *any_slot_found = 1;
32607616SVladimir.Kotal@Sun.COM return (1);
32610Sstevel@tonic-gate }
32620Sstevel@tonic-gate
pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR pflist,int slot_id,CK_MECHANISM_TYPE mech,int * current_slot_n_cipher,int * local_cipher_nids,int id)32637211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR pflist,
32647211Sjp161948 int slot_id, CK_MECHANISM_TYPE mech, int *current_slot_n_cipher,
32657211Sjp161948 int *local_cipher_nids, int id)
32667211Sjp161948 {
32677211Sjp161948 CK_MECHANISM_INFO mech_info;
32687211Sjp161948 CK_RV rv;
32697211Sjp161948
32707211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32717211Sjp161948 fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
32727211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32737211Sjp161948 rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
32747211Sjp161948
32757616SVladimir.Kotal@Sun.COM if (rv != CKR_OK)
32767211Sjp161948 {
32777211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32787211Sjp161948 fprintf(stderr, " not found\n");
32797211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32807211Sjp161948 return;
32817211Sjp161948 }
32827211Sjp161948
32837211Sjp161948 if ((mech_info.flags & CKF_ENCRYPT) &&
32847211Sjp161948 (mech_info.flags & CKF_DECRYPT))
32857211Sjp161948 {
32867211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
32877211Sjp161948 if (nid_in_table(ciphers[id].nid, hw_cnids))
32887211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
32897211Sjp161948 {
32907211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32917211Sjp161948 fprintf(stderr, " usable\n");
32927211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
32937211Sjp161948 local_cipher_nids[(*current_slot_n_cipher)++] =
32947211Sjp161948 ciphers[id].nid;
32957211Sjp161948 }
32967211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
32977211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
32987211Sjp161948 else
32997211Sjp161948 {
33007211Sjp161948 fprintf(stderr, " rejected, software implementation only\n");
33017211Sjp161948 }
33027211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33037211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
33047211Sjp161948 }
33057211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33067211Sjp161948 else
33077211Sjp161948 {
33087211Sjp161948 fprintf(stderr, " unusable\n");
33097211Sjp161948 }
33107211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33117211Sjp161948
33127211Sjp161948 return;
33137211Sjp161948 }
33147211Sjp161948
pk11_get_digest(CK_FUNCTION_LIST_PTR pflist,int slot_id,CK_MECHANISM_TYPE mech,int * current_slot_n_digest,int * local_digest_nids,int id)33157211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
33167211Sjp161948 CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
33177211Sjp161948 int id)
33180Sstevel@tonic-gate {
33190Sstevel@tonic-gate CK_MECHANISM_INFO mech_info;
33200Sstevel@tonic-gate CK_RV rv;
33210Sstevel@tonic-gate
33227211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33237211Sjp161948 fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
33247211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33257211Sjp161948 rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
33260Sstevel@tonic-gate
33277616SVladimir.Kotal@Sun.COM if (rv != CKR_OK)
33280Sstevel@tonic-gate {
33297211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33307211Sjp161948 fprintf(stderr, " not found\n");
33317211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33327211Sjp161948 return;
33330Sstevel@tonic-gate }
33340Sstevel@tonic-gate
33350Sstevel@tonic-gate if (mech_info.flags & CKF_DIGEST)
33360Sstevel@tonic-gate {
33377211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
33387616SVladimir.Kotal@Sun.COM if (nid_in_table(digests[id].nid, hw_dnids))
33397211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
33407211Sjp161948 {
33417211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33427211Sjp161948 fprintf(stderr, " usable\n");
33437211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33447211Sjp161948 local_digest_nids[(*current_slot_n_digest)++] =
33457211Sjp161948 digests[id].nid;
33467211Sjp161948 }
33477211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
33487211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33497211Sjp161948 else
33507211Sjp161948 {
33517211Sjp161948 fprintf(stderr, " rejected, software implementation only\n");
33527211Sjp161948 }
33537211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33547211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
33557211Sjp161948 }
33567211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
33577211Sjp161948 else
33587211Sjp161948 {
33597211Sjp161948 fprintf(stderr, " unusable\n");
33600Sstevel@tonic-gate }
33617211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
33627211Sjp161948
33637211Sjp161948 return;
33647211Sjp161948 }
33657211Sjp161948
33667211Sjp161948 #ifdef SOLARIS_AES_CTR
33677211Sjp161948 /* create a new NID when we have no OID for that mechanism */
pk11_add_NID(char * sn,char * ln)33687211Sjp161948 static int pk11_add_NID(char *sn, char *ln)
33697211Sjp161948 {
33707211Sjp161948 ASN1_OBJECT *o;
33717211Sjp161948 int nid;
33727211Sjp161948
33737211Sjp161948 if ((o = ASN1_OBJECT_create(OBJ_new_nid(1), (unsigned char *)"",
33747211Sjp161948 1, sn, ln)) == NULL)
33757211Sjp161948 {
33767616SVladimir.Kotal@Sun.COM return (0);
33777211Sjp161948 }
33787211Sjp161948
33797211Sjp161948 /* will return NID_undef on error */
33807211Sjp161948 nid = OBJ_add_object(o);
33817211Sjp161948 ASN1_OBJECT_free(o);
33827211Sjp161948
33837211Sjp161948 return (nid);
33847211Sjp161948 }
33857211Sjp161948
33867211Sjp161948 /*
33877211Sjp161948 * Create new NIDs for AES counter mode. OpenSSL doesn't support them now so we
33887211Sjp161948 * have to help ourselves here.
33897211Sjp161948 */
pk11_add_aes_ctr_NIDs(void)33907211Sjp161948 static int pk11_add_aes_ctr_NIDs(void)
33917211Sjp161948 {
33927211Sjp161948 /* are we already set? */
33937211Sjp161948 if (NID_aes_256_ctr != NID_undef)
33947616SVladimir.Kotal@Sun.COM return (1);
33957211Sjp161948
33967211Sjp161948 /*
33977211Sjp161948 * There are no official names for AES counter modes yet so we just
33987211Sjp161948 * follow the format of those that exist.
33997211Sjp161948 */
34007211Sjp161948 if ((NID_aes_128_ctr = pk11_add_NID("AES-128-CTR", "aes-128-ctr")) ==
34017211Sjp161948 NID_undef)
34027211Sjp161948 goto err;
34037211Sjp161948 ciphers[PK11_AES_128_CTR].nid = pk11_aes_128_ctr.nid = NID_aes_128_ctr;
34047211Sjp161948 if ((NID_aes_192_ctr = pk11_add_NID("AES-192-CTR", "aes-192-ctr")) ==
34057211Sjp161948 NID_undef)
34067211Sjp161948 goto err;
34077211Sjp161948 ciphers[PK11_AES_192_CTR].nid = pk11_aes_192_ctr.nid = NID_aes_192_ctr;
34087211Sjp161948 if ((NID_aes_256_ctr = pk11_add_NID("AES-256-CTR", "aes-256-ctr")) ==
34097211Sjp161948 NID_undef)
34107211Sjp161948 goto err;
34117211Sjp161948 ciphers[PK11_AES_256_CTR].nid = pk11_aes_256_ctr.nid = NID_aes_256_ctr;
34127616SVladimir.Kotal@Sun.COM return (1);
34137211Sjp161948
34147211Sjp161948 err:
34157211Sjp161948 PK11err(PK11_F_ADD_AES_CTR_NIDS, PK11_R_ADD_NID_FAILED);
34167616SVladimir.Kotal@Sun.COM return (0);
34170Sstevel@tonic-gate }
34187211Sjp161948 #endif /* SOLARIS_AES_CTR */
34197211Sjp161948
34207211Sjp161948 /* Find what symmetric ciphers this slot supports. */
pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,CK_SLOT_ID current_slot,int * current_slot_n_cipher,int * local_cipher_nids)34217211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
34227211Sjp161948 CK_SLOT_ID current_slot, int *current_slot_n_cipher, int *local_cipher_nids)
34237211Sjp161948 {
34247211Sjp161948 int i;
34257211Sjp161948
34267211Sjp161948 for (i = 0; i < PK11_CIPHER_MAX; ++i)
34277211Sjp161948 {
34287211Sjp161948 pk11_get_symmetric_cipher(pflist, current_slot,
34297211Sjp161948 ciphers[i].mech_type, current_slot_n_cipher,
34307211Sjp161948 local_cipher_nids, ciphers[i].id);
34317211Sjp161948 }
34327211Sjp161948 }
34337211Sjp161948
34347211Sjp161948 /* Find what digest algorithms this slot supports. */
pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,CK_SLOT_ID current_slot,int * current_slot_n_digest,int * local_digest_nids)34357211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
34367211Sjp161948 CK_SLOT_ID current_slot, int *current_slot_n_digest, int *local_digest_nids)
34377211Sjp161948 {
34387211Sjp161948 int i;
34397211Sjp161948
34407211Sjp161948 for (i = 0; i < PK11_DIGEST_MAX; ++i)
34417211Sjp161948 {
34427211Sjp161948 pk11_get_digest(pflist, current_slot, digests[i].mech_type,
34437211Sjp161948 current_slot_n_digest, local_digest_nids, digests[i].id);
34447211Sjp161948 }
34457211Sjp161948 }
34467211Sjp161948
34477211Sjp161948 #ifdef SOLARIS_HW_SLOT_SELECTION
34487211Sjp161948 /*
34497211Sjp161948 * It would be great if we could use pkcs11_kernel directly since this library
34507211Sjp161948 * offers hardware slots only. That's the easiest way to achieve the situation
34517211Sjp161948 * where we use the hardware accelerators when present and OpenSSL native code
34527211Sjp161948 * otherwise. That presumes the fact that OpenSSL native code is faster than the
34537211Sjp161948 * code in the soft token. It's a logical assumption - Crypto Framework has some
34547211Sjp161948 * inherent overhead so going there for the software implementation of a
34557211Sjp161948 * mechanism should be logically slower in contrast to the OpenSSL native code,
34567211Sjp161948 * presuming that both implementations are of similar speed. For example, the
34577211Sjp161948 * soft token for AES is roughly three times slower than OpenSSL for 64 byte
34587211Sjp161948 * blocks and still 20% slower for 8KB blocks. So, if we want to ship products
34597211Sjp161948 * that use the PKCS#11 engine by default, we must somehow avoid that regression
34607211Sjp161948 * on machines without hardware acceleration. That's why switching to the
34617211Sjp161948 * pkcs11_kernel library seems like a very good idea.
34627211Sjp161948 *
34637211Sjp161948 * The problem is that OpenSSL built with SunStudio is roughly 2x slower for
34647211Sjp161948 * asymmetric operations (RSA/DSA/DH) than the soft token built with the same
34657211Sjp161948 * compiler. That means that if we switched to pkcs11_kernel from the libpkcs11
34667211Sjp161948 * library, we would have had a performance regression on machines without
34677211Sjp161948 * hardware acceleration for asymmetric operations for all applications that use
34687211Sjp161948 * the PKCS#11 engine. There is one such application - Apache web server since
34697211Sjp161948 * it's shipped configured to use the PKCS#11 engine by default. Having said
34707211Sjp161948 * that, we can't switch to the pkcs11_kernel library now and have to come with
34717211Sjp161948 * a solution that, on non-accelerated machines, uses the OpenSSL native code
34727211Sjp161948 * for all symmetric ciphers and digests while it uses the soft token for
34737211Sjp161948 * asymmetric operations.
34747211Sjp161948 *
34757211Sjp161948 * This is the idea: dlopen() pkcs11_kernel directly and find out what
34767211Sjp161948 * mechanisms are there. We don't care about duplications (more slots can
34777211Sjp161948 * support the same mechanism), we just want to know what mechanisms can be
34787211Sjp161948 * possibly supported in hardware on that particular machine. As said before,
34797211Sjp161948 * pkcs11_kernel will show you hardware providers only.
34807211Sjp161948 *
34817211Sjp161948 * Then, we rely on the fact that since we use libpkcs11 library we will find
34827211Sjp161948 * the metaslot. When we go through the metaslot's mechanisms for symmetric
34837211Sjp161948 * ciphers and digests, we check that any found mechanism is in the table
34847211Sjp161948 * created using the pkcs11_kernel library. So, as a result we have two arrays
34857211Sjp161948 * of mechanisms that were advertised as supported in hardware which was the
34867211Sjp161948 * goal of that whole excercise. Thus, we can use libpkcs11 but avoid soft token
34877211Sjp161948 * code for symmetric ciphers and digests. See pk11_choose_slots() for more
34887211Sjp161948 * information.
34897211Sjp161948 *
34907211Sjp161948 * This is Solaris specific code, if SOLARIS_HW_SLOT_SELECTION is not defined
34917211Sjp161948 * the code won't be used.
34927211Sjp161948 */
34937211Sjp161948 #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
34947211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/64/pkcs11_kernel.so.1";
34957211Sjp161948 #else
34967211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/pkcs11_kernel.so.1";
34977211Sjp161948 #endif
34987211Sjp161948
34997211Sjp161948 /*
35007211Sjp161948 * Check hardware capabilities of the machines. The output are two lists,
35017211Sjp161948 * hw_cnids and hw_dnids, that contain hardware mechanisms found in all hardware
35027211Sjp161948 * providers together. They are not sorted and may contain duplicate mechanisms.
35037211Sjp161948 */
check_hw_mechanisms(void)35047211Sjp161948 static int check_hw_mechanisms(void)
35057211Sjp161948 {
35067211Sjp161948 int i;
35077211Sjp161948 CK_RV rv;
35087211Sjp161948 void *handle;
35097211Sjp161948 CK_C_GetFunctionList p;
35107211Sjp161948 CK_TOKEN_INFO token_info;
35117211Sjp161948 CK_ULONG ulSlotCount = 0;
35127211Sjp161948 int n_cipher = 0, n_digest = 0;
35137211Sjp161948 CK_FUNCTION_LIST_PTR pflist = NULL;
35147211Sjp161948 CK_SLOT_ID_PTR pSlotList = NULL_PTR;
35157211Sjp161948 int *tmp_hw_cnids, *tmp_hw_dnids;
35167211Sjp161948 int hw_ctable_size, hw_dtable_size;
35177211Sjp161948
35187211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
35197211Sjp161948 fprintf(stderr, "%s: SOLARIS_HW_SLOT_SELECTION code running\n",
35207211Sjp161948 PK11_DBG);
35210Sstevel@tonic-gate #endif
35227211Sjp161948 if ((handle = dlopen(pkcs11_kernel, RTLD_LAZY)) == NULL)
35237211Sjp161948 {
35247211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35257211Sjp161948 goto err;
35267211Sjp161948 }
35277211Sjp161948
35287616SVladimir.Kotal@Sun.COM if ((p = (CK_C_GetFunctionList)dlsym(handle,
35297211Sjp161948 PK11_GET_FUNCTION_LIST)) == NULL)
35307211Sjp161948 {
35317211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35327211Sjp161948 goto err;
35337211Sjp161948 }
35347616SVladimir.Kotal@Sun.COM
35357616SVladimir.Kotal@Sun.COM /* get the full function list from the loaded library */
35367211Sjp161948 if (p(&pflist) != CKR_OK)
35377211Sjp161948 {
35387211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35397211Sjp161948 goto err;
35407211Sjp161948 }
35417616SVladimir.Kotal@Sun.COM
35427211Sjp161948 rv = pflist->C_Initialize(NULL_PTR);
35437211Sjp161948 if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
35447211Sjp161948 {
35457211Sjp161948 PK11err_add_data(PK11_F_CHECK_HW_MECHANISMS,
35467211Sjp161948 PK11_R_INITIALIZE, rv);
35477211Sjp161948 goto err;
35487211Sjp161948 }
35497211Sjp161948
35507211Sjp161948 if (pflist->C_GetSlotList(0, NULL_PTR, &ulSlotCount) != CKR_OK)
35517211Sjp161948 {
35527211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
35537211Sjp161948 goto err;
35547211Sjp161948 }
35557211Sjp161948
35567211Sjp161948 /* no slots, set the hw mechanism tables as empty */
35577211Sjp161948 if (ulSlotCount == 0)
35587211Sjp161948 {
35597211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
35607211Sjp161948 fprintf(stderr, "%s: no hardware mechanisms found\n", PK11_DBG);
35610Sstevel@tonic-gate #endif
35627211Sjp161948 hw_cnids = OPENSSL_malloc(sizeof (int));
35637211Sjp161948 hw_dnids = OPENSSL_malloc(sizeof (int));
35647211Sjp161948 if (hw_cnids == NULL || hw_dnids == NULL)
35657211Sjp161948 {
35667211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS,
35677211Sjp161948 PK11_R_MALLOC_FAILURE);
35687211Sjp161948 return (0);
35697211Sjp161948 }
35707211Sjp161948 /* this means empty tables */
35717211Sjp161948 hw_cnids[0] = NID_undef;
35727211Sjp161948 hw_dnids[0] = NID_undef;
35737211Sjp161948 return (1);
35747211Sjp161948 }
35757211Sjp161948
35767211Sjp161948 pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
35777616SVladimir.Kotal@Sun.COM if (pSlotList == NULL)
35787211Sjp161948 {
35797211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
35807211Sjp161948 goto err;
35817211Sjp161948 }
35827211Sjp161948
35837211Sjp161948 /* Get the slot list for processing */
35847211Sjp161948 if (pflist->C_GetSlotList(0, pSlotList, &ulSlotCount) != CKR_OK)
35857211Sjp161948 {
35867211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
35877211Sjp161948 goto err;
35887211Sjp161948 }
35897211Sjp161948
35907211Sjp161948 /*
35917211Sjp161948 * We don't care about duplicit mechanisms in multiple slots and also
35927211Sjp161948 * reserve one slot for the terminal NID_undef which we use to stop the
35937211Sjp161948 * search.
35947211Sjp161948 */
35957211Sjp161948 hw_ctable_size = ulSlotCount * PK11_CIPHER_MAX + 1;
35967211Sjp161948 hw_dtable_size = ulSlotCount * PK11_DIGEST_MAX + 1;
35977211Sjp161948 tmp_hw_cnids = OPENSSL_malloc(hw_ctable_size * sizeof (int));
35987211Sjp161948 tmp_hw_dnids = OPENSSL_malloc(hw_dtable_size * sizeof (int));
35997211Sjp161948 if (tmp_hw_cnids == NULL || tmp_hw_dnids == NULL)
36007211Sjp161948 {
36017211Sjp161948 PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
36027211Sjp161948 goto err;
36037211Sjp161948 }
36047211Sjp161948
36057211Sjp161948 /*
36067211Sjp161948 * Do not use memset since we should not rely on the fact that NID_undef
36077211Sjp161948 * is zero now.
36087211Sjp161948 */
36097211Sjp161948 for (i = 0; i < hw_ctable_size; ++i)
36107211Sjp161948 tmp_hw_cnids[i] = NID_undef;
36117211Sjp161948 for (i = 0; i < hw_dtable_size; ++i)
36127211Sjp161948 tmp_hw_dnids[i] = NID_undef;
36137211Sjp161948
36147211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
36157211Sjp161948 fprintf(stderr, "%s: provider: %s\n", PK11_DBG, pkcs11_kernel);
36167211Sjp161948 fprintf(stderr, "%s: found %d hardware slots\n", PK11_DBG, ulSlotCount);
36177211Sjp161948 fprintf(stderr, "%s: now looking for mechs supported in hw\n",
36187616SVladimir.Kotal@Sun.COM PK11_DBG);
36197211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
36207211Sjp161948
36217616SVladimir.Kotal@Sun.COM for (i = 0; i < ulSlotCount; i++)
36227211Sjp161948 {
36237211Sjp161948 if (pflist->C_GetTokenInfo(pSlotList[i], &token_info) != CKR_OK)
36247211Sjp161948 continue;
36257211Sjp161948
36267211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
36277211Sjp161948 fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
36287211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
36297211Sjp161948
36307211Sjp161948 /*
36317211Sjp161948 * We are filling the hw mech tables here. Global tables are
36327211Sjp161948 * still NULL so all mechanisms are put into tmp tables.
36337211Sjp161948 */
36347211Sjp161948 pk11_find_symmetric_ciphers(pflist, pSlotList[i],
36357211Sjp161948 &n_cipher, tmp_hw_cnids);
36367211Sjp161948 pk11_find_digests(pflist, pSlotList[i],
36377211Sjp161948 &n_digest, tmp_hw_dnids);
36387211Sjp161948 }
36397211Sjp161948
36407211Sjp161948 /*
36417211Sjp161948 * Since we are part of a library (libcrypto.so), calling this function
36427211Sjp161948 * may have side-effects. Also, C_Finalize() is triggered by
36437211Sjp161948 * dlclose(3C).
36447211Sjp161948 */
36457211Sjp161948 #if 0
36467211Sjp161948 pflist->C_Finalize(NULL);
36477211Sjp161948 #endif
36487211Sjp161948 OPENSSL_free(pSlotList);
36497534SVladimir.Kotal@Sun.COM (void) dlclose(handle);
36507211Sjp161948 hw_cnids = tmp_hw_cnids;
36517211Sjp161948 hw_dnids = tmp_hw_dnids;
36527211Sjp161948
36537211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
36547211Sjp161948 fprintf(stderr, "%s: hw mechs check complete\n", PK11_DBG);
36557211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
36567211Sjp161948 return (1);
36577211Sjp161948
36587211Sjp161948 err:
36597211Sjp161948 if (pSlotList != NULL)
36607211Sjp161948 OPENSSL_free(pSlotList);
36617211Sjp161948 if (tmp_hw_cnids != NULL)
36627211Sjp161948 OPENSSL_free(tmp_hw_cnids);
36637211Sjp161948 if (tmp_hw_dnids != NULL)
36647211Sjp161948 OPENSSL_free(tmp_hw_dnids);
36657211Sjp161948
36667211Sjp161948 return (0);
36677211Sjp161948 }
36687211Sjp161948
36697211Sjp161948 /*
36707211Sjp161948 * Check presence of a NID in the table of NIDs. The table may be NULL (i.e.,
36717211Sjp161948 * non-existent).
36727211Sjp161948 */
nid_in_table(int nid,int * nid_table)36737211Sjp161948 static int nid_in_table(int nid, int *nid_table)
36747211Sjp161948 {
36757211Sjp161948 int i = 0;
36767211Sjp161948
36777211Sjp161948 /*
36787211Sjp161948 * a special case. NULL means that we are initializing a new
36797211Sjp161948 * table.
36807211Sjp161948 */
36817211Sjp161948 if (nid_table == NULL)
36827211Sjp161948 return (1);
36837211Sjp161948
36847211Sjp161948 /*
36857211Sjp161948 * the table is never full, there is always at least one
36867211Sjp161948 * NID_undef.
36877211Sjp161948 */
36887211Sjp161948 while (nid_table[i] != NID_undef)
36897211Sjp161948 {
36907211Sjp161948 if (nid_table[i++] == nid)
36917211Sjp161948 {
36927211Sjp161948 #ifdef DEBUG_SLOT_SELECTION
36937211Sjp161948 fprintf(stderr, " (NID %d in hw table, idx %d)", nid, i);
36947211Sjp161948 #endif /* DEBUG_SLOT_SELECTION */
36957211Sjp161948 return (1);
36967211Sjp161948 }
36977211Sjp161948 }
36987211Sjp161948
36997211Sjp161948 return (0);
37007211Sjp161948 }
37017211Sjp161948 #endif /* SOLARIS_HW_SLOT_SELECTION */
37027211Sjp161948
37037211Sjp161948 #endif /* OPENSSL_NO_HW_PK11 */
37047211Sjp161948 #endif /* OPENSSL_NO_HW */
3705