8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / pkcs11 / pkcs11_softtoken / common / softDSA.c
blobb366cc2171208931b01a59fd0b1b77cc34aa82f4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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"
42 * Allocate a DSA context for the active sign or verify operation.
43 * This function is called without the session lock held.
45 CK_RV
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)
51 soft_dsa_ctx_t *dsa_ctx;
52 CK_MECHANISM digest_mech;
53 soft_object_t *tmp_key = NULL;
54 CK_RV rv;
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);
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);
73 dsa_ctx = malloc(sizeof (soft_dsa_ctx_t));
75 if (dsa_ctx == NULL) {
76 return (CKR_HOST_MEMORY);
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.
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);
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);
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;
100 (void) pthread_mutex_lock(&session_p->session_mutex);
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;
110 (void) pthread_mutex_unlock(&session_p->session_mutex);
112 return (CKR_OK);
116 static CK_RV
117 local_dsa_sign(soft_object_t *key, CK_BYTE_PTR in, CK_ULONG inlen,
118 CK_BYTE_PTR out)
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;
131 rv = soft_get_private_value(key, CKA_PRIME, p, &plen);
132 if (rv != CKR_OK) {
133 goto clean1;
136 rv = soft_get_private_value(key, CKA_SUBPRIME, q, &qlen);
137 if (rv != CKR_OK) {
138 goto clean1;
141 rv = soft_get_private_value(key, CKA_BASE, g, &glen);
142 if (rv != CKR_OK) {
143 goto clean1;
146 rv = soft_get_private_value(key, CKA_VALUE, x, &xlen);
147 if (rv != CKR_OK) {
148 goto clean1;
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;
161 rv = dsa_sign(&k, in, inlen, out);
163 clean1:
164 return (rv);
167 static CK_RV
168 local_dsa_verify(soft_object_t *key, CK_BYTE_PTR data, CK_BYTE_PTR sig)
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;
181 rv = soft_get_public_value(key, CKA_PRIME, p, &plen);
182 if (rv != CKR_OK) {
183 goto clean1;
186 rv = soft_get_public_value(key, CKA_SUBPRIME, q, &qlen);
187 if (rv != CKR_OK) {
188 goto clean1;
191 rv = soft_get_public_value(key, CKA_BASE, g, &glen);
192 if (rv != CKR_OK) {
193 goto clean1;
196 rv = soft_get_public_value(key, CKA_VALUE, y, &ylen);
197 if (rv != CKR_OK) {
198 goto clean1;
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;
211 rv = dsa_verify(&k, data, sig);
213 clean1:
214 return (rv);
218 CK_RV
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)
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;
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;
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;
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);
250 if (rv != CKR_OK) {
251 /* free the signature key */
252 soft_cleanup_object(key);
253 free(key);
254 goto clean_exit;
258 * Now, we are ready to sign the data
259 * soft_dsa_sign() will free the signature key.
261 rv = soft_dsa_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
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);
269 clean1:
270 return (rv);
274 CK_RV
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)
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;
284 if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_DSA)) {
285 rv = CKR_KEY_TYPE_INCONSISTENT;
286 goto clean_exit;
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);
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;
302 if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
303 *pulSignedLen = DSA_SIGNATURE_LENGTH;
304 return (CKR_BUFFER_TOO_SMALL);
307 rv = local_dsa_sign(key, pData, ulDataLen, pSigned);
308 if (rv == CKR_OK) {
309 *pulSignedLen = DSA_SIGNATURE_LENGTH;
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);
323 CK_RV
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)
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;
333 if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_DSA)) {
334 rv = CKR_KEY_TYPE_INCONSISTENT;
335 goto clean_exit;
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;
344 /* The signature length is always 40 bytes. */
345 if (ulSignatureLen != DSA_SIGNATURE_LENGTH) {
346 rv = CKR_SIGNATURE_LEN_RANGE;
347 goto clean_exit;
350 rv = local_dsa_verify(key, pData, pSignature);
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);
363 CK_RV
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)
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;
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);
381 if (rv != CKR_OK) {
382 /* free the verification key */
383 soft_cleanup_object(key);
384 free(key);
385 goto clean_exit;
389 * Now, we are ready to verify the data using signature.
390 * soft_dsa_verify() will free the verification key.
392 rv = soft_dsa_verify(session_p, hash, hash_len,
393 pSigned, ulSignedLen);
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);
404 static CK_RV
405 soft_genDSAkey_set_attribute(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
406 uchar_t *value, uint32_t value_len, boolean_t public)
409 CK_RV rv = CKR_OK;
410 biginteger_t *dst = NULL;
411 biginteger_t src;
413 switch (type) {
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;
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;
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;
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;
444 /* Note: removal of preceding 0x00 imitates similar code in RSA */
445 while (value[0] == 0) { /* remove preceding 0x00 */
446 value++;
447 value_len--;
450 if ((rv = dup_bigint_attr(&src, value, value_len)) != CKR_OK)
451 goto cleanexit;
453 /* Copy the attribute in the key object. */
454 copy_bigint_attr(&src, dst);
456 cleanexit:
457 /* No need to free big_value because dst holds it now after copy. */
458 return (rv);
463 CK_RV
464 soft_dsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
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;
479 if ((pubkey == NULL) || (prikey == NULL)) {
480 return (CKR_ARGUMENTS_BAD);
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;
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;
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;
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;
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);
519 rv = dsa_genkey_pair(&k);
521 if (rv != CKR_OK) {
522 goto cleanexit;
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;
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;
536 if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_SUBPRIME, subprime,
537 CRYPTO_BITS2BYTES(k.subprime_bits), B_FALSE)) != CKR_OK) {
538 goto cleanexit;
541 if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_BASE,
542 base, k.base_bytes, B_FALSE)) != CKR_OK) {
543 goto cleanexit;
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;
551 cleanexit:
552 return (rv);