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 <stdlib.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <sys/types.h>
30 #include <security/cryptoki.h>
31 #include <sys/crypto/common.h>
32 #include <des_impl.h>
33 #include <cryptoutil.h>
34 #include "softGlobal.h"
35 #include "softSession.h"
36 #include "softObject.h"
37 #include "softDH.h"
38 #include "softCrypt.h"
39 
40 
41 /*
42  * This function takes a converted big integer of the specified attribute
43  * as an octet string and stores it in the corresponding key object.
44  */
45 static CK_RV
soft_genDHkey_set_attribute(soft_object_t * key,CK_ATTRIBUTE_TYPE type,uchar_t * buf,uint32_t buflen,boolean_t public)46 soft_genDHkey_set_attribute(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
47     uchar_t *buf, uint32_t buflen, boolean_t public)
48 {
49 
50 	CK_RV rv = CKR_OK;
51 	biginteger_t *dst = NULL;
52 	biginteger_t src;
53 
54 	switch (type) {
55 
56 	case CKA_VALUE:
57 		if (public)
58 			dst = OBJ_PUB_DH_VALUE(key);
59 		else
60 			dst = OBJ_PRI_DH_VALUE(key);
61 		break;
62 
63 	case CKA_PRIME:
64 		dst = OBJ_PRI_DH_PRIME(key);
65 		break;
66 
67 	case CKA_BASE:
68 		dst = OBJ_PRI_DH_BASE(key);
69 		break;
70 	}
71 
72 	if ((rv = dup_bigint_attr(&src, buf, buflen)) != CKR_OK)
73 		goto cleanexit;
74 
75 	/* Copy the attribute in the key object. */
76 	copy_bigint_attr(&src, dst);
77 
78 cleanexit:
79 	/* No need to free big_value because dst holds it now after copy. */
80 	return (rv);
81 
82 }
83 
84 /*
85  * This function covers the DH Key agreement.
86  */
87 CK_RV
soft_dh_genkey_pair(soft_object_t * pubkey,soft_object_t * prikey)88 soft_dh_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
89 {
90 	CK_RV		rv;
91 	CK_ATTRIBUTE 	template;
92 	uchar_t		prime[MAX_KEY_ATTR_BUFLEN];
93 	uint32_t	prime_len = sizeof (prime);
94 	uchar_t		base[MAX_KEY_ATTR_BUFLEN];
95 	uint32_t	base_len = sizeof (base);
96 	uint32_t	value_bits;
97 	uchar_t		private_x[MAX_KEY_ATTR_BUFLEN];
98 	uchar_t		public_y[MAX_KEY_ATTR_BUFLEN];
99 	DHbytekey	k;
100 
101 	if ((pubkey->class != CKO_PUBLIC_KEY) ||
102 	    (pubkey->key_type != CKK_DH)) {
103 		return (CKR_KEY_TYPE_INCONSISTENT);
104 	}
105 
106 	if ((prikey->class != CKO_PRIVATE_KEY) ||
107 	    (prikey->key_type != CKK_DH)) {
108 		return (CKR_KEY_TYPE_INCONSISTENT);
109 	}
110 
111 	/* Get private-value length in bits */
112 	template.pValue = malloc(sizeof (CK_ULONG));
113 	if (template.pValue == NULL) {
114 		return (CKR_HOST_MEMORY);
115 	}
116 	template.ulValueLen = sizeof (CK_ULONG);
117 	rv = get_ulong_attr_from_object(OBJ_PRI_DH_VAL_BITS(prikey),
118 	    &template);
119 	if (rv != CKR_OK) {
120 		free(template.pValue);
121 		return (rv);
122 	}
123 
124 #ifdef	__sparcv9
125 	/* LINTED */
126 	value_bits = (uint32_t)(*((CK_ULONG *)(template.pValue)));
127 #else	/* !__sparcv9 */
128 	value_bits = *((CK_ULONG *)(template.pValue));
129 #endif	/* __sparcv9 */
130 
131 	free(template.pValue);
132 
133 	/*
134 	 * The input to the first phase shall be the Diffie-Hellman
135 	 * parameters, which include prime, base, and private-value length.
136 	 */
137 	rv = soft_get_public_value(pubkey, CKA_PRIME, prime, &prime_len);
138 	if (rv != CKR_OK) {
139 		return (rv);
140 	}
141 
142 	rv = soft_get_public_value(pubkey, CKA_BASE, base, &base_len);
143 	if (rv != CKR_OK) {
144 		goto ret;
145 	}
146 
147 	/* Inputs to DH key pair generation. */
148 	k.prime = prime;
149 	k.prime_bits = CRYPTO_BYTES2BITS(prime_len);
150 	k.base = base;
151 	k.base_bytes = base_len;
152 	k.value_bits = value_bits;
153 	k.rfunc = (IS_TOKEN_OBJECT(pubkey) || IS_TOKEN_OBJECT(prikey)) ?
154 	    pkcs11_get_random : pkcs11_get_urandom;
155 
156 	/* Outputs from DH key pair generation. */
157 	k.private_x = private_x;
158 	k.public_y = public_y;
159 
160 	/* If value_bits is 0, it will return as same size as prime */
161 	if ((rv = dh_genkey_pair(&k)) != CKR_OK) {
162 		goto ret;
163 	}
164 
165 	/*
166 	 * The integer public value y shall be converted to an octet
167 	 * string PV of length k, the public value.
168 	 */
169 	if ((rv = soft_genDHkey_set_attribute(pubkey, CKA_VALUE, public_y,
170 	    prime_len, B_TRUE)) != CKR_OK) {
171 		goto ret;
172 	}
173 
174 	/* Convert the big integer private value to an octet string. */
175 	if ((rv = soft_genDHkey_set_attribute(prikey, CKA_VALUE, private_x,
176 	    CRYPTO_BITS2BYTES(k.value_bits), B_FALSE)) != CKR_OK) {
177 		goto ret;
178 	}
179 
180 	/* Convert the big integer prime to an octet string. */
181 	if ((rv = soft_genDHkey_set_attribute(prikey, CKA_PRIME, prime,
182 	    CRYPTO_BITS2BYTES(k.prime_bits), B_FALSE)) != CKR_OK) {
183 		goto ret;
184 	}
185 
186 	/* Convert the big integer base to an octet string. */
187 	if ((rv = soft_genDHkey_set_attribute(prikey, CKA_BASE, base,
188 	    k.base_bytes, B_FALSE)) != CKR_OK) {
189 		goto ret;
190 	}
191 
192 	/* Update private-value length in bits; could have been 0 before */
193 	OBJ_PRI_DH_VAL_BITS(prikey) = k.value_bits;
194 
195 ret:
196 	return (rv);
197 }
198 
199 /* ARGSUSED3 */
200 CK_RV
soft_dh_key_derive(soft_object_t * basekey,soft_object_t * secretkey,void * publicvalue,size_t publicvaluelen)201 soft_dh_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
202     void *publicvalue, size_t publicvaluelen)
203 {
204 	CK_RV		rv;
205 	uchar_t		privatevalue[MAX_KEY_ATTR_BUFLEN];
206 	uint32_t	privatevaluelen = sizeof (privatevalue);
207 	uchar_t		privateprime[MAX_KEY_ATTR_BUFLEN];
208 	uint32_t	privateprimelen = sizeof (privateprime);
209 	uchar_t		key[MAX_KEY_ATTR_BUFLEN];
210 	uint32_t	keylen;
211 	DHbytekey	k;
212 
213 	rv = soft_get_private_value(basekey, CKA_VALUE, privatevalue,
214 	    &privatevaluelen);
215 	if (rv != CKR_OK) {
216 		return (rv);
217 	}
218 
219 	rv = soft_get_private_value(basekey, CKA_PRIME, privateprime,
220 	    &privateprimelen);
221 	if (rv != CKR_OK) {
222 		goto ret;
223 	}
224 
225 	/* keylen may be 0 if CKA_VALUE_LEN did not specify */
226 	keylen = OBJ_SEC_VALUE_LEN(secretkey);
227 	if (keylen > sizeof (key)) {		/* check for overflow */
228 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
229 		goto ret;
230 	}
231 
232 	k.prime = privateprime;
233 	k.prime_bits = CRYPTO_BYTES2BITS(privateprimelen);
234 	k.value_bits = CRYPTO_BYTES2BITS(privatevaluelen);
235 	k.private_x = privatevalue;
236 	k.public_y = publicvalue;
237 	k.rfunc = NULL;
238 
239 	/* keylen may be modified if it was 0 or conflicts with key type */
240 	rv = dh_key_derive(&k, secretkey->key_type, key, &keylen, 0);
241 
242 	if (rv != CKR_OK) {
243 		goto ret;
244 	}
245 
246 	if ((OBJ_SEC_VALUE(secretkey) = malloc(keylen)) == NULL) {
247 		rv = CKR_HOST_MEMORY;
248 		goto ret;
249 	}
250 
251 	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
252 	(void) memcpy(OBJ_SEC_VALUE(secretkey), key, keylen);
253 
254 ret:
255 	return (rv);
256 }
257