xref: /illumos-gate/usr/src/lib/pkcs11/libpkcs11/common/metaKeys.c (revision 33efde4275d24731ef87927237b0ffb0630b6b2d)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Key Management Functions
28  * (as defined in PKCS#11 spec section 11.14)
29  */
30 
31 #include "metaGlobal.h"
32 
33 
34 /*
35  * meta_GenerateKey
36  *
37  */
38 CK_RV
meta_GenerateKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phKey)39 meta_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
40     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
41 {
42 	CK_RV rv;
43 	meta_session_t *session;
44 	meta_object_t *key = NULL;
45 
46 	if (pMechanism == NULL || phKey == NULL)
47 		return (CKR_ARGUMENTS_BAD);
48 
49 	rv = meta_handle2session(hSession, &session);
50 	if (rv != CKR_OK)
51 		return (rv);
52 
53 
54 	rv = meta_object_alloc(session, &key);
55 	if (rv != CKR_OK)
56 		goto finish;
57 
58 	rv = meta_generate_keys(session, pMechanism, pTemplate, ulCount, key,
59 	    NULL, 0, NULL);
60 	if (rv != CKR_OK)
61 		goto finish;
62 
63 	meta_object_activate(key);
64 
65 	*phKey = (CK_OBJECT_HANDLE) key;
66 
67 finish:
68 	if (rv != CKR_OK) {
69 		if (key)
70 			(void) meta_object_dealloc(session, key, B_TRUE);
71 	}
72 
73 	REFRELEASE(session);
74 
75 	return (rv);
76 }
77 
78 
79 /*
80  * meta_GenerateKeyPair
81  *
82  */
83 CK_RV
meta_GenerateKeyPair(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,CK_OBJECT_HANDLE_PTR phPublicKey,CK_OBJECT_HANDLE_PTR phPrivateKey)84 meta_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
85     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
86     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
87     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
88 {
89 	CK_RV rv;
90 	meta_session_t *session;
91 	meta_object_t *key1 = NULL, *key2 = NULL;
92 
93 	if (pMechanism == NULL || phPublicKey == NULL || phPrivateKey == NULL)
94 		return (CKR_ARGUMENTS_BAD);
95 
96 	rv = meta_handle2session(hSession, &session);
97 	if (rv != CKR_OK)
98 		return (rv);
99 
100 
101 	rv = meta_object_alloc(session, &key1);
102 	if (rv != CKR_OK)
103 		goto finish;
104 
105 	rv = meta_object_alloc(session, &key2);
106 	if (rv != CKR_OK)
107 		goto finish;
108 
109 	rv = meta_generate_keys(session, pMechanism,
110 	    pPublicKeyTemplate, ulPublicKeyAttributeCount, key1,
111 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount, key2);
112 	if (rv != CKR_OK)
113 		goto finish;
114 
115 	meta_object_activate(key1);
116 	meta_object_activate(key2);
117 
118 	*phPublicKey = (CK_OBJECT_HANDLE) key1;
119 	*phPrivateKey = (CK_OBJECT_HANDLE) key2;
120 
121 finish:
122 	if (rv != CKR_OK) {
123 		if (key1)
124 			(void) meta_object_dealloc(session, key1, B_TRUE);
125 		if (key2)
126 			(void) meta_object_dealloc(session, key2, B_TRUE);
127 	}
128 
129 	REFRELEASE(session);
130 
131 	return (rv);
132 }
133 
134 
135 /*
136  * meta_WrapKey
137  *
138  */
139 CK_RV
meta_WrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hWrappingKey,CK_OBJECT_HANDLE hKey,CK_BYTE_PTR pWrappedKey,CK_ULONG_PTR pulWrappedKeyLen)140 meta_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
141     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
142     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
143 {
144 	CK_RV rv;
145 	meta_session_t *session;
146 	meta_object_t *wrappingKey, *inputKey;
147 
148 	if (pMechanism == NULL || pulWrappedKeyLen == NULL)
149 		return (CKR_ARGUMENTS_BAD);
150 
151 	rv = meta_handle2session(hSession, &session);
152 	if (rv != CKR_OK)
153 		return (rv);
154 
155 	rv = meta_handle2object(hKey, &inputKey);
156 	if (rv != CKR_OK) {
157 		REFRELEASE(session);
158 		return (rv);
159 	}
160 
161 	rv = meta_handle2object(hWrappingKey, &wrappingKey);
162 	if (rv != CKR_OK) {
163 		OBJRELEASE(inputKey);
164 		REFRELEASE(session);
165 		return (rv);
166 	}
167 
168 	rv = meta_wrap_key(session, pMechanism, wrappingKey,
169 	    inputKey, pWrappedKey, pulWrappedKeyLen);
170 
171 	OBJRELEASE(inputKey);
172 	OBJRELEASE(wrappingKey);
173 	REFRELEASE(session);
174 
175 	return (rv);
176 }
177 
178 
179 /*
180  * meta_UnwrapKey
181  *
182  */
183 CK_RV
meta_UnwrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hUnwrappingKey,CK_BYTE_PTR pWrappedKey,CK_ULONG ulWrappedKeyLen,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)184 meta_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
185     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
186     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
187     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
188 {
189 	CK_RV rv;
190 	meta_session_t *session;
191 	meta_object_t *unwrappingKey, *outputKey = NULL;
192 
193 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL)
194 		return (CKR_ARGUMENTS_BAD);
195 
196 	rv = meta_handle2session(hSession, &session);
197 	if (rv != CKR_OK)
198 		return (rv);
199 
200 	rv = meta_handle2object(hUnwrappingKey, &unwrappingKey);
201 	if (rv != CKR_OK) {
202 		REFRELEASE(session);
203 		return (rv);
204 	}
205 
206 	rv = meta_object_alloc(session, &outputKey);
207 	if (rv != CKR_OK)
208 		goto finish;
209 
210 	(void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount,
211 	    &(outputKey->isToken));
212 
213 	rv = meta_unwrap_key(session, pMechanism, unwrappingKey,
214 	    pWrappedKey, ulWrappedKeyLen,
215 	    pTemplate, ulAttributeCount, outputKey);
216 	if (rv != CKR_OK)
217 		goto finish;
218 
219 	meta_object_activate(outputKey);
220 
221 	*phKey = (CK_OBJECT_HANDLE) outputKey;
222 
223 finish:
224 	if (rv != CKR_OK) {
225 		if (outputKey)
226 			(void) meta_object_dealloc(session, outputKey, B_TRUE);
227 	}
228 
229 	OBJRELEASE(unwrappingKey);
230 	REFRELEASE(session);
231 
232 	return (rv);
233 }
234 
235 
236 /*
237  * meta_DeriveKey
238  *
239  * This function is a bit gross because of PKCS#11 kludges that pass extra
240  * object handles in some mechanism parameters. It probably needs to be
241  * broken up into more managable pieces.
242  */
243 CK_RV
meta_DeriveKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hBaseKey,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)244 meta_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
245     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
246     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
247 {
248 	CK_RV rv;
249 	CK_MECHANISM *pMech = pMechanism;
250 	meta_session_t *session;
251 	meta_object_t *basekey1 = NULL, *basekey2 = NULL;
252 	meta_object_t *newKey1 = NULL, *newKey2 = NULL, *newKey3 = NULL,
253 	    *newKey4 = NULL;
254 	boolean_t ssl_keys = B_FALSE;
255 	boolean_t tlsprf = B_FALSE;
256 
257 	CK_MECHANISM metaMech;
258 	CK_OBJECT_HANDLE *phBaseKey2 = NULL;
259 	CK_X9_42_DH2_DERIVE_PARAMS x942_params, *x9_tmpptr;
260 	CK_ECDH2_DERIVE_PARAMS ecdh_params, *ec_tmpptr;
261 	CK_SSL3_KEY_MAT_OUT *ssl_key_mat;
262 	CK_SSL3_KEY_MAT_PARAMS *keyparams;
263 
264 	if (pMech == NULL) {
265 		return (CKR_ARGUMENTS_BAD);
266 	}
267 
268 	/*
269 	 * Special case: Normally, the caller must always provide storage
270 	 * for the derived key handle at phKey. Two (related) mechanisms
271 	 * are special, in that multiple keys are instead returned via
272 	 * pMech->pParameter. In these cases the spec says (see 12.38.4
273 	 * and 12.39.4) that phKey should be a NULL pointer, as it is not used.
274 	 */
275 	switch (pMech->mechanism) {
276 	case CKM_SSL3_KEY_AND_MAC_DERIVE:
277 	case CKM_TLS_KEY_AND_MAC_DERIVE:
278 		keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMech->pParameter;
279 
280 		if ((keyparams == NULL) || (pMech->ulParameterLen
281 		    != sizeof (CK_SSL3_KEY_MAT_PARAMS)))
282 			return (CKR_ARGUMENTS_BAD);
283 
284 		ssl_key_mat = keyparams->pReturnedKeyMaterial;
285 		if (ssl_key_mat == NULL)
286 			return (CKR_ARGUMENTS_BAD);
287 
288 		ssl_keys = B_TRUE;
289 		break;
290 
291 	case CKM_TLS_PRF:
292 		tlsprf = B_TRUE;
293 		break;
294 
295 	default:
296 		if (phKey == NULL)
297 			return (CKR_ARGUMENTS_BAD);
298 	};
299 
300 	rv = meta_handle2session(hSession, &session);
301 	if (rv != CKR_OK)
302 		return (rv);
303 
304 	rv = meta_handle2object(hBaseKey, &basekey1);
305 	if (rv != CKR_OK)
306 		goto finish;
307 
308 
309 	/*
310 	 * A few oddball mechanisms pass a 2nd object handle in the parameters.
311 	 * Here we validate that handle, and create a duplicate copy of the
312 	 * mechanism and parameters. This is done because the application
313 	 * does not expect these values to be changing, and could be using the
314 	 * same data in multiple threads (eg concurrent calls to C_DeriveKey).
315 	 * We copy the data to make sure there are no MT-Safe problems.
316 	 */
317 	switch (pMech->mechanism) {
318 
319 	case CKM_ECMQV_DERIVE:
320 		/* uses CK_ECDH2_DERIVE_PARAMS struct as the parameter */
321 
322 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
323 		    != sizeof (CK_ECDH2_DERIVE_PARAMS))) {
324 			rv = CKR_ARGUMENTS_BAD;
325 			goto finish;
326 		}
327 
328 		/* Duplicate the mechanism and paramaters */
329 		ec_tmpptr = (CK_ECDH2_DERIVE_PARAMS *)pMech->pParameter;
330 		ecdh_params = *ec_tmpptr;
331 		metaMech = *pMech;
332 		metaMech.pParameter = &ecdh_params;
333 		pMech = &metaMech;
334 
335 		/* Get the key the application is providing */
336 		phBaseKey2 = &ecdh_params.hPrivateData;
337 		break;
338 
339 	case CKM_X9_42_DH_HYBRID_DERIVE:
340 	case CKM_X9_42_MQV_DERIVE:
341 		/* both use CK_X9_42_DH2_DERIVE_PARAMS as the parameter */
342 
343 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
344 		    != sizeof (CK_X9_42_DH2_DERIVE_PARAMS))) {
345 			rv = CKR_ARGUMENTS_BAD;
346 			goto finish;
347 		}
348 
349 		/* Duplicate the mechanism and paramaters */
350 		x9_tmpptr = (CK_X9_42_DH2_DERIVE_PARAMS *)pMech->pParameter;
351 		x942_params = *x9_tmpptr;
352 		metaMech = *pMech;
353 		metaMech.pParameter  = &x942_params;
354 		pMech = &metaMech;
355 
356 		/* Get the key the application is providing */
357 		phBaseKey2 = &x942_params.hPrivateData;
358 		break;
359 
360 	case CKM_CONCATENATE_BASE_AND_KEY:
361 		/* uses a CK_OBJECT_HANDLE as the parameter */
362 
363 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
364 		    != sizeof (CK_OBJECT_HANDLE))) {
365 			rv = CKR_ARGUMENTS_BAD;
366 			goto finish;
367 		}
368 
369 		/* Duplicate the mechanism and paramaters */
370 		metaMech = *pMech;
371 		pMech = &metaMech;
372 
373 		/* Get the key the application is providing */
374 		phBaseKey2 = (CK_OBJECT_HANDLE *) &metaMech.pParameter;
375 		break;
376 
377 	default:
378 		/* nothing special to do. */
379 		break;
380 	}
381 
382 	if (phBaseKey2) {
383 		rv = meta_handle2object(*phBaseKey2, &basekey2);
384 		if (rv != CKR_OK)
385 			goto finish;
386 	}
387 
388 	/*
389 	 * Allocate meta objects to store the derived key(s). Normally just
390 	 * a single key is created, but the SSL/TLS mechanisms generate four.
391 	 */
392 	rv = meta_object_alloc(session, &newKey1);
393 	if (rv != CKR_OK)
394 		goto finish;
395 
396 	if (ssl_keys) {
397 		rv = meta_object_alloc(session, &newKey2);
398 		if (rv != CKR_OK)
399 			goto finish;
400 		rv = meta_object_alloc(session, &newKey3);
401 		if (rv != CKR_OK)
402 			goto finish;
403 		rv = meta_object_alloc(session, &newKey4);
404 		if (rv != CKR_OK)
405 			goto finish;
406 	}
407 
408 
409 	/* Perform the actual key derive operation. */
410 	rv = meta_derive_key(session, pMech, basekey1, basekey2, phBaseKey2,
411 	    pTemplate, ulAttributeCount, newKey1, newKey2, newKey3, newKey4);
412 	if (rv != CKR_OK)
413 		goto finish;
414 
415 	if (tlsprf) {
416 		(void) meta_object_dealloc(session, newKey1, B_TRUE);
417 		newKey1 = NULL;
418 		/* phKey isn't used (is NULL) for mechanism CKM_TLS_PRF. */
419 
420 	} else {
421 		/* Make derived key(s) active and visible to other threads. */
422 		meta_object_activate(newKey1);
423 		if (ssl_keys) {
424 			meta_object_activate(newKey2);
425 			meta_object_activate(newKey3);
426 			meta_object_activate(newKey4);
427 
428 			ssl_key_mat->hClientMacSecret
429 			    = (CK_OBJECT_HANDLE) newKey1;
430 			ssl_key_mat->hServerMacSecret
431 			    = (CK_OBJECT_HANDLE) newKey2;
432 			ssl_key_mat->hClientKey = (CK_OBJECT_HANDLE) newKey3;
433 			ssl_key_mat->hServerKey = (CK_OBJECT_HANDLE) newKey4;
434 			/* phKey isn't used (is NULL) for these SSL/TLS mechs */
435 
436 		} else {
437 			*phKey = (CK_OBJECT_HANDLE) newKey1;
438 		}
439 	}
440 
441 finish:
442 	if (rv != CKR_OK) {
443 		if (newKey1)
444 			(void) meta_object_dealloc(session, newKey1, B_TRUE);
445 		if (newKey2)
446 			(void) meta_object_dealloc(session, newKey2, B_TRUE);
447 		if (newKey3)
448 			(void) meta_object_dealloc(session, newKey3, B_TRUE);
449 		if (newKey4)
450 			(void) meta_object_dealloc(session, newKey4, B_TRUE);
451 	}
452 
453 	if (basekey1)
454 		OBJRELEASE(basekey1);
455 	if (basekey2)
456 		OBJRELEASE(basekey2);
457 	REFRELEASE(session);
458 
459 	return (rv);
460 }
461