xref: /illumos-gate/usr/src/lib/pkcs11/libpkcs11/common/metaKeys.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 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 
260 	CK_MECHANISM metaMech;
261 	CK_OBJECT_HANDLE *phBaseKey2 = NULL;
262 	CK_X9_42_DH2_DERIVE_PARAMS x942_params, *x9_tmpptr;
263 	CK_ECDH2_DERIVE_PARAMS ecdh_params, *ec_tmpptr;
264 	CK_SSL3_KEY_MAT_OUT *ssl_key_mat;
265 
266 	if (pMech == NULL) {
267 		return (CKR_ARGUMENTS_BAD);
268 	}
269 
270 	/*
271 	 * Special case: Normally, the caller must always provide storage
272 	 * for the derived key handle at phKey. Two (related) mechanisms
273 	 * are special, in that multiple keys are instead returned via
274 	 * pMech->pParameter. In these cases the spec says (see 12.38.4
275 	 * and 12.39.4) that phKey should be a NULL pointer, as it is not used.
276 	 */
277 	if (pMech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
278 	    pMech->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) {
279 		CK_SSL3_KEY_MAT_PARAMS *keyparams =
280 			(CK_SSL3_KEY_MAT_PARAMS*)pMech->pParameter;
281 
282 		if ((keyparams == NULL) || (pMech->ulParameterLen
283 		    != sizeof (CK_SSL3_KEY_MAT_PARAMS))) {
284 			return (CKR_ARGUMENTS_BAD);
285 		}
286 
287 		ssl_key_mat = keyparams->pReturnedKeyMaterial;
288 		if (ssl_key_mat == NULL) {
289 			return (CKR_ARGUMENTS_BAD);
290 		}
291 
292 		ssl_keys = B_TRUE;
293 	} else {
294 		if (phKey == NULL) {
295 			return (CKR_ARGUMENTS_BAD);
296 		}
297 	}
298 
299 	rv = meta_handle2session(hSession, &session);
300 	if (rv != CKR_OK)
301 		return (rv);
302 
303 	rv = meta_handle2object(hBaseKey, &basekey1);
304 	if (rv != CKR_OK)
305 		goto finish;
306 
307 
308 	/*
309 	 * A few oddball mechanisms pass a 2nd object handle in the parameters.
310 	 * Here we validate that handle, and create a duplicate copy of the
311 	 * mechanism and parameters. This is done because the application
312 	 * does not expect these values to be changing, and could be using the
313 	 * same data in multiple threads (eg concurrent calls to C_DeriveKey).
314 	 * We copy the data to make sure there are no MT-Safe problems.
315 	 */
316 	switch (pMech->mechanism) {
317 
318 	    case CKM_ECMQV_DERIVE:
319 		/* uses CK_ECDH2_DERIVE_PARAMS struct as the parameter */
320 
321 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
322 		    != sizeof (CK_ECDH2_DERIVE_PARAMS))) {
323 			rv = CKR_ARGUMENTS_BAD;
324 			goto finish;
325 		}
326 
327 		/* Duplicate the mechanism and paramaters */
328 		ec_tmpptr = (CK_ECDH2_DERIVE_PARAMS *)pMech->pParameter;
329 		ecdh_params = *ec_tmpptr;
330 		metaMech = *pMech;
331 		metaMech.pParameter = &ecdh_params;
332 		pMech = &metaMech;
333 
334 		/* Get the key the application is providing */
335 		phBaseKey2 = &ecdh_params.hPrivateData;
336 		break;
337 
338 	    case CKM_X9_42_DH_HYBRID_DERIVE:
339 	    case CKM_X9_42_MQV_DERIVE:
340 		/* both use CK_X9_42_DH2_DERIVE_PARAMS as the parameter */
341 
342 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
343 		    != sizeof (CK_X9_42_DH2_DERIVE_PARAMS))) {
344 			rv = CKR_ARGUMENTS_BAD;
345 			goto finish;
346 		}
347 
348 		/* Duplicate the mechanism and paramaters */
349 		x9_tmpptr = (CK_X9_42_DH2_DERIVE_PARAMS *)pMech->pParameter;
350 		x942_params = *x9_tmpptr;
351 		metaMech = *pMech;
352 		metaMech.pParameter  = &x942_params;
353 		pMech = &metaMech;
354 
355 		/* Get the key the application is providing */
356 		phBaseKey2 = &x942_params.hPrivateData;
357 		break;
358 
359 	    case CKM_CONCATENATE_BASE_AND_KEY:
360 		/* uses a CK_OBJECT_HANDLE as the parameter */
361 
362 		if ((pMech->pParameter == NULL) || (pMech->ulParameterLen
363 		    != sizeof (CK_OBJECT_HANDLE))) {
364 			rv = CKR_ARGUMENTS_BAD;
365 			goto finish;
366 		}
367 
368 		/* Duplicate the mechanism and paramaters */
369 		metaMech = *pMech;
370 		pMech = &metaMech;
371 
372 		/* Get the key the application is providing */
373 		phBaseKey2 = (CK_OBJECT_HANDLE *) &metaMech.pParameter;
374 		break;
375 
376 	    default:
377 		/* nothing special to do. */
378 		break;
379 	}
380 
381 	if (phBaseKey2) {
382 		rv = meta_handle2object(*phBaseKey2, &basekey2);
383 		if (rv != CKR_OK)
384 			goto finish;
385 	}
386 
387 	/*
388 	 * Allocate meta objects to store the derived key(s). Normally just
389 	 * a single key is created, but the SSL/TLS mechanisms generate four.
390 	 */
391 	rv = meta_object_alloc(session, &newKey1);
392 	if (rv != CKR_OK)
393 		goto finish;
394 
395 	if (ssl_keys) {
396 		rv = meta_object_alloc(session, &newKey2);
397 		if (rv != CKR_OK)
398 			goto finish;
399 		rv = meta_object_alloc(session, &newKey3);
400 		if (rv != CKR_OK)
401 			goto finish;
402 		rv = meta_object_alloc(session, &newKey4);
403 		if (rv != CKR_OK)
404 			goto finish;
405 	}
406 
407 
408 	/* Perform the actual key derive operation. */
409 	rv = meta_derive_key(session, pMech, basekey1, basekey2, phBaseKey2,
410 		pTemplate, ulAttributeCount,
411 		newKey1, newKey2, newKey3, newKey4);
412 	if (rv != CKR_OK)
413 		goto finish;
414 
415 	/* Make the derived key(s) active and visible to other threads. */
416 	meta_object_activate(newKey1);
417 	if (ssl_keys) {
418 		meta_object_activate(newKey2);
419 		meta_object_activate(newKey3);
420 		meta_object_activate(newKey4);
421 
422 		ssl_key_mat->hClientMacSecret = (CK_OBJECT_HANDLE) newKey1;
423 		ssl_key_mat->hServerMacSecret = (CK_OBJECT_HANDLE) newKey2;
424 		ssl_key_mat->hClientKey = (CK_OBJECT_HANDLE) newKey3;
425 		ssl_key_mat->hServerKey = (CK_OBJECT_HANDLE) newKey4;
426 		/* phKey is not used (it's NULL) for these SSL/TLS mechs. */
427 	} else {
428 		*phKey = (CK_OBJECT_HANDLE) newKey1;
429 	}
430 
431 finish:
432 	if (rv != CKR_OK) {
433 		if (newKey1)
434 			(void) meta_object_dealloc(newKey1, B_TRUE);
435 		if (newKey2)
436 			(void) meta_object_dealloc(newKey2, B_TRUE);
437 		if (newKey3)
438 			(void) meta_object_dealloc(newKey3, B_TRUE);
439 		if (newKey4)
440 			(void) meta_object_dealloc(newKey4, B_TRUE);
441 	}
442 
443 	if (basekey1)
444 		OBJRELEASE(basekey1);
445 	if (basekey2)
446 		OBJRELEASE(basekey2);
447 	REFRELEASE(session);
448 
449 	return (rv);
450 }
451