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