xref: /illumos-gate/usr/src/lib/pkcs11/libpkcs11/common/pkcs11SUNWExtensions.c (revision bea83d026ee1bd1b2a2419e1d0232f107a5d7d9b)
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 2007 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	12
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 	{CKA_WRAP, CKF_WRAP},
58 	{CKA_UNWRAP, CKF_UNWRAP}
59 };
60 
61 
62 /*
63  * List of mechanisms that only supports asymmetric key operations
64  * in PKCS #11 V2.11
65  */
66 CK_MECHANISM_TYPE asymmetric_mechs[] = {
67 	CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509,
68 	CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31,
69 	CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1,
70 	CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN,
71 	CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE,
72 	CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE
73 };
74 
75 
76 typedef struct _KEY_TYPE_SIZE_MAPPING {
77 	CK_KEY_TYPE type;
78 	CK_ULONG len;
79 } KEY_TYPE_SIZE_MAPPING;
80 
81 /*
82  * List of secret key types that have fixed sizes and their sizes.
83  * These key types do not allow CKA_VALUE_LEN for key generation.
84  * The sizes are in bytes.
85  *
86  * Discrete-sized keys, such as AES and Twofish, and variable sized
87  * keys, such as Blowfish, are not in this list.
88  */
89 KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = {
90 	{CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16},
91 	{CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40}
92 };
93 
94 
95 /*
96  * SUNW_C_GetMechSession will initialize the framework and do all
97  * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo()
98  * C_OpenSession() to provide a session capable of providing the requested
99  * mechanism.
100  *
101  * If the function is called multiple times, it will return a new session
102  * without reinitializing the framework.
103  */
104 CK_RV
105 SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession)
106 {
107 	CK_RV rv;
108 	CK_ULONG slotcount;
109 	CK_SLOT_ID_PTR slot_list;
110 	CK_SLOT_ID slot_id;
111 	CK_MECHANISM_INFO mech_info;
112 	CK_ULONG i;
113 
114 	if (hSession == NULL) {
115 		return (CKR_ARGUMENTS_BAD);
116 	}
117 
118 	/* initialize PKCS #11 */
119 	if (!pkcs11_initialized) {
120 		rv = C_Initialize(NULL);
121 		if ((rv != CKR_OK) &&
122 		    (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
123 			return (rv);
124 		}
125 	}
126 
127 	/* get slot count */
128 	rv = C_GetSlotList(0, NULL, &slotcount);
129 	if (rv != CKR_OK) {
130 		return (rv);
131 	}
132 
133 	if (slotcount == 0) {
134 		return (CKR_FUNCTION_FAILED);
135 	}
136 
137 
138 	/* allocate memory for slot list */
139 	slot_list = malloc(slotcount * sizeof (CK_SLOT_ID));
140 	if (slot_list == NULL) {
141 		return (CKR_HOST_MEMORY);
142 	}
143 
144 	if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
145 		free(slot_list);
146 		return (rv);
147 	}
148 
149 	/* find slot with matching mechanism */
150 	for (i = 0; i < slotcount; i++) {
151 		slot_id = slot_list[i];
152 		if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) {
153 			/* found mechanism */
154 			break;
155 		}
156 	}
157 
158 	if (i == slotcount) {
159 		/* no matching mechanism found */
160 		free(slot_list);
161 		return (CKR_MECHANISM_INVALID);
162 	}
163 
164 	rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
165 	    NULL, hSession);
166 
167 	free(slot_list);
168 	return (rv);
169 }
170 
171 /*
172  * SUNW_C_KeyToObject creates a secret key object for the given
173  * mechanism from the rawkey data.
174  */
175 CK_RV
176 SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech,
177     const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj)
178 {
179 
180 	CK_RV rv;
181 	CK_SESSION_INFO session_info;
182 	CK_SLOT_ID slot_id;
183 	CK_MECHANISM_INFO mech_info;
184 	CK_ULONG i, j;
185 	CK_KEY_TYPE keytype;
186 	CK_ULONG num_asym_mechs, num_mapping;
187 
188 	/* template for creating generic secret key object */
189 	CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
190 
191 	if ((hSession == NULL) || (obj == NULL) ||
192 	    (rawkey == NULL) || (rawkey_len == 0)) {
193 		return (CKR_ARGUMENTS_BAD);
194 	}
195 
196 	/*
197 	 * Check to make sure mechanism type is not for asymmetric key
198 	 * only operations.  This function is only applicable to
199 	 * generating secret key.
200 	 */
201 	num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE);
202 	for (i = 0; i < num_asym_mechs; i++) {
203 		if (mech == asymmetric_mechs[i]) {
204 			return (CKR_MECHANISM_INVALID);
205 		}
206 	}
207 
208 	rv = C_GetSessionInfo(hSession, &session_info);
209 	if (rv != CKR_OK) {
210 		return (rv);
211 	}
212 
213 	slot_id = session_info.slotID;
214 
215 	i = 0;
216 	template[i].type = CKA_CLASS;
217 	template[i].pValue = &objclass;
218 	template[i].ulValueLen = sizeof (objclass);
219 	i++;
220 
221 	/* get the key type for this mechanism */
222 	if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) {
223 		return (rv);
224 	}
225 
226 	assert(i < NUM_SECRETKEY_ATTRS);
227 	template[i].type = CKA_KEY_TYPE;
228 	template[i].pValue = &keytype;
229 	template[i].ulValueLen = sizeof (keytype);
230 	i++;
231 
232 	rv = C_GetMechanismInfo(slot_id, mech, &mech_info);
233 	if (rv != CKR_OK) {
234 		return (rv);
235 	}
236 
237 	/* set the attribute type flag on object based on mechanism */
238 	num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING);
239 	for (j = 0; j < num_mapping; j++) {
240 		assert(i < NUM_SECRETKEY_ATTRS);
241 		template[i].type = mapping[j].attr;
242 		template[i].ulValueLen = sizeof (falsevalue);
243 		if (mech_info.flags & ((mapping[j]).flag)) {
244 			template[i].pValue = &truevalue;
245 		} else {
246 			template[i].pValue = &falsevalue;
247 		}
248 		i++;
249 	}
250 
251 	assert(i < NUM_SECRETKEY_ATTRS);
252 	template[i].type = CKA_TOKEN;
253 	template[i].pValue = &falsevalue;
254 	template[i].ulValueLen = sizeof (falsevalue);
255 	i++;
256 
257 	assert(i < NUM_SECRETKEY_ATTRS);
258 	template[i].type = CKA_VALUE;
259 	template[i].pValue = (CK_VOID_PTR)rawkey;
260 	template[i].ulValueLen = (CK_ULONG)rawkey_len;
261 	i++;
262 
263 	rv = C_CreateObject(hSession, template, i, obj);
264 	return (rv);
265 }
266 
267 
268 /*
269  * pkcs11_PasswdToPBKD2Object will create a secret key from the given string
270  * (e.g. passphrase) using PKCS#5 Password-Based Key Derivation Function 2
271  * (PBKD2).
272  *
273  * Session must be open.  Salt and iterations use defaults.
274  */
275 CK_RV
276 pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase,
277     size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations,
278     CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags,
279     CK_OBJECT_HANDLE_PTR obj)
280 {
281 	CK_RV rv;
282 	CK_PKCS5_PBKD2_PARAMS params;
283 	CK_MECHANISM mechanism;
284 	CK_KEY_TYPE asym_key_type;
285 	CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping;
286 	CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
287 
288 	if (hSession == NULL || obj == NULL ||
289 	    passphrase == NULL || passphrase_len == 0 ||
290 	    iterations == 0UL) {
291 		return (CKR_ARGUMENTS_BAD);
292 	}
293 
294 	/*
295 	 * Check to make sure key type is not asymmetric.  This function
296 	 * is only applicable to generating secret key.
297 	 */
298 	num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE);
299 	for (i = 0; i < num_asym_mechs; i++) {
300 		rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type);
301 		assert(rv == CKR_OK);
302 		if (key_type == asym_key_type) {
303 			return (CKR_KEY_TYPE_INCONSISTENT);
304 		}
305 	}
306 
307 	/*
308 	 * Key length must either be 0 or the correct size for PBKD of
309 	 * fixed-size secret keys.  However, underlying key generation
310 	 * cannot have CKA_VALUE_LEN set for the key length attribute.
311 	 */
312 	num_fixed_secs =
313 	    sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING);
314 	for (i = 0; i < num_fixed_secs; i++) {
315 		if (key_type == fixed_size_secrets[i].type) {
316 			if (key_len == fixed_size_secrets[i].len) {
317 				key_len = 0;
318 			}
319 			if (key_len == 0) {
320 				break;
321 			}
322 			return (CKR_KEY_SIZE_RANGE);
323 		}
324 	}
325 
326 	if (salt == NULL || salt_len == 0) {
327 		params.saltSource = 0;
328 		params.pSaltSourceData = NULL;
329 		params.ulSaltSourceDataLen = 0;
330 	} else {
331 		params.saltSource = CKZ_SALT_SPECIFIED;
332 		params.pSaltSourceData = salt;
333 		params.ulSaltSourceDataLen = salt_len;
334 	}
335 	params.iterations = iterations;
336 	params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
337 	params.pPrfData = NULL;
338 	params.ulPrfDataLen = 0;
339 	params.pPassword = (CK_UTF8CHAR_PTR)passphrase;
340 	params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len;
341 	/*
342 	 * PKCS#11 spec error, ulPasswordLen should have been pulPasswordLen,
343 	 * or its type should have been CK_ULONG instead of CK_ULONG_PTR,
344 	 * but it's legacy now
345 	 */
346 
347 	mechanism.mechanism = CKM_PKCS5_PBKD2;
348 	mechanism.pParameter = &params;
349 	mechanism.ulParameterLen = sizeof (params);
350 
351 	i = 0;
352 	template[i].type = CKA_CLASS;
353 	template[i].pValue = &objclass;
354 	template[i].ulValueLen = sizeof (objclass);
355 	i++;
356 
357 	assert(i < NUM_SECRETKEY_ATTRS);
358 	template[i].type = CKA_KEY_TYPE;
359 	template[i].pValue = &key_type;
360 	template[i].ulValueLen = sizeof (key_type);
361 	i++;
362 
363 	assert(i < NUM_SECRETKEY_ATTRS);
364 	template[i].type = CKA_TOKEN;
365 	template[i].pValue = &falsevalue;
366 	template[i].ulValueLen = sizeof (falsevalue);
367 	i++;
368 
369 	if (key_len != 0) {
370 		assert(i < NUM_SECRETKEY_ATTRS);
371 		template[i].type = CKA_VALUE_LEN;
372 		template[i].pValue = &key_len;
373 		template[i].ulValueLen = sizeof (key_len);
374 		i++;
375 	}
376 
377 	/*
378 	 * C_GenerateKey may not implicitly set capability attributes,
379 	 * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ...
380 	 */
381 	num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING);
382 	for (j = 0; j < num_mapping; j++) {
383 		assert(i < NUM_SECRETKEY_ATTRS);
384 		template[i].type = mapping[j].attr;
385 		template[i].pValue = (key_flags & ((mapping[j]).flag)) ?
386 		    &truevalue : &falsevalue;
387 		template[i].ulValueLen = sizeof (falsevalue);
388 		i++;
389 	}
390 
391 	rv = C_GenerateKey(hSession, &mechanism, template, i, obj);
392 	return (rv);
393 }
394 
395 /*
396  * pkcs11_ObjectToKey gets the rawkey data from a secret key object.
397  * The caller is responsible to free the allocated rawkey data.
398  *
399  * Optionally the object can be destroyed after the value is retrieved.
400  * As an example, after using pkcs11_PasswdToPBKD2Object() to create a
401  * secret key object from a passphrase, an app may call pkcs11_ObjectToKey
402  * to get the rawkey data.  The intermediate object may no longer be needed
403  * and should be destroyed.
404  */
405 CK_RV
406 pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj,
407     void **rawkey, size_t *rawkey_len, boolean_t destroy_obj)
408 {
409 	CK_RV rv;
410 	CK_ATTRIBUTE template;
411 
412 	if (hSession == NULL || rawkey == NULL || rawkey_len == NULL ||
413 	    *rawkey_len == 0) {
414 		return (CKR_ARGUMENTS_BAD);
415 	}
416 
417 	template.type = CKA_VALUE;
418 	template.pValue = NULL;
419 	template.ulValueLen = 0;
420 
421 	/* First get the size of the rawkey */
422 	rv = C_GetAttributeValue(hSession, obj, &template, 1);
423 	if (rv != CKR_OK) {
424 		return (rv);
425 	}
426 
427 	template.pValue = malloc(template.ulValueLen);
428 	if (template.pValue == NULL) {
429 		return (CKR_HOST_MEMORY);
430 	}
431 
432 	/* Then get the rawkey data */
433 	rv = C_GetAttributeValue(hSession, obj, &template, 1);
434 	if (rv != CKR_OK) {
435 		free(template.pValue);
436 		return (rv);
437 	}
438 
439 	if (destroy_obj) {
440 		/*
441 		 * Could have asserted rv == CKR_OK, making threaded
442 		 * apps that share objects see stars.  Here mercy is ok.
443 		 */
444 		(void) C_DestroyObject(hSession, obj);
445 	}
446 
447 	*rawkey = template.pValue;
448 	*rawkey_len = template.ulValueLen;
449 
450 	return (CKR_OK);
451 }
452 
453 /*
454  * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the
455  * given passphrase.  The caller is responsible to free the allocated
456  * rawkey data.
457  */
458 CK_RV
459 pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase,
460     size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type,
461     CK_ULONG key_len, void **rawkey, size_t *rawkey_len)
462 {
463 	CK_RV rv;
464 	CK_OBJECT_HANDLE obj;
465 
466 	rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len,
467 	    salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0,
468 	    &obj);
469 	if (rv != CKR_OK)
470 		return (rv);
471 	rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE);
472 	return (rv);
473 }
474