1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2014 Jason King.
14 */
15 #include <sys/debug.h>
16 #include <security/cryptoki.h>
17 #include <umem.h>
18 #include <limits.h>
19 #include <string.h>
20 #include "defs.h"
21 #include "ikev2.h"
22 #include "prf.h"
23 #include "pkcs11.h"
24
25 typedef struct prf_alg_s {
26 int i2alg;
27 CK_MECHANISM_TYPE hash;
28 CK_MECHANISM_TYPE hmac;
29 size_t inlen; /* in bytes */
30 size_t outlen; /* in bytes */
31 boolean_t pad;
32 } prf_alg_t;
33
34 #define MECHPAD(_i2, _p11, _in, _out) { \
35 .i2alg = IKEV2_PRF_HMAC_ ## _i2, \
36 .hash = CKM_ ## _p11, \
37 .hmac = CKM_ ## _p11 ## _HMAC, \
38 .inlen = _in, \
39 .outlen = _out, \
40 .pad = B_TRUE \
41 }
42
43 static const prf_alg_t prf_tbl[] = {
44 MECHPAD(MD5, MD5, 64, 16),
45 MECHPAD(SHA1, SHA_1, 64, 16),
46 MECHPAD(SHA2_256, SHA256, 64, 32),
47 MECHPAD(SHA2_384, SHA384, 128, 48),
48 MECHPAD(SHA2_512, SHA512, 128, 64)
49 };
50 #define N_PRF (sizeof (prf_tbl) / sizeof (prf_alg_t))
51
52 static const prf_alg_t *get_alg(int);
53 static CK_RV prfplus_update(prfp_t *);
54
55 /*
56 * Create a PKCS11 key object that can be used in C_Sign* operations with
57 * a scatter/gather-like listing of source input.
58 *
59 * Args:
60 * alg The PRF algorithm this will be used with
61 * src An array of buf_t's pointing to the source key
62 * n The number of buf_t's we have
63 * kp Pointer to CK_OBJECT_HANDLE to write the resulting key
64 * object.
65 * Returns:
66 * CKR_OK Success
67 */
68 CK_RV
69 prf_genkey(int alg, buf_t *restrict src, size_t n,
70 CK_OBJECT_HANDLE_PTR restrict kp)
71 {
72 const prf_alg_t *algp;
73
74 CK_RV rc;
75 CK_OBJECT_CLASS cls = CKO_SECRET_KEY;
76 CK_KEY_TYPE kt = CKK_GENERIC_SECRET;
77 CK_BBOOL false_v = CK_FALSE;
78 CK_MECHANISM_TYPE hmac;
79 CK_ATTRIBUTE template[] = {
80 { CKA_VALUE, NULL_PTR, 0 }, /* filled in later */
81 { CKA_CLASS, &cls, sizeof (cls) },
82 { CKA_KEY_TYPE, &kt, sizeof (kt) },
83 /* XXX: is this actually needed? */
84 { CKA_ALLOWED_MECHANISMS, &hmac, sizeof (hmac) },
85 { CKA_MODIFIABLE, &false_v, sizeof (false_v) }
86 };
87 buf_t key = { 0 };
88 size_t srclen;
89 ulong_t keylen = 0; /* actual length */
90
91 rc = CKR_OK;
92
93 VERIFY((algp = get_alg(alg)) != NULL);
94 hmac = algp->hmac;
95
96 srclen = 0;
97 for (size_t i = 0; i < n; i++)
98 srclen += buf_left(&src[i]);
99
100 if (srclen < algp->inlen && algp->pad)
101 keylen = algp->inlen;
102 else
103 keylen = srclen;
104
105 if (!buf_alloc(&key, keylen)) {
106 rc = CKR_HOST_MEMORY;
107 goto done;
108 }
109 buf_set_write(&key);
110
111 /*
112 * The HMAC standards specify what an implementation should do when
113 * the given key length doesn't match the preferred key length (either
114 * pad or run the digest alg on the key to yield a value of the desired
115 * length), so we should not need to worry about this.
116 */
117 VERIFY3U(buf_copy(&key, src, n), <=, keylen);
118
119 template[0].pValue = key.b_buf;
120 template[0].ulValueLen = keylen;
121
122 rc = C_CreateObject(p11h, template,
123 sizeof (template) / sizeof (CK_ATTRIBUTE), kp);
124
125 done:
126 buf_free(&key);
127 return (rc);
128 }
129
130 /*
131 * Run the given PRF algorithm for the given key and seed and place
132 * result into out.
133 */
134 CK_RV
135 prf(int alg, CK_OBJECT_HANDLE key, buf_t *restrict seed, size_t nseed,
136 buf_t *restrict out)
137 {
138 const prf_alg_t *algp;
139 CK_MECHANISM mech;
140 CK_RV rc = CKR_OK;
141 CK_ULONG len;
142
143 VERIFY3P((algp = get_alg(alg)), !=, NULL);
144 VERIFY3U(out->b_len, >=, algp->outlen);
145
146 mech.mechanism = algp->hmac;
147 mech.pParameter = NULL;
148 mech.ulParameterLen = 0;
149
150 if ((rc = C_SignInit(p11h, &mech, key)) != CKR_OK)
151 return (rc);
152
153 for (size_t i = 0; i < nseed; i++, seed) {
154 BUF_IS_READ(seed);
155 rc = C_SignUpdate(p11h, seed->b_ptr, buf_left(seed));
156 /* XXX: should we still call C_SignFinal? */
157 if (rc != CKR_OK)
158 return (rc);
159 }
160
161 BUF_IS_WRITE(out);
162
163 len = buf_left(out);
164 rc = C_SignFinal(p11h, out->b_ptr, &len);
165 if (rc == CKR_OK)
166 VERIFY3U(len, ==, buf_left(out));
167
168 buf_skip(out, len);
169 return (rc);
170 }
171
172 /*
173 * Inititalize a prf+ instance for the given algorithm, key, and seed.
174 */
175 CK_RV
176 prfplus_init(prfp_t *restrict prfp, int alg, CK_OBJECT_HANDLE key,
177 const buf_t *restrict seed)
178 {
179 const prf_alg_t *algp;
180 CK_RV rc = CKR_OK;
181
182 (void) memset(prfp, 0, sizeof (*prfp));
183
184 VERIFY((algp = get_alg(alg)) != NULL);
185
186 if (!buf_alloc(&prfp->tbuf[0], algp->outlen) ||
187 !buf_alloc(&prfp->tbuf[1], algp->outlen) ||
188 !buf_alloc(&prfp->seed, buf_left(seed))) {
189 rc = CKR_HOST_MEMORY;
190 goto error;
191 }
192
193 /* stash our own copy of the seed */
194 (void) buf_copy(&prfp->seed, seed, 1);
195 VERIFY(!buf_eof(&prfp->seed));
196
197 /*
198 * Per RFC5996 2.13, prf+(K, S) = T1 | T2 | T3 | T4 | ...
199 *
200 * where:
201 * T1 = prf (K, S | 0x01)
202 * T2 = prf (K, T1 | S | 0x02)
203 * T3 = prf (K, T2 | S | 0x03)
204 * T4 = prf (K, T3 | S | 0x04)
205 *
206 * As such, we keep a list of buf_t's for each of the three components
207 * Since the last two never change location, they are set now, while
208 * the first points to either prfp->tbuf[0] or prfp->tbuf[1], based
209 * on the value of prfp->n
210 */
211 prfp->prf_arg[1] = prfp->seed;
212 prfp->prf_arg[2].b_ptr = prfp->prf_arg[2].b_buf = &prfp->n;
213 prfp->prf_arg[2].b_len = sizeof (prfp->n);
214 prfp->n = 1;
215
216 buf_set_read(&prfp->prf_arg[1]);
217 buf_set_read(&prfp->prf_arg[2]);
218
219 /*
220 * Fill prfp->tbuf[1] with T1. T1 is defined as:
221 * T1 = prf (K, S | 0x01)
222 * Note that this is different from subsequent iterations, hence
223 * starting at prfp->prf_arg[1], not prfp->arg[0]
224 */
225 rc = prf(alg, prfp->key, &prfp->prf_arg[1], 2, &prfp->tbuf[1]);
226 return (rc);
227
228 error:
229 prfplus_fini(prfp);
230 return (rc);
231 }
232
233 /*
234 * Fill out with the result of the prf+ function.
235 */
236 CK_RV
237 prfplus(prfp_t *restrict prfp, buf_t *restrict out)
238 {
239 const prf_alg_t *algp;
240 buf_t t;
241 buf_t outcopy;
242 CK_RV rc = CKR_OK;
243
244 algp = get_alg(prfp->i2alg);
245
246 /* generate a local cache of out so we can manipulate the ptr and len */
247 outcopy = *out;
248 buf_set_write(&outcopy);
249
250 while (buf_left(&outcopy) > 0) {
251 size_t chunk;
252
253 chunk = buf_left(&outcopy);
254
255 if (prfp->n & 0x01)
256 t = prfp->tbuf[1];
257 else
258 t = prfp->tbuf[0];
259
260 t.b_ptr += prfp->pos;
261 t.b_len -= prfp->pos;
262
263 if (t.b_len == 0) {
264 if ((rc = prfplus_update(prfp)) != CKR_OK)
265 goto done;
266 continue;
267 }
268
269 if (chunk > t.b_len)
270 chunk = t.b_len;
271
272 VERIFY(buf_copy(&outcopy, &t, chunk) == chunk);
273 buf_skip(&outcopy, chunk);
274 prfp->pos += chunk;
275 }
276
277 done:
278 return (rc);
279 }
280
281 /*
282 * Perform a prf+ iteration
283 */
284 static CK_RV
285 prfplus_update(prfp_t *prfp)
286 {
287 buf_t *dest;
288 CK_RV rc = CKR_OK;
289
290 ASSERT(prfp->n >= 1);
291
292 if (prfp->n == 0xff) {
293 /* XXX: log error */
294 return (CKR_GENERAL_ERROR);
295 }
296
297 if (++prfp->n & 0x01) {
298 prfp->prf_arg[1] = prfp->tbuf[1];
299 dest = &prfp->tbuf[0];
300 } else {
301 prfp->prf_arg[0] = prfp->tbuf[0];
302 dest = &prfp->tbuf[1];
303 }
304
305 rc = prf(prfp->i2alg, prfp->key, prfp->prf_arg, 3, dest);
306 prfp->pos = 0;
307 return (rc);
308 }
309
310 void
311 prfplus_fini(prfp_t *prfp)
312 {
313 if (prfp == NULL)
314 return;
315
316 buf_free(&prfp->tbuf[0]);
317 buf_free(&prfp->tbuf[1]);
318 buf_free(&prfp->seed);
319 (void) memset(prfp, 0, sizeof (*prfp));
320 }
321
322 CK_MECHANISM_TYPE
323 ikev2_prf_to_p11(int prf)
324 {
325 switch (prf) {
326 case IKEV2_PRF_HMAC_MD5:
327 return (CKM_MD5_HMAC);
328 case IKEV2_PRF_HMAC_SHA1:
329 return (CKM_SHA_1_HMAC);
330 case IKEV2_PRF_HMAC_SHA2_256:
331 return (CKM_SHA256_HMAC);
332 case IKEV2_PRF_HMAC_SHA2_384:
333 return (CKM_SHA384_HMAC);
334 case IKEV2_PRF_HMAC_SHA2_512:
335 return (CKM_SHA512_HMAC);
336 }
337
338 INVALID("invalid hmac value");
339
340 /*NOTREACHED*/
341 return (0);
342 }
343
344 size_t
345 ikev2_prf_keylen(int prf)
346 {
347 return (get_alg(prf)->inlen);
348 }
349
350 /*
351 * Get the information for a given algorithm, or NULL of not found
352 */
353 static const prf_alg_t *
354 get_alg(int i2alg)
355 {
356 for (int i = 0; i < N_PRF; i++) {
357 if (prf_tbl[i].i2alg == i2alg)
358 return (&prf_tbl[i]);
359 }
360 return (NULL);
361 }