1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
7  */
8 
9 #pragma ident	"%Z%%M%	%I%	%E% SMI"
10 
11 #include <kmfapiP.h>
12 #include <sha1.h>
13 #include <security/cryptoki.h>
14 
15 #include <algorithm.h>
16 #include <ber_der.h>
17 
18 #define	MAX_PUBLIC_KEY_TEMPLATES    (20)
19 #define	MAX_PRIVATE_KEY_TEMPLATES   (24)
20 #define	MAX_SECRET_KEY_TEMPLATES    (24)
21 
22 static KMF_RETURN
23 create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech,
24 	CK_FLAGS wanted_flags)
25 {
26 	CK_RV rv;
27 	KMF_RETURN ret;
28 	KMF_RETURN kmf_rv = KMF_OK;
29 	CK_SLOT_ID_PTR pSlotList;
30 	CK_ULONG pulCount;
31 	CK_MECHANISM_INFO info;
32 	int i;
33 
34 	ret = init_pk11();
35 
36 	if (ret != KMF_OK)
37 		return (ret);
38 
39 	rv = C_GetSlotList(0, NULL, &pulCount);
40 	if (rv != CKR_OK) {
41 		kmf_rv = KMF_ERR_UNINITIALIZED;
42 		goto out;
43 	}
44 
45 	pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID));
46 	if (pSlotList == NULL) {
47 		kmf_rv = KMF_ERR_MEMORY;
48 		goto out;
49 	}
50 
51 	rv = C_GetSlotList(0, pSlotList, &pulCount);
52 	if (rv != CKR_OK) {
53 		kmf_rv = KMF_ERR_UNINITIALIZED;
54 		goto out;
55 	}
56 
57 	for (i = 0; i < pulCount; i++) {
58 		rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info);
59 		if (rv == CKR_OK && (info.flags & wanted_flags))
60 			break;
61 	}
62 	if (i < pulCount) {
63 		rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION,
64 			NULL, NULL, sessionp);
65 
66 		if (rv != CKR_OK) {
67 			kmf_rv = KMF_ERR_UNINITIALIZED;
68 		}
69 	} else {
70 		kmf_rv = KMF_ERR_UNINITIALIZED;
71 	}
72 
73 out:
74 	if (pSlotList != NULL)
75 		free(pSlotList);
76 	return (kmf_rv);
77 
78 }
79 
80 /*
81  * Name: PKCS_AddTemplate
82  *
83  * Description:
84  *  Adds a CK_ATTRIBUTE value to an existing array of CK_ATTRIBUTES. Will
85  *  not expand the array beyond the maximum specified size.
86  *
87  * Returns:
88  *  TRUE - Attribute value succesfully added.
89  *  FALSE - Maximum array size would be exceded.
90  */
91 static int
92 PKCS_AddTemplate(CK_ATTRIBUTE *pTemplate,
93 	CK_ULONG *ckNumTemplates,
94 	CK_ULONG ckMaxTemplates,
95 	CK_ATTRIBUTE_TYPE ckAttribCode,
96 	CK_BYTE * pckBuffer,
97 	CK_ULONG ckBufferLen)
98 {
99 	if (*ckNumTemplates >= ckMaxTemplates) {
100 		return (FALSE);
101 	}
102 
103 	pTemplate[*ckNumTemplates].type = ckAttribCode;
104 	pTemplate[*ckNumTemplates].pValue = pckBuffer;
105 	pTemplate[*ckNumTemplates].ulValueLen = ckBufferLen;
106 	(*ckNumTemplates)++;
107 
108 	return (TRUE);
109 }
110 
111 /*
112  * Convert an SPKI data record to PKCS#11
113  * public key object.
114  */
115 static KMF_RETURN
116 PKCS_CreatePublicKey(
117 	const KMF_X509_SPKI *pKey,
118 	CK_SESSION_HANDLE ckSession,
119 	CK_OBJECT_HANDLE *pckPublicKey)
120 {
121 	KMF_RETURN mrReturn = KMF_OK;
122 	CK_RV ckRv;
123 
124 	CK_ATTRIBUTE ckTemplate[MAX_PUBLIC_KEY_TEMPLATES];
125 	CK_ULONG ckNumTemplates = 0;
126 
127 	/* Common object attributes */
128 	CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
129 	CK_BBOOL ckToken = 0;
130 	CK_BBOOL ckPrivate = 0;
131 
132 	/* Common key attributes */
133 	CK_KEY_TYPE ckKeyType;
134 	CK_BBOOL ckDerive = CK_FALSE;
135 
136 	/* Common public key attributes */
137 	CK_BBOOL ckEncrypt = 1;
138 	CK_BBOOL ckVerify = 1;
139 
140 	CK_BBOOL ckVerifyRecover = CK_FALSE;
141 	CK_BBOOL ckWrap = CK_FALSE;
142 
143 	/* Key part array */
144 	KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
145 	uint32_t i, uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
146 	KMF_ALGORITHM_INDEX AlgorithmId;
147 
148 	/* Parse the keyblob */
149 	(void) memset(KeyParts, 0, sizeof (KeyParts));
150 
151 	AlgorithmId = X509_AlgorithmOidToAlgId((KMF_OID *)
152 		&pKey->algorithm.algorithm);
153 
154 	mrReturn = ExtractSPKIData(pKey, AlgorithmId, KeyParts, &uNumKeyParts);
155 
156 	if (mrReturn != KMF_OK)
157 		return (mrReturn);
158 
159 	/* Fill in the common object attributes */
160 	if (!PKCS_AddTemplate(ckTemplate,
161 		&ckNumTemplates,
162 		MAX_PUBLIC_KEY_TEMPLATES,
163 		CKA_CLASS,
164 		(CK_BYTE *)&ckObjClass,
165 		sizeof (ckObjClass)) ||
166 		!PKCS_AddTemplate(ckTemplate,
167 			&ckNumTemplates,
168 			MAX_PUBLIC_KEY_TEMPLATES,
169 			CKA_TOKEN,
170 			(CK_BYTE *)&ckToken,
171 			sizeof (ckToken)) ||
172 		!PKCS_AddTemplate(ckTemplate,
173 			&ckNumTemplates,
174 			MAX_PUBLIC_KEY_TEMPLATES,
175 			CKA_PRIVATE,
176 			(CK_BYTE *)&ckPrivate,
177 			sizeof (ckPrivate))) {
178 		mrReturn = KMF_ERR_INTERNAL;
179 		goto cleanup;
180 	}
181 
182 	/* Fill in the common key attributes */
183 	if (!PKCS_ConvertAlgorithmId2PKCSKeyType(AlgorithmId,
184 		&ckKeyType)) {
185 		goto cleanup;
186 	}
187 	if (!PKCS_AddTemplate(ckTemplate,
188 		&ckNumTemplates,
189 		MAX_PUBLIC_KEY_TEMPLATES,
190 		CKA_KEY_TYPE,
191 		(CK_BYTE *)&ckKeyType,
192 		sizeof (ckKeyType)) ||
193 	    !PKCS_AddTemplate(ckTemplate,
194 		&ckNumTemplates,
195 		MAX_PUBLIC_KEY_TEMPLATES,
196 		CKA_DERIVE,
197 		(CK_BYTE *)&ckDerive,
198 		sizeof (ckDerive))) {
199 		mrReturn = KMF_ERR_INTERNAL;
200 		goto cleanup;
201 	}
202 
203 	/* Add common public key attributes */
204 	if (!PKCS_AddTemplate(ckTemplate,
205 		&ckNumTemplates,
206 		MAX_PUBLIC_KEY_TEMPLATES,
207 		CKA_ENCRYPT,
208 		(CK_BYTE *)&ckEncrypt,
209 		sizeof (ckEncrypt)) ||
210 	    !PKCS_AddTemplate(ckTemplate,
211 		&ckNumTemplates,
212 		MAX_PUBLIC_KEY_TEMPLATES,
213 		CKA_VERIFY,
214 		(CK_BYTE *)&ckVerify,
215 		sizeof (ckVerify)) ||
216 	    !PKCS_AddTemplate(ckTemplate,
217 		&ckNumTemplates,
218 		MAX_PUBLIC_KEY_TEMPLATES,
219 		CKA_VERIFY_RECOVER,
220 		(CK_BYTE *)&ckVerifyRecover,
221 		sizeof (ckVerifyRecover)) ||
222 	    !PKCS_AddTemplate(ckTemplate,
223 		&ckNumTemplates,
224 		MAX_PUBLIC_KEY_TEMPLATES,
225 		CKA_WRAP,
226 		(CK_BYTE *)&ckWrap,
227 		sizeof (ckWrap))) {
228 		mrReturn = KMF_ERR_INTERNAL;
229 		goto cleanup;
230 	}
231 
232 	/* Add algorithm specific attributes */
233 	switch (ckKeyType) {
234 	case CKK_RSA:
235 		if (!PKCS_AddTemplate(ckTemplate,
236 			&ckNumTemplates,
237 			MAX_PUBLIC_KEY_TEMPLATES,
238 			CKA_MODULUS,
239 			(CK_BYTE *)KeyParts[KMF_RSA_MODULUS].Data,
240 			(CK_ULONG)KeyParts[KMF_RSA_MODULUS].Length) ||
241 		!PKCS_AddTemplate(ckTemplate,
242 			&ckNumTemplates,
243 			MAX_PUBLIC_KEY_TEMPLATES,
244 			CKA_PUBLIC_EXPONENT,
245 			(CK_BYTE *)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Data,
246 			(CK_ULONG)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Length)) {
247 		mrReturn = KMF_ERR_INTERNAL;
248 		goto cleanup;
249 		}
250 		break;
251 	case CKK_DSA:
252 		if (!PKCS_AddTemplate(ckTemplate,
253 			&ckNumTemplates,
254 			MAX_PUBLIC_KEY_TEMPLATES,
255 			CKA_PRIME,
256 			(CK_BYTE *)KeyParts[KMF_DSA_PRIME].Data,
257 			(CK_ULONG)KeyParts[KMF_DSA_PRIME].Length) ||
258 		!PKCS_AddTemplate(ckTemplate,
259 			&ckNumTemplates,
260 			MAX_PUBLIC_KEY_TEMPLATES,
261 			CKA_SUBPRIME,
262 			(CK_BYTE *)KeyParts[KMF_DSA_SUB_PRIME].Data,
263 			(CK_ULONG)KeyParts[KMF_DSA_SUB_PRIME].Length) ||
264 		!PKCS_AddTemplate(ckTemplate,
265 			&ckNumTemplates,
266 			MAX_PUBLIC_KEY_TEMPLATES,
267 			CKA_BASE,
268 			(CK_BYTE *)KeyParts[KMF_DSA_BASE].Data,
269 			(CK_ULONG)KeyParts[KMF_DSA_BASE].Length) ||
270 		!PKCS_AddTemplate(ckTemplate,
271 			&ckNumTemplates,
272 			MAX_PUBLIC_KEY_TEMPLATES,
273 			CKA_VALUE,
274 			(CK_BYTE *)KeyParts[KMF_DSA_PUBLIC_VALUE].Data,
275 			(CK_ULONG)KeyParts[KMF_DSA_PUBLIC_VALUE].Length)) {
276 		mrReturn = KMF_ERR_INTERNAL;
277 		goto cleanup;
278 		}
279 		break;
280 	default:
281 		mrReturn = KMF_ERR_BAD_PARAMETER;
282 	}
283 
284 	if (mrReturn == KMF_OK) {
285 		/* Instantiate the object */
286 		ckRv = C_CreateObject(ckSession,
287 				ckTemplate,
288 				ckNumTemplates,
289 				pckPublicKey);
290 		if (ckRv != CKR_OK)
291 			mrReturn = KMF_ERR_INTERNAL;
292 	}
293 
294 cleanup:
295 	for (i = 0; i < uNumKeyParts; i++) {
296 		KMF_FreeData(&KeyParts[i]);
297 	}
298 
299 	return (mrReturn);
300 }
301 
302 /*
303  * PKCS_AcquirePublicKeyHandle
304  *
305  *   Given an assymetric key keyblob, attempts to find the appropriate
306  *    public key.
307  *
308  *  Methods of finding the public key:
309  *  - Public Key with data present:
310  *    Parses the key and creates a temporary session object.
311  *  - Public Key with handle:
312  *    The handle is type converted and returned. Validity of the handle is
313  *    not checked.
314  *  - Public Key with label:
315  *    Attempts to find a public key with the corresponding label.
316  */
317 KMF_RETURN
318 PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession,
319 	const KMF_X509_SPKI *pKey,
320 	CK_KEY_TYPE ckRequestedKeyType,
321 	CK_OBJECT_HANDLE *pckKeyHandle,
322 	KMF_BOOL *pbTemporary)
323 {
324 	KMF_RETURN mrReturn = KMF_OK;
325 
326 
327 	/* Key searching variables */
328 	CK_OBJECT_HANDLE ckKeyHandle;
329 	CK_OBJECT_CLASS ckObjClass;
330 	CK_KEY_TYPE ckKeyType;
331 	CK_ATTRIBUTE ckTemplate[3];
332 	CK_ULONG ckNumTemplates;
333 	static const CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
334 		sizeof (CK_ATTRIBUTE));
335 	CK_RV ckRv;
336 
337 	/* Extract the data from the SPKI into individual fields */
338 	mrReturn = PKCS_CreatePublicKey(pKey, ckSession, &ckKeyHandle);
339 	if (mrReturn != KMF_OK)
340 		return (mrReturn);
341 
342 	*pbTemporary = KMF_TRUE;
343 
344 	/* Fetch the key class and algorithm from the object */
345 	ckNumTemplates = 0;
346 	if (!PKCS_AddTemplate(ckTemplate,
347 			&ckNumTemplates,
348 			ckMaxTemplates,
349 			CKA_CLASS,
350 			(CK_BYTE *)&ckObjClass,
351 			sizeof (ckObjClass)) ||
352 		!PKCS_AddTemplate(ckTemplate,
353 			&ckNumTemplates,
354 			ckMaxTemplates,
355 			CKA_KEY_TYPE,
356 			(CK_BYTE *)&ckKeyType,
357 			sizeof (ckKeyType))) {
358 		return (KMF_ERR_INTERNAL);
359 	}
360 	ckRv = C_GetAttributeValue(ckSession,
361 				ckKeyHandle,
362 				ckTemplate,
363 				ckNumTemplates);
364 	if (ckRv != CKR_OK) {
365 		return (ckRv);
366 	}
367 
368 	/* Make sure the results match the expected values */
369 	if ((ckKeyType != ckRequestedKeyType) ||
370 		(ckObjClass != CKO_PUBLIC_KEY)) {
371 		if (*pbTemporary == KMF_TRUE) {
372 			(void) C_DestroyObject(ckSession, ckKeyHandle);
373 		}
374 
375 		return (KMF_ERR_BAD_KEY_FORMAT);
376 	}
377 
378 	/* Set the return values */
379 	*pckKeyHandle = ckKeyHandle;
380 
381 	return (KMF_OK);
382 }
383 
384 KMF_SIGNATURE_MODE
385 PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX AlgId)
386 {
387 	KMF_SIGNATURE_MODE AlgMode;
388 
389 	switch (AlgId) {
390 		case KMF_ALGID_RSA:
391 		case KMF_ALGID_MD5WithRSA:
392 		case KMF_ALGID_MD2WithRSA:
393 		case KMF_ALGID_SHA1WithRSA:
394 			AlgMode = KMF_ALGMODE_PKCS1_EMSA_V15;
395 			break;
396 		default:
397 			AlgMode = KMF_ALGMODE_NONE;
398 			break;
399 	}
400 
401 	return (AlgMode);
402 }
403 
404 KMF_RETURN
405 PKCS_VerifyData(KMF_HANDLE_T kmfh,
406 		KMF_ALGORITHM_INDEX AlgorithmId,
407 		KMF_X509_SPKI *keyp,
408 		KMF_DATA *data,
409 		KMF_DATA *signed_data)
410 {
411 	KMF_RETURN rv = KMF_OK;
412 	PKCS_ALGORITHM_MAP *pAlgMap = NULL;
413 	CK_RV ckRv;
414 	CK_MECHANISM ckMechanism;
415 	CK_OBJECT_HANDLE ckKeyHandle;
416 	KMF_BOOL	bTempKey;
417 	CK_SESSION_HANDLE ckSession = 0;
418 
419 	if (AlgorithmId == KMF_ALGID_NONE)
420 		return (KMF_ERR_BAD_ALGORITHM);
421 
422 	pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
423 		AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId));
424 
425 	if (!pAlgMap)
426 		return (KMF_ERR_BAD_ALGORITHM);
427 
428 	rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism,
429 		CKF_VERIFY);
430 
431 	if (rv != KMF_OK)
432 		return (rv);
433 
434 	/* Fetch the verifying key */
435 	rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
436 		pAlgMap->key_type, &ckKeyHandle, &bTempKey);
437 
438 	if (rv != KMF_OK) {
439 		(void) C_CloseSession(ckSession);
440 		return (rv);
441 	}
442 
443 	ckMechanism.mechanism = pAlgMap->pkcs_mechanism;
444 	ckMechanism.pParameter = NULL;
445 	ckMechanism.ulParameterLen = 0;
446 
447 	ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle);
448 	if (ckRv != CKR_OK) {
449 		if (bTempKey)
450 			(void) C_DestroyObject(ckSession, ckKeyHandle);
451 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
452 		kmfh->lasterr.errcode = ckRv;
453 		(void) C_CloseSession(ckSession);
454 		return (KMF_ERR_INTERNAL);
455 	}
456 
457 	ckRv = C_Verify(ckSession,
458 		(CK_BYTE *)data->Data,
459 			(CK_ULONG)data->Length,
460 			(CK_BYTE *)signed_data->Data,
461 			(CK_ULONG)signed_data->Length);
462 
463 	if (ckRv != CKR_OK) {
464 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
465 		kmfh->lasterr.errcode = ckRv;
466 		rv = KMF_ERR_INTERNAL;
467 	}
468 	if (bTempKey)
469 		(void) C_DestroyObject(ckSession, ckKeyHandle);
470 
471 	(void) C_CloseSession(ckSession);
472 	return (rv);
473 
474 }
475 
476 KMF_RETURN
477 PKCS_EncryptData(KMF_HANDLE_T kmfh,
478 		KMF_ALGORITHM_INDEX AlgorithmId,
479 		KMF_X509_SPKI *keyp,
480 		KMF_DATA *plaintext,
481 		KMF_DATA *ciphertext)
482 {
483 	KMF_RETURN rv = KMF_OK;
484 	PKCS_ALGORITHM_MAP *pAlgMap = NULL;
485 	CK_RV ckRv;
486 	CK_MECHANISM ckMechanism;
487 	CK_OBJECT_HANDLE ckKeyHandle;
488 	KMF_BOOL bTempKey;
489 	CK_SESSION_HANDLE ckSession = NULL;
490 	CK_ULONG out_len = 0, in_len = 0, total_encrypted = 0;
491 	uint8_t *in_data, *out_data;
492 	int i, blocks, block_size;
493 	CK_ATTRIBUTE ckTemplate[2];
494 	CK_ULONG ckNumTemplates;
495 	CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
496 		sizeof (CK_ATTRIBUTE));
497 
498 	pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
499 	    AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId));
500 
501 	if (!pAlgMap)
502 		return (KMF_ERR_BAD_ALGORITHM);
503 
504 	rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism,
505 		CKF_ENCRYPT);
506 
507 	if (rv != KMF_OK)
508 		return (rv);
509 
510 	/* Get the public key used in encryption */
511 	rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
512 	    pAlgMap->key_type, &ckKeyHandle, &bTempKey);
513 
514 	if (rv != KMF_OK) {
515 		(void) C_CloseSession(ckSession);
516 		return (rv);
517 	}
518 
519 	/* Get the modulus length */
520 	ckNumTemplates = 0;
521 	if (!PKCS_AddTemplate(ckTemplate,
522 			&ckNumTemplates,
523 			ckMaxTemplates,
524 			CKA_MODULUS,
525 			(CK_BYTE *)NULL,
526 			sizeof (CK_ULONG))) {
527 		if (bTempKey)
528 			(void) C_DestroyObject(ckSession, ckKeyHandle);
529 		(void) C_CloseSession(ckSession);
530 		return (KMF_ERR_INTERNAL);
531 	}
532 
533 	ckRv = C_GetAttributeValue(ckSession,
534 				ckKeyHandle,
535 				ckTemplate,
536 				ckNumTemplates);
537 
538 	if (ckRv != CKR_OK) {
539 		if (bTempKey)
540 			(void) C_DestroyObject(ckSession, ckKeyHandle);
541 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
542 		kmfh->lasterr.errcode = ckRv;
543 		(void) C_CloseSession(ckSession);
544 		return (KMF_ERR_INTERNAL);
545 	}
546 	out_len = ckTemplate[0].ulValueLen;
547 
548 	if (out_len > ciphertext->Length) {
549 		if (bTempKey)
550 			(void) C_DestroyObject(ckSession, ckKeyHandle);
551 		(void) C_CloseSession(ckSession);
552 		return (KMF_ERR_BUFFER_SIZE);
553 	}
554 
555 	ckMechanism.mechanism = pAlgMap->pkcs_mechanism;
556 	ckMechanism.pParameter = NULL_PTR;
557 	ckMechanism.ulParameterLen = 0;
558 
559 	/* Compute the fixed input data length for single-part encryption */
560 	block_size = out_len - 11;
561 
562 	in_data = plaintext->Data;
563 	out_data = ciphertext->Data;
564 
565 	blocks = plaintext->Length/block_size;
566 
567 	for (i = 0; i < blocks; i++) {
568 		ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
569 		if (ckRv != CKR_OK) {
570 			if (bTempKey)
571 				(void) C_DestroyObject(ckSession, ckKeyHandle);
572 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
573 			kmfh->lasterr.errcode = ckRv;
574 			(void) C_CloseSession(ckSession);
575 			return (KMF_ERR_INTERNAL);
576 		}
577 		ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, block_size,
578 		    (CK_BYTE_PTR)out_data, &out_len);
579 
580 		if (ckRv != CKR_OK) {
581 			if (bTempKey)
582 				(void) C_DestroyObject(ckSession, ckKeyHandle);
583 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
584 			kmfh->lasterr.errcode = ckRv;
585 			(void) C_CloseSession(ckSession);
586 			return (KMF_ERR_INTERNAL);
587 		}
588 
589 		out_data += out_len;
590 		total_encrypted += out_len;
591 		in_data += block_size;
592 	}
593 
594 	if (plaintext->Length % block_size) {
595 		/* Encrypt the remaining data */
596 		ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
597 		if (ckRv != CKR_OK) {
598 			if (bTempKey)
599 				(void) C_DestroyObject(ckSession, ckKeyHandle);
600 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
601 			kmfh->lasterr.errcode = ckRv;
602 			(void) C_CloseSession(ckSession);
603 			return (KMF_ERR_INTERNAL);
604 		}
605 
606 		in_len = plaintext->Length % block_size;
607 		ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, in_len,
608 		    (CK_BYTE_PTR)out_data, &out_len);
609 
610 		if (ckRv != CKR_OK) {
611 			if (bTempKey)
612 				(void) C_DestroyObject(ckSession, ckKeyHandle);
613 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
614 			kmfh->lasterr.errcode = ckRv;
615 			(void) C_CloseSession(ckSession);
616 			return (KMF_ERR_INTERNAL);
617 		}
618 
619 		out_data += out_len;
620 		total_encrypted += out_len;
621 		in_data += in_len;
622 	}
623 
624 	ciphertext->Length = total_encrypted;
625 
626 	if (bTempKey)
627 		(void) C_DestroyObject(ckSession, ckKeyHandle);
628 
629 	(void) C_CloseSession(ckSession);
630 	return (rv);
631 
632 }
633 
634 static void
635 DigestData(KMF_DATA *IDInput, KMF_DATA *IDOutput)
636 {
637 	SHA1_CTX ctx;
638 
639 	SHA1Init(&ctx);
640 	SHA1Update(&ctx, IDInput->Data, IDInput->Length);
641 	SHA1Final(IDOutput->Data, &ctx);
642 
643 	IDOutput->Length = SHA1_DIGEST_LENGTH;
644 }
645 
646 KMF_RETURN
647 GetIDFromSPKI(KMF_X509_SPKI *spki, KMF_DATA *ID)
648 {
649 	KMF_RETURN rv = KMF_OK;
650 	KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
651 	uint32_t uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
652 	KMF_ALGORITHM_INDEX algId;
653 	int i;
654 
655 	if (ID == NULL || spki == NULL)
656 		return (KMF_ERR_BAD_PARAMETER);
657 
658 	ID->Data = (uchar_t *)malloc(SHA1_HASH_LENGTH);
659 	if (ID->Data == NULL)
660 		return (KMF_ERR_MEMORY);
661 
662 	ID->Length = SHA1_HASH_LENGTH;
663 
664 	algId = X509_AlgorithmOidToAlgId(&spki->algorithm.algorithm);
665 
666 	rv = ExtractSPKIData(spki, algId, KeyParts, &uNumKeyParts);
667 	if (rv != KMF_OK)
668 		return (rv);
669 
670 	/* Check the KEY algorithm */
671 	if (algId == KMF_ALGID_RSA) {
672 		DigestData(&KeyParts[KMF_RSA_MODULUS], ID);
673 	} else if (algId == KMF_ALGID_DSA) {
674 		DigestData(&KeyParts[KMF_DSA_PUBLIC_VALUE], ID);
675 	} else {
676 		/* We only support RSA and DSA keys for now */
677 		rv = KMF_ERR_BAD_ALGORITHM;
678 	}
679 
680 
681 	for (i = 0; i < uNumKeyParts; i++) {
682 		if (KeyParts[i].Data != NULL)
683 			free(KeyParts[i].Data);
684 	}
685 
686 	if (rv != KMF_OK && ID->Data != NULL) {
687 		free(ID->Data);
688 		ID->Data = NULL;
689 		ID->Length = 0;
690 	}
691 
692 	return (rv);
693 }
694