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 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <security/cryptoki.h>
32 #include <cryptoutil.h>
33 #include "softGlobal.h"
34 #include "softSession.h"
35 #include "softObject.h"
36 #include "softDSA.h"
37 #include "softOps.h"
38 #include "softMAC.h"
39 #include "softCrypt.h"
40 
41 /*
42  * Allocate a DSA context for the active sign or verify operation.
43  * This function is called without the session lock held.
44  */
45 CK_RV
soft_dsa_sign_verify_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t sign)46 soft_dsa_sign_verify_init_common(soft_session_t *session_p,
47     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
48     boolean_t sign)
49 {
50 
51 	soft_dsa_ctx_t *dsa_ctx;
52 	CK_MECHANISM digest_mech;
53 	soft_object_t *tmp_key = NULL;
54 	CK_RV rv;
55 
56 	if (sign) {
57 		if ((key_p->class != CKO_PRIVATE_KEY) ||
58 		    (key_p->key_type != CKK_DSA))
59 			return (CKR_KEY_TYPE_INCONSISTENT);
60 	} else {
61 		if ((key_p->class != CKO_PUBLIC_KEY) ||
62 		    (key_p->key_type != CKK_DSA))
63 			return (CKR_KEY_TYPE_INCONSISTENT);
64 	}
65 
66 	if (pMechanism->mechanism == CKM_DSA_SHA1) {
67 		digest_mech.mechanism = CKM_SHA_1;
68 		rv = soft_digest_init_internal(session_p, &digest_mech);
69 		if (rv != CKR_OK)
70 			return (rv);
71 	}
72 
73 	dsa_ctx = malloc(sizeof (soft_dsa_ctx_t));
74 
75 	if (dsa_ctx == NULL) {
76 		return (CKR_HOST_MEMORY);
77 	}
78 
79 	/*
80 	 * Make a copy of the signature or verification key, and save it
81 	 * in the DSA crypto context since it will be used later for
82 	 * signing/verification. We don't want to hold any object reference
83 	 * on this original key while doing signing/verification.
84 	 */
85 	(void) pthread_mutex_lock(&key_p->object_mutex);
86 	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH,
87 	    NULL);
88 
89 	if ((rv != CKR_OK) || (tmp_key == NULL)) {
90 		/* Most likely we ran out of space. */
91 		(void) pthread_mutex_unlock(&key_p->object_mutex);
92 		free(dsa_ctx);
93 		return (rv);
94 	}
95 
96 	/* No need to hold the lock on the old object. */
97 	(void) pthread_mutex_unlock(&key_p->object_mutex);
98 	dsa_ctx->key = tmp_key;
99 
100 	(void) pthread_mutex_lock(&session_p->session_mutex);
101 
102 	if (sign) {
103 		session_p->sign.context = dsa_ctx;
104 		session_p->sign.mech.mechanism = pMechanism->mechanism;
105 	} else {
106 		session_p->verify.context = dsa_ctx;
107 		session_p->verify.mech.mechanism = pMechanism->mechanism;
108 	}
109 
110 	(void) pthread_mutex_unlock(&session_p->session_mutex);
111 
112 	return (CKR_OK);
113 }
114 
115 
116 static CK_RV
local_dsa_sign(soft_object_t * key,CK_BYTE_PTR in,CK_ULONG inlen,CK_BYTE_PTR out)117 local_dsa_sign(soft_object_t *key, CK_BYTE_PTR in, CK_ULONG inlen,
118     CK_BYTE_PTR out)
119 {
120 	CK_RV rv;
121 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
122 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
123 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
124 	uchar_t x[MAX_KEY_ATTR_BUFLEN];
125 	uint_t qlen = sizeof (q);
126 	uint_t plen = sizeof (p);
127 	uint_t glen = sizeof (g);
128 	uint_t xlen = sizeof (x);
129 	DSAbytekey k;
130 
131 	rv = soft_get_private_value(key, CKA_PRIME, p, &plen);
132 	if (rv != CKR_OK) {
133 		goto clean1;
134 	}
135 
136 	rv = soft_get_private_value(key, CKA_SUBPRIME, q, &qlen);
137 	if (rv != CKR_OK) {
138 		goto clean1;
139 	}
140 
141 	rv = soft_get_private_value(key, CKA_BASE, g, &glen);
142 	if (rv != CKR_OK) {
143 		goto clean1;
144 	}
145 
146 	rv = soft_get_private_value(key, CKA_VALUE, x, &xlen);
147 	if (rv != CKR_OK) {
148 		goto clean1;
149 	}
150 
151 	k.prime = p;
152 	k.prime_bits = CRYPTO_BYTES2BITS(plen);
153 	k.subprime = q;
154 	k.subprime_bits = CRYPTO_BYTES2BITS(qlen);
155 	k.base = g;
156 	k.base_bytes = glen;
157 	k.private_x_bits = CRYPTO_BYTES2BITS(xlen);
158 	k.private_x = x;
159 	k.rfunc = NULL;
160 
161 	rv = dsa_sign(&k, in, inlen, out);
162 
163 clean1:
164 	return (rv);
165 }
166 
167 static CK_RV
local_dsa_verify(soft_object_t * key,CK_BYTE_PTR data,CK_BYTE_PTR sig)168 local_dsa_verify(soft_object_t *key, CK_BYTE_PTR data, CK_BYTE_PTR sig)
169 {
170 	CK_RV rv;
171 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
172 	uchar_t y[MAX_KEY_ATTR_BUFLEN];
173 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
174 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
175 	uint_t glen = sizeof (g);
176 	uint_t ylen = sizeof (y);
177 	uint_t plen = sizeof (p);
178 	uint_t qlen = sizeof (q);
179 	DSAbytekey k;
180 
181 	rv = soft_get_public_value(key, CKA_PRIME, p, &plen);
182 	if (rv != CKR_OK) {
183 		goto clean1;
184 	}
185 
186 	rv = soft_get_public_value(key, CKA_SUBPRIME, q, &qlen);
187 	if (rv != CKR_OK) {
188 		goto clean1;
189 	}
190 
191 	rv = soft_get_public_value(key, CKA_BASE, g, &glen);
192 	if (rv != CKR_OK) {
193 		goto clean1;
194 	}
195 
196 	rv = soft_get_public_value(key, CKA_VALUE, y, &ylen);
197 	if (rv != CKR_OK) {
198 		goto clean1;
199 	}
200 
201 	k.prime = p;
202 	k.prime_bits = CRYPTO_BYTES2BITS(plen);
203 	k.subprime = q;
204 	k.subprime_bits = CRYPTO_BYTES2BITS(qlen);
205 	k.base = g;
206 	k.base_bytes = glen;
207 	k.public_y_bits = CRYPTO_BYTES2BITS(ylen);
208 	k.public_y = y;
209 	k.rfunc = NULL;
210 
211 	rv = dsa_verify(&k, data, sig);
212 
213 clean1:
214 	return (rv);
215 }
216 
217 
218 CK_RV
soft_dsa_digest_sign_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen,boolean_t Final)219 soft_dsa_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
220     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
221     CK_ULONG_PTR pulSignedLen, boolean_t Final)
222 {
223 
224 	CK_RV rv = CKR_OK;
225 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
226 	CK_ULONG hash_len = SHA1_HASH_SIZE;
227 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
228 	soft_object_t *key = dsa_ctx->key;
229 
230 	/* Check arguments before performing message digest. */
231 	if (pSigned == NULL) {
232 		/* Application asks for the length of the output buffer. */
233 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
234 		goto clean1;
235 	}
236 
237 	/* Is the application-supplied buffer large enough? */
238 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
239 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
240 		rv = CKR_BUFFER_TOO_SMALL;
241 		goto clean1;
242 	}
243 
244 	if (Final) {
245 		rv = soft_digest_final(session_p, hash, &hash_len);
246 	} else {
247 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
248 	}
249 
250 	if (rv != CKR_OK) {
251 		/* free the signature key */
252 		soft_cleanup_object(key);
253 		free(key);
254 		goto clean_exit;
255 	}
256 
257 	/*
258 	 * Now, we are ready to sign the data
259 	 * soft_dsa_sign() will free the signature key.
260 	 */
261 	rv = soft_dsa_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
262 
263 clean_exit:
264 	(void) pthread_mutex_lock(&session_p->session_mutex);
265 	/* soft_digest_common() has freed the digest context */
266 	session_p->digest.flags = 0;
267 	(void) pthread_mutex_unlock(&session_p->session_mutex);
268 
269 clean1:
270 	return (rv);
271 }
272 
273 
274 CK_RV
soft_dsa_sign(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen)275 soft_dsa_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
276     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
277     CK_ULONG_PTR pulSignedLen)
278 {
279 
280 	CK_RV rv = CKR_OK;
281 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
282 	soft_object_t *key = dsa_ctx->key;
283 
284 	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_DSA)) {
285 		rv = CKR_KEY_TYPE_INCONSISTENT;
286 		goto clean_exit;
287 	}
288 
289 	/* Output length is always 40 bytes. */
290 	if (pSigned == NULL) {
291 		/* Application asks for the length of the output buffer. */
292 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
293 		return (CKR_OK);
294 	}
295 
296 	/* Input data length needs to be 20 bytes. */
297 	if (ulDataLen != DSA_SUBPRIME_BYTES) {
298 		rv = CKR_DATA_LEN_RANGE;
299 		goto clean_exit;
300 	}
301 
302 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
303 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
304 		return (CKR_BUFFER_TOO_SMALL);
305 	}
306 
307 	rv = local_dsa_sign(key, pData, ulDataLen, pSigned);
308 	if (rv == CKR_OK) {
309 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
310 	}
311 
312 clean_exit:
313 	(void) pthread_mutex_lock(&session_p->session_mutex);
314 	free(session_p->sign.context);
315 	session_p->sign.context = NULL;
316 	(void) pthread_mutex_unlock(&session_p->session_mutex);
317 	soft_cleanup_object(key);
318 	free(key);
319 	return (rv);
320 }
321 
322 
323 CK_RV
soft_dsa_verify(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)324 soft_dsa_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
325     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
326     CK_ULONG ulSignatureLen)
327 {
328 
329 	CK_RV rv = CKR_OK;
330 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
331 	soft_object_t *key = dsa_ctx->key;
332 
333 	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_DSA)) {
334 		rv = CKR_KEY_TYPE_INCONSISTENT;
335 		goto clean_exit;
336 	}
337 
338 	/* Input data length needs to be 20 bytes. */
339 	if (ulDataLen != DSA_SUBPRIME_BYTES) {
340 		rv = CKR_DATA_LEN_RANGE;
341 		goto clean_exit;
342 	}
343 
344 	/* The signature length is always 40 bytes. */
345 	if (ulSignatureLen != DSA_SIGNATURE_LENGTH) {
346 		rv = CKR_SIGNATURE_LEN_RANGE;
347 		goto clean_exit;
348 	}
349 
350 	rv = local_dsa_verify(key, pData, pSignature);
351 
352 clean_exit:
353 	(void) pthread_mutex_lock(&session_p->session_mutex);
354 	free(session_p->verify.context);
355 	session_p->verify.context = NULL;
356 	(void) pthread_mutex_unlock(&session_p->session_mutex);
357 	soft_cleanup_object(key);
358 	free(key);
359 	return (rv);
360 }
361 
362 
363 CK_RV
soft_dsa_digest_verify_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG ulSignedLen,boolean_t Final)364 soft_dsa_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
365     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
366     CK_ULONG ulSignedLen, boolean_t Final)
367 {
368 
369 	CK_RV rv;
370 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
371 	CK_ULONG hash_len = SHA1_HASH_SIZE;
372 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
373 	soft_object_t *key = dsa_ctx->key;
374 
375 	if (Final) {
376 		rv = soft_digest_final(session_p, hash, &hash_len);
377 	} else {
378 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
379 	}
380 
381 	if (rv != CKR_OK) {
382 		/* free the verification key */
383 		soft_cleanup_object(key);
384 		free(key);
385 		goto clean_exit;
386 	}
387 
388 	/*
389 	 * Now, we are ready to verify the data using signature.
390 	 * soft_dsa_verify() will free the verification key.
391 	 */
392 	rv = soft_dsa_verify(session_p, hash, hash_len,
393 	    pSigned, ulSignedLen);
394 
395 clean_exit:
396 	(void) pthread_mutex_lock(&session_p->session_mutex);
397 	/* soft_digest_common() has freed the digest context */
398 	session_p->digest.flags = 0;
399 	(void) pthread_mutex_unlock(&session_p->session_mutex);
400 	return (rv);
401 }
402 
403 
404 static CK_RV
soft_genDSAkey_set_attribute(soft_object_t * key,CK_ATTRIBUTE_TYPE type,uchar_t * value,uint32_t value_len,boolean_t public)405 soft_genDSAkey_set_attribute(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
406     uchar_t *value, uint32_t value_len, boolean_t public)
407 {
408 
409 	CK_RV rv = CKR_OK;
410 	biginteger_t *dst = NULL;
411 	biginteger_t src;
412 
413 	switch (type) {
414 
415 	case CKA_VALUE:
416 		if (public)
417 			dst = OBJ_PUB_DSA_VALUE(key);
418 		else
419 			dst = OBJ_PRI_DSA_VALUE(key);
420 		break;
421 
422 	case CKA_PRIME:
423 		if (public)
424 			dst = OBJ_PUB_DSA_PRIME(key);
425 		else
426 			dst = OBJ_PRI_DSA_PRIME(key);
427 		break;
428 
429 	case CKA_SUBPRIME:
430 		if (public)
431 			dst = OBJ_PUB_DSA_SUBPRIME(key);
432 		else
433 			dst = OBJ_PRI_DSA_SUBPRIME(key);
434 		break;
435 
436 	case CKA_BASE:
437 		if (public)
438 			dst = OBJ_PUB_DSA_BASE(key);
439 		else
440 			dst = OBJ_PRI_DSA_BASE(key);
441 		break;
442 	}
443 
444 	/* Note: removal of preceding 0x00 imitates similar code in RSA */
445 	while (value[0] == 0) {		/* remove preceding 0x00 */
446 		value++;
447 		value_len--;
448 	}
449 
450 	if ((rv = dup_bigint_attr(&src, value, value_len)) != CKR_OK)
451 		goto cleanexit;
452 
453 	/* Copy the attribute in the key object. */
454 	copy_bigint_attr(&src, dst);
455 
456 cleanexit:
457 	/* No need to free big_value because dst holds it now after copy. */
458 	return (rv);
459 
460 }
461 
462 
463 CK_RV
soft_dsa_genkey_pair(soft_object_t * pubkey,soft_object_t * prikey)464 soft_dsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
465 {
466 	CK_RV rv;
467 	uchar_t prime[MAX_KEY_ATTR_BUFLEN];
468 	uint32_t prime_len = sizeof (prime);
469 	uchar_t	subprime[MAX_KEY_ATTR_BUFLEN];
470 	uint32_t subprime_len = sizeof (subprime);
471 	uchar_t	base[MAX_KEY_ATTR_BUFLEN];
472 	uint32_t base_len = sizeof (base);
473 	uchar_t	pubvalue[MAX_KEY_ATTR_BUFLEN];
474 	uint32_t pubvalue_len = sizeof (pubvalue);
475 	uchar_t	privalue[DSA_SUBPRIME_BYTES];
476 	uint32_t privalue_len = sizeof (privalue);
477 	DSAbytekey k;
478 
479 	if ((pubkey == NULL) || (prikey == NULL)) {
480 		return (CKR_ARGUMENTS_BAD);
481 	}
482 
483 	/* lookup prime, subprime and base */
484 	rv = soft_get_public_value(pubkey, CKA_PRIME, prime, &prime_len);
485 	if (rv != CKR_OK) {
486 		rv = CKR_TEMPLATE_INCOMPLETE;
487 		goto cleanexit;
488 	}
489 
490 	rv = soft_get_public_value(pubkey, CKA_SUBPRIME, subprime,
491 	    &subprime_len);
492 	if (rv != CKR_OK) {
493 		rv = CKR_TEMPLATE_INCOMPLETE;
494 		goto cleanexit;
495 	}
496 
497 	rv = soft_get_public_value(pubkey, CKA_BASE, base, &base_len);
498 	if (rv != CKR_OK) {
499 		rv = CKR_TEMPLATE_INCOMPLETE;
500 		goto cleanexit;
501 	}
502 
503 	/* Inputs to DSA key pair generation. */
504 	k.prime = prime;
505 	k.prime_bits = CRYPTO_BYTES2BITS(prime_len);
506 	k.subprime = subprime;
507 	k.subprime_bits = CRYPTO_BYTES2BITS(subprime_len);
508 	k.base = base;
509 	k.base_bytes = base_len;
510 	k.rfunc = (IS_TOKEN_OBJECT(pubkey) || IS_TOKEN_OBJECT(prikey)) ?
511 	    pkcs11_get_random : pkcs11_get_urandom;
512 
513 	/* Outputs from DSA key pair generation. */
514 	k.public_y = pubvalue;
515 	k.public_y_bits = CRYPTO_BYTES2BITS(pubvalue_len);
516 	k.private_x = privalue;
517 	k.private_x_bits = CRYPTO_BYTES2BITS(privalue_len);
518 
519 	rv = dsa_genkey_pair(&k);
520 
521 	if (rv != CKR_OK) {
522 		goto cleanexit;
523 	}
524 
525 	/* Update attribute in public key. */
526 	if ((rv = soft_genDSAkey_set_attribute(pubkey, CKA_VALUE,
527 	    pubvalue, CRYPTO_BITS2BYTES(k.public_y_bits), B_TRUE)) != CKR_OK) {
528 		goto cleanexit;
529 	}
530 	/* Update attributes in private key. */
531 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_PRIME,
532 	    prime, CRYPTO_BITS2BYTES(k.prime_bits), B_FALSE)) != CKR_OK) {
533 		goto cleanexit;
534 	}
535 
536 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_SUBPRIME, subprime,
537 	    CRYPTO_BITS2BYTES(k.subprime_bits), B_FALSE)) != CKR_OK) {
538 		goto cleanexit;
539 	}
540 
541 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_BASE,
542 	    base, k.base_bytes, B_FALSE)) != CKR_OK) {
543 		goto cleanexit;
544 	}
545 
546 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_VALUE, privalue,
547 	    CRYPTO_BITS2BYTES(k.private_x_bits), B_FALSE)) != CKR_OK) {
548 		goto cleanexit;
549 	}
550 
551 cleanexit:
552 	return (rv);
553 }
554