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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <stdlib.h>
27#include <string.h>
28#include <strings.h>
29#include <sys/types.h>
30#include <sys/crypto/common.h>
31#include <security/cryptoki.h>
32#include <bignum.h>
33#include <des_impl.h>
34#include "softGlobal.h"
35#include "softSession.h"
36#include "softObject.h"
37#include "softEC.h"
38#include "softCrypt.h"
39#include "softOps.h"
40#include "softMAC.h"
41
42void
43soft_free_ecparams(ECParams *params, boolean_t freeit)
44{
45	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
46	SECITEM_FreeItem(&params->curve.a, B_FALSE);
47	SECITEM_FreeItem(&params->curve.b, B_FALSE);
48	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
49	SECITEM_FreeItem(&params->base, B_FALSE);
50	SECITEM_FreeItem(&params->order, B_FALSE);
51	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
52	SECITEM_FreeItem(&params->curveOID, B_FALSE);
53	if (freeit)
54		free(params);
55}
56
57static void
58soft_free_ecc_context(soft_ecc_ctx_t *ecc_ctx)
59{
60	if (ecc_ctx != NULL) {
61		if (ecc_ctx->key != NULL) {
62			soft_cleanup_object(ecc_ctx->key);
63			free(ecc_ctx->key);
64		}
65
66		soft_free_ecparams(&ecc_ctx->ecparams, B_FALSE);
67		free(ecc_ctx);
68	}
69}
70
71void
72soft_free_ecprivkey(ECPrivateKey *key)
73{
74	soft_free_ecparams(&key->ecParams, B_FALSE);
75	/*
76	 * Don't free publicValue or privateValue
77	 * as these values are copied into objects.
78	 */
79	SECITEM_FreeItem(&key->version, B_FALSE);
80	free(key);
81}
82
83/*
84 * Called from init routines to do basic sanity checks. Init routines,
85 * e.g. sign_init should fail rather than subsequent operations.
86 */
87static int
88check_key(soft_object_t *key_p, boolean_t sign)
89{
90	biginteger_t *p;
91	ulong_t len;
92
93	if (sign) {
94		if ((key_p->class != CKO_PRIVATE_KEY) ||
95		    (key_p->key_type != CKK_EC))
96			return (CKR_KEY_TYPE_INCONSISTENT);
97
98		p = OBJ_PRI_EC_VALUE(key_p);
99		len = p->big_value_len;
100		if (p->big_value == NULL)
101			len = 0;
102
103		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
104		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
105			return (CKR_KEY_SIZE_RANGE);
106	} else {
107		if ((key_p->class != CKO_PUBLIC_KEY) ||
108		    (key_p->key_type != CKK_EC))
109			return (CKR_KEY_TYPE_INCONSISTENT);
110
111		p = OBJ_PUB_EC_POINT(key_p);
112		len = p->big_value_len;
113		if (p->big_value == NULL)
114			len = 0;
115
116		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
117		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
118			return (CKR_KEY_SIZE_RANGE);
119	}
120
121	return (CKR_OK);
122}
123
124/*
125 * This function places the octet string of the specified attribute
126 * into the corresponding key object.
127 */
128static void
129soft_genECkey_set_attribute(soft_object_t *key, biginteger_t *bi,
130    CK_ATTRIBUTE_TYPE type)
131{
132	biginteger_t *dst;
133
134	switch (type) {
135	case CKA_VALUE:
136		dst = OBJ_PRI_EC_VALUE(key);
137		break;
138
139	case CKA_EC_POINT:
140		dst = OBJ_PUB_EC_POINT(key);
141		break;
142	}
143	copy_bigint_attr(bi, dst);
144}
145
146CK_RV
147soft_ec_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
148{
149	CK_RV rv;
150	CK_ATTRIBUTE template;
151	ECPrivateKey *privKey;	/* contains both public and private values */
152	ECParams *ecparams;
153	SECKEYECParams params_item;
154	biginteger_t bi;
155	uchar_t param_buffer[EC_MAX_OID_LEN];
156	uint_t paramlen;
157
158	if ((pubkey->class != CKO_PUBLIC_KEY) ||
159	    (pubkey->key_type != CKK_EC))
160		return (CKR_KEY_TYPE_INCONSISTENT);
161
162	if ((prikey->class != CKO_PRIVATE_KEY) ||
163	    (prikey->key_type != CKK_EC))
164		return (CKR_KEY_TYPE_INCONSISTENT);
165
166	template.type = CKA_EC_PARAMS;
167	template.pValue = param_buffer;
168	template.ulValueLen = sizeof (param_buffer);
169	rv = soft_get_public_key_attribute(pubkey, &template);
170	if (rv != CKR_OK) {
171		return (rv);
172	}
173	paramlen = template.ulValueLen;
174
175	/* private key also has CKA_EC_PARAMS attribute */
176	rv = set_extra_attr_to_object(prikey, CKA_EC_PARAMS, &template);
177	if (rv != CKR_OK) {
178		return (rv);
179	}
180
181	/* ASN1 check */
182	if (param_buffer[0] != 0x06 ||
183	    param_buffer[1] != paramlen - 2) {
184		return (CKR_ATTRIBUTE_VALUE_INVALID);
185	}
186	params_item.len = paramlen;
187	params_item.data = param_buffer;
188	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
189		/* bad curve OID */
190		return (CKR_ARGUMENTS_BAD);
191	}
192
193	if (EC_NewKey(ecparams, &privKey, 0) != SECSuccess) {
194		soft_free_ecparams(ecparams, B_TRUE);
195		return (CKR_FUNCTION_FAILED);
196	}
197
198	bi.big_value = privKey->privateValue.data;
199	bi.big_value_len = privKey->privateValue.len;
200	soft_genECkey_set_attribute(prikey, &bi, CKA_VALUE);
201
202	bi.big_value = privKey->publicValue.data;
203	bi.big_value_len = privKey->publicValue.len;
204	soft_genECkey_set_attribute(pubkey, &bi, CKA_EC_POINT);
205
206	soft_free_ecprivkey(privKey);
207	soft_free_ecparams(ecparams, B_TRUE);
208
209	return (CKR_OK);
210}
211
212CK_RV
213soft_ec_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
214    void *mech_params, size_t mech_params_len)
215{
216	CK_RV		rv;
217	CK_ATTRIBUTE	template;
218	CK_ECDH1_DERIVE_PARAMS *ecdh1_derive_params = mech_params;
219	uchar_t		value[EC_MAX_VALUE_LEN];
220	uint32_t	value_len = sizeof (value);
221	uchar_t		params[EC_MAX_OID_LEN];
222	uint32_t	params_len = sizeof (params);
223	uint32_t	keylen;
224	ECParams	*ecparams;
225	SECKEYECParams	params_item;
226	SECItem		public_value_item, private_value_item, secret_item;
227	uchar_t		*buf;
228
229	if (mech_params_len != sizeof (CK_ECDH1_DERIVE_PARAMS) ||
230	    ecdh1_derive_params->kdf != CKD_NULL) {
231		return (CKR_MECHANISM_PARAM_INVALID);
232	}
233
234	template.type = CKA_VALUE;
235	template.pValue = value;
236	template.ulValueLen = value_len;
237	rv = soft_get_private_key_attribute(basekey, &template);
238	if (rv != CKR_OK) {
239		return (rv);
240	}
241	value_len = template.ulValueLen;
242	private_value_item.data = value;
243	private_value_item.len = value_len;
244
245	template.type = CKA_EC_PARAMS;
246	template.pValue = params;
247	template.ulValueLen = params_len;
248	rv = soft_get_private_key_attribute(basekey, &template);
249	if (rv != CKR_OK) {
250		return (rv);
251	}
252	params_len = template.ulValueLen;
253
254	switch (secretkey->key_type) {
255	case CKK_DES:
256		keylen = DES_KEYSIZE;
257		break;
258	case CKK_DES2:
259		keylen = DES2_KEYSIZE;
260		break;
261	case CKK_DES3:
262		keylen = DES3_KEYSIZE;
263		break;
264	case CKK_RC4:
265	case CKK_AES:
266	case CKK_GENERIC_SECRET:
267#ifdef	__sparcv9
268		/* LINTED */
269		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
270#else	/* !__sparcv9 */
271		keylen = OBJ_SEC_VALUE_LEN(secretkey);
272#endif	/* __sparcv9 */
273		break;
274	}
275
276	/* ASN1 check */
277	if (params[0] != 0x06 ||
278	    params[1] != params_len - 2) {
279		return (CKR_ATTRIBUTE_VALUE_INVALID);
280	}
281	params_item.data = params;
282	params_item.len = params_len;
283	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
284		/* bad curve OID */
285		return (CKR_ARGUMENTS_BAD);
286	}
287
288	public_value_item.data = ecdh1_derive_params->pPublicData;
289	public_value_item.len = ecdh1_derive_params->ulPublicDataLen;
290
291	secret_item.data = NULL;
292	secret_item.len = 0;
293
294	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
295	    B_FALSE, &secret_item, 0) != SECSuccess) {
296		soft_free_ecparams(ecparams, B_TRUE);
297		return (CKR_FUNCTION_FAILED);
298	} else {
299		rv = CKR_OK;
300	}
301
302	if (keylen == 0)
303		keylen = secret_item.len;
304
305	if (keylen > secret_item.len) {
306		rv = CKR_ATTRIBUTE_VALUE_INVALID;
307		goto out;
308	}
309	buf = malloc(keylen);
310	if (buf == NULL) {
311		rv = CKR_HOST_MEMORY;
312		goto out;
313	}
314	bcopy(secret_item.data + secret_item.len - keylen, buf, keylen);
315	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
316	OBJ_SEC_VALUE(secretkey) = buf;
317
318out:
319	soft_free_ecparams(ecparams, B_TRUE);
320	SECITEM_FreeItem(&secret_item, B_FALSE);
321
322	return (rv);
323}
324
325/*
326 * Allocate a ECC context for the active sign or verify operation.
327 * This function is called without the session lock held.
328 */
329CK_RV
330soft_ecc_sign_verify_init_common(soft_session_t *session_p,
331    CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
332    boolean_t sign)
333{
334	CK_RV rv;
335	CK_ATTRIBUTE template;
336	CK_MECHANISM digest_mech;
337	soft_ecc_ctx_t *ecc_ctx;
338	soft_object_t *tmp_key = NULL;
339	uchar_t params[EC_MAX_OID_LEN];
340	ECParams *ecparams;
341	SECKEYECParams params_item;
342
343	if ((rv = check_key(key_p, sign)) != CKR_OK)
344		return (rv);
345
346	if (pMechanism->mechanism == CKM_ECDSA_SHA1) {
347		digest_mech.mechanism = CKM_SHA_1;
348		rv = soft_digest_init_internal(session_p, &digest_mech);
349		if (rv != CKR_OK)
350			return (rv);
351	}
352
353	ecc_ctx = malloc(sizeof (soft_ecc_ctx_t));
354	if (ecc_ctx == NULL) {
355		return (CKR_HOST_MEMORY);
356	}
357
358	/*
359	 * Make a copy of the signature or verification key, and save it
360	 * in the ECC crypto context since it will be used later for
361	 * signing/verification. We don't want to hold any object reference
362	 * on this original key while doing signing/verification.
363	 */
364	(void) pthread_mutex_lock(&key_p->object_mutex);
365	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH, NULL);
366	if ((rv != CKR_OK) || (tmp_key == NULL)) {
367		/* Most likely we ran out of space. */
368		(void) pthread_mutex_unlock(&key_p->object_mutex);
369		free(ecc_ctx);
370		return (rv);
371	}
372
373
374	template.type = CKA_EC_PARAMS;
375	template.pValue = params;
376	template.ulValueLen = sizeof (params);
377	rv = soft_get_private_key_attribute(key_p, &template);
378	(void) pthread_mutex_unlock(&key_p->object_mutex);
379	if (rv != CKR_OK) {
380		goto out;
381	}
382
383	/* ASN1 check */
384	if (params[0] != 0x06 ||
385	    params[1] != template.ulValueLen - 2) {
386		rv = CKR_ATTRIBUTE_VALUE_INVALID;
387		goto out;
388	}
389	params_item.data = params;
390	params_item.len = template.ulValueLen;
391
392	ecc_ctx->key = tmp_key;
393
394	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
395		/* bad curve OID */
396		rv = CKR_ARGUMENTS_BAD;
397		goto out;
398	}
399	ecc_ctx->ecparams = *ecparams;
400	free(ecparams);
401
402	(void) pthread_mutex_lock(&session_p->session_mutex);
403
404	if (sign) {
405		session_p->sign.context = ecc_ctx;
406		session_p->sign.mech.mechanism = pMechanism->mechanism;
407	} else {
408		session_p->verify.context = ecc_ctx;
409		session_p->verify.mech.mechanism = pMechanism->mechanism;
410	}
411
412	(void) pthread_mutex_unlock(&session_p->session_mutex);
413	return (CKR_OK);
414
415out:
416	soft_cleanup_object(tmp_key);
417	free(tmp_key);
418	free(ecc_ctx);
419
420	return (rv);
421}
422
423CK_RV
424soft_ecc_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
425    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
426    CK_ULONG_PTR pulSignedLen, boolean_t Final)
427{
428	CK_RV rv = CKR_OK;
429	CK_BYTE hash[SHA1_HASH_SIZE];
430	CK_ULONG hash_len = SHA1_HASH_SIZE;
431
432	if (pSigned != NULL) {
433		if (Final) {
434			rv = soft_digest_final(session_p, hash, &hash_len);
435		} else {
436			rv = soft_digest(session_p, pData, ulDataLen, hash,
437			    &hash_len);
438		}
439
440		if (rv != CKR_OK) {
441			(void) pthread_mutex_lock(&session_p->session_mutex);
442			soft_free_ecc_context(session_p->sign.context);
443			session_p->sign.context = NULL;
444			session_p->digest.flags = 0;
445			(void) pthread_mutex_unlock(&session_p->session_mutex);
446			return (rv);
447		}
448	}
449
450	rv = soft_ecc_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
451
452clean_exit:
453	(void) pthread_mutex_lock(&session_p->session_mutex);
454	/* soft_digest_common() has freed the digest context */
455	session_p->digest.flags = 0;
456	(void) pthread_mutex_unlock(&session_p->session_mutex);
457
458clean1:
459	return (rv);
460}
461
462CK_RV
463soft_ecc_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
464    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
465    CK_ULONG_PTR pulSignedLen)
466{
467	CK_RV rv = CKR_OK;
468	SECStatus ss;
469	soft_ecc_ctx_t *ecc_ctx = session_p->sign.context;
470	soft_object_t *key = ecc_ctx->key;
471	uchar_t value[EC_MAX_VALUE_LEN];
472	ECPrivateKey ECkey;
473	SECItem signature_item;
474	SECItem digest_item;
475	uint_t value_len;
476
477	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_EC)) {
478		rv = CKR_KEY_TYPE_INCONSISTENT;
479		goto clean_exit;
480	}
481
482	if (ulDataLen > EC_MAX_DIGEST_LEN) {
483		rv = CKR_DATA_LEN_RANGE;
484		goto clean_exit;
485	}
486
487	/* structure assignment */
488	ECkey.ecParams = ecc_ctx->ecparams;
489
490	value_len = EC_MAX_VALUE_LEN;
491	rv = soft_get_private_value(key, CKA_VALUE, value, &value_len);
492	if (rv != CKR_OK) {
493		goto clean_exit;
494	}
495
496	ECkey.privateValue.data = value;
497	ECkey.privateValue.len = value_len;
498
499	signature_item.data = pSigned;
500	signature_item.len = *pulSignedLen;
501
502	digest_item.data = pData;
503	digest_item.len = ulDataLen;
504
505	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item, 0))
506	    != SECSuccess) {
507		if (ss == SECBufferTooSmall)
508			return (CKR_BUFFER_TOO_SMALL);
509
510		rv = CKR_FUNCTION_FAILED;
511		goto clean_exit;
512	}
513
514	if (rv == CKR_OK) {
515		*pulSignedLen = signature_item.len;
516		if (pSigned == NULL)
517			return (rv);
518	}
519
520clean_exit:
521	(void) pthread_mutex_lock(&session_p->session_mutex);
522	soft_free_ecc_context(session_p->sign.context);
523	session_p->sign.context = NULL;
524	(void) pthread_mutex_unlock(&session_p->session_mutex);
525	return (rv);
526}
527
528CK_RV
529soft_ecc_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
530    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
531    CK_ULONG ulSignatureLen)
532{
533	CK_RV rv = CKR_OK;
534	soft_ecc_ctx_t *ecc_ctx = session_p->verify.context;
535	soft_object_t *key = ecc_ctx->key;
536	uchar_t point[EC_MAX_POINT_LEN];
537	CK_ATTRIBUTE template;
538	ECPublicKey ECkey;
539	SECItem signature_item;
540	SECItem digest_item;
541
542	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_EC)) {
543		rv = CKR_KEY_TYPE_INCONSISTENT;
544		goto clean_exit;
545	}
546
547	if (ulSignatureLen > EC_MAX_SIG_LEN) {
548		rv = CKR_SIGNATURE_LEN_RANGE;
549		goto clean_exit;
550	}
551
552	if (ulDataLen > EC_MAX_DIGEST_LEN) {
553		rv = CKR_DATA_LEN_RANGE;
554		goto clean_exit;
555	}
556
557	/* structure assignment */
558	ECkey.ecParams = ecc_ctx->ecparams;
559
560	template.type = CKA_EC_POINT;
561	template.pValue = point;
562	template.ulValueLen = sizeof (point);
563	rv = soft_get_public_key_attribute(key, &template);
564	if (rv != CKR_OK) {
565		goto clean_exit;
566	}
567
568	ECkey.publicValue.data = point;
569	ECkey.publicValue.len = template.ulValueLen;
570
571	signature_item.data = pSignature;
572	signature_item.len = ulSignatureLen;
573
574	digest_item.data = pData;
575	digest_item.len = ulDataLen;
576
577	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, 0)
578	    != SECSuccess) {
579		rv = CKR_SIGNATURE_INVALID;
580	} else {
581		rv = CKR_OK;
582	}
583
584clean_exit:
585	(void) pthread_mutex_lock(&session_p->session_mutex);
586	soft_free_ecc_context(session_p->verify.context);
587	session_p->verify.context = NULL;
588	(void) pthread_mutex_unlock(&session_p->session_mutex);
589	return (rv);
590}
591
592
593CK_RV
594soft_ecc_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
595    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
596    CK_ULONG ulSignedLen, boolean_t Final)
597{
598	CK_RV rv;
599	CK_BYTE hash[SHA1_HASH_SIZE];
600	CK_ULONG hash_len = SHA1_HASH_SIZE;
601
602	if (Final) {
603		rv = soft_digest_final(session_p, hash, &hash_len);
604	} else {
605		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
606	}
607
608	if (rv != CKR_OK) {
609		(void) pthread_mutex_lock(&session_p->session_mutex);
610		soft_free_ecc_context(session_p->verify.context);
611		session_p->verify.context = NULL;
612		session_p->digest.flags = 0;
613		(void) pthread_mutex_unlock(&session_p->session_mutex);
614		return (rv);
615	}
616
617	/*
618	 * Now, we are ready to verify the data using signature.
619	 * soft_ecc_verify() will free the verification key.
620	 */
621	rv = soft_ecc_verify(session_p, hash, hash_len,
622	    pSigned, ulSignedLen);
623
624clean_exit:
625	(void) pthread_mutex_lock(&session_p->session_mutex);
626	/* soft_digest_common() has freed the digest context */
627	session_p->digest.flags = 0;
628	(void) pthread_mutex_unlock(&session_p->session_mutex);
629	return (rv);
630}
631