1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Solaris specific functions to reduce the initialization
30  * overhead of using PKCS #11
31  */
32 
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <security/cryptoki.h>
36 #include <assert.h>
37 #include <cryptoutil.h>
38 #include <pkcs11Global.h>
39 
40 static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
41 static CK_BBOOL falsevalue = FALSE;
42 static CK_BBOOL truevalue = TRUE;
43 
44 #define	NUM_SECRETKEY_ATTRS	8
45 
46 typedef struct _ATTRTYPE_MECHINFO_MAPPING {
47 	CK_ATTRIBUTE_TYPE attr;
48 	CK_FLAGS	flag;
49 } ATTRTYPE_MECHINFO_MAPPING;
50 
51 /* possible attribute types for creating key */
52 ATTRTYPE_MECHINFO_MAPPING mapping[] = {
53 	{CKA_ENCRYPT, CKF_ENCRYPT},
54 	{CKA_DECRYPT, CKF_DECRYPT},
55 	{CKA_SIGN, CKF_SIGN},
56 	{CKA_VERIFY, CKF_VERIFY}
57 };
58 
59 
60 /*
61  * List of mechanisms that only supports asymmetric key operations
62  * in PKCS #11 V2.11
63  */
64 CK_MECHANISM_TYPE asymmetric_mechs[] = {
65 	CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509,
66 	CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31,
67 	CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1,
68 	CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN,
69 	CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE,
70 	CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE
71 };
72 
73 
74 /*
75  * SUNW_C_GetMechSession will initialize the framework and do all
76  * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo()
77  * C_OpenSession() to provide a session capable of providing the requested
78  * mechanism.
79  *
80  * If the function is called multiple times, it will return a new session
81  * without reinitializing the framework.
82  */
83 CK_RV
84 SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession)
85 {
86 	CK_RV rv;
87 	CK_ULONG slotcount;
88 	CK_SLOT_ID_PTR slot_list;
89 	CK_SLOT_ID slot_id;
90 	CK_MECHANISM_INFO mech_info;
91 	CK_ULONG i;
92 
93 	if (hSession == NULL) {
94 		return (CKR_ARGUMENTS_BAD);
95 	}
96 
97 	/* initialize PKCS #11 */
98 	if (!pkcs11_initialized) {
99 		rv = C_Initialize(NULL);
100 		if ((rv != CKR_OK) &&
101 		    (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
102 			return (rv);
103 		}
104 	}
105 
106 	/* get slot count */
107 	rv = C_GetSlotList(0, NULL, &slotcount);
108 	if (rv != CKR_OK) {
109 		return (rv);
110 	}
111 
112 	if (slotcount == 0) {
113 		return (CKR_FUNCTION_FAILED);
114 	}
115 
116 
117 	/* allocate memory for slot list */
118 	slot_list = malloc(slotcount * sizeof (CK_SLOT_ID));
119 	if (slot_list == NULL) {
120 		return (CKR_HOST_MEMORY);
121 	}
122 
123 	if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
124 		free(slot_list);
125 		return (rv);
126 	}
127 
128 	/* find slot with matching mechanism */
129 	for (i = 0; i < slotcount; i++) {
130 		slot_id = slot_list[i];
131 		if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) {
132 			/* found mechanism */
133 			break;
134 		}
135 	}
136 
137 	if (i == slotcount) {
138 		/* no matching mechanism found */
139 		free(slot_list);
140 		return (CKR_MECHANISM_INVALID);
141 	}
142 
143 	rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
144 	    NULL, hSession);
145 
146 	free(slot_list);
147 	return (rv);
148 }
149 
150 /*
151  * SUNW_C_KeyToObject creates a secret key object for the given
152  * mechanism from the rawkey data.
153  */
154 CK_RV
155 SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech,
156     const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj)
157 {
158 
159 	CK_RV rv;
160 	CK_SESSION_INFO session_info;
161 	CK_SLOT_ID slot_id;
162 	CK_MECHANISM_INFO mech_info;
163 	CK_ULONG i, j;
164 	CK_KEY_TYPE keytype;
165 	CK_ULONG num_asym_mechs, num_mapping;
166 
167 	/* template for creating generic secret key object */
168 	CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
169 
170 	if ((hSession == NULL) || (obj == NULL) ||
171 	    (rawkey == NULL) || (rawkey_len == 0)) {
172 		return (CKR_ARGUMENTS_BAD);
173 	}
174 
175 	/*
176 	 * Check to make sure mechanism type is not for asymmetric key
177 	 * only operations.  This function is only applicable to
178 	 * generating secret key.
179 	 */
180 	num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE);
181 	for (i = 0; i < num_asym_mechs; i++) {
182 		if (mech == asymmetric_mechs[i]) {
183 			return (CKR_MECHANISM_INVALID);
184 		}
185 	}
186 
187 	/* set the attribute type flag on object based on mechanism */
188 	rv = C_GetSessionInfo(hSession, &session_info);
189 	if (rv != CKR_OK) {
190 		goto cleanup;
191 	}
192 
193 	slot_id = session_info.slotID;
194 
195 	/* create a generic object first */
196 	i = 0;
197 	template[i].type = CKA_CLASS;
198 	template[i].pValue = &objclass;
199 	template[i].ulValueLen = sizeof (objclass);
200 	i++;
201 
202 	/* get the key type for this mechanism */
203 	if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) {
204 		return (rv);
205 	}
206 
207 	assert(i < NUM_SECRETKEY_ATTRS);
208 	template[i].type = CKA_KEY_TYPE;
209 	template[i].pValue = &keytype;
210 	template[i].ulValueLen = sizeof (keytype);
211 	i++;
212 
213 	rv = C_GetMechanismInfo(slot_id, mech, &mech_info);
214 	if (rv != CKR_OK) {
215 		goto cleanup;
216 	}
217 
218 	num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING);
219 	for (j = 0; j < num_mapping; j++) {
220 		assert(i < NUM_SECRETKEY_ATTRS);
221 		template[i].type = mapping[j].attr;
222 		template[i].ulValueLen = sizeof (falsevalue);
223 		if (mech_info.flags & ((mapping[j]).flag)) {
224 			template[i].pValue = &truevalue;
225 		} else {
226 			template[i].pValue = &falsevalue;
227 		}
228 		i++;
229 	}
230 
231 	assert(i < NUM_SECRETKEY_ATTRS);
232 	template[i].type = CKA_TOKEN;
233 	template[i].pValue = &falsevalue;
234 	template[i].ulValueLen = sizeof (falsevalue);
235 	i++;
236 
237 	assert(i < NUM_SECRETKEY_ATTRS);
238 	template[i].type = CKA_VALUE;
239 	template[i].pValue = (CK_VOID_PTR)rawkey;
240 	template[i].ulValueLen = (CK_ULONG)rawkey_len;
241 	i++;
242 
243 	rv = C_CreateObject(hSession, template, i, obj);
244 	if (rv != CKR_OK) {
245 		return (rv);
246 	}
247 
248 	return (rv);
249 
250 cleanup:
251 	/* This cleanup is only for failure cases */
252 	(void) C_DestroyObject(hSession, *obj);
253 	return (rv);
254 }
255