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 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Deimos - cryptographic acceleration based upon Broadcom 582x.
29 */
30
31 #include <sys/types.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/kmem.h>
35 #include <sys/crypto/spi.h>
36 #include <sys/crypto/dca.h>
37
38 /*
39 * DSA implementation.
40 */
41
42 static void dca_dsa_sign_done(dca_request_t *, int);
43 static void dca_dsa_verify_done(dca_request_t *, int);
44
45
46 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
47 crypto_req_handle_t req);
48 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
49 crypto_req_handle_t req);
50 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
51 crypto_key_t *key, int kmflag, int mode);
52
53
54 int
dca_dsa_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)55 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
56 crypto_req_handle_t req)
57 {
58 dca_request_t *reqp = ctx->cc_provider_private;
59 dca_t *dca = ctx->cc_provider;
60 int err;
61 int rv = CRYPTO_QUEUED;
62 caddr_t kaddr;
63 size_t buflen;
64
65 buflen = dca_length(data);
66 if (buflen != SHA1LEN) {
67 DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN);
68 rv = CRYPTO_DATA_LEN_RANGE;
69 goto errout;
70 }
71
72 /* Return length needed to store the output. */
73 if (dca_length(sig) < DSASIGLEN) {
74 DBG(dca, DWARN,
75 "dca_dsa_sign: output buffer too short (%d < %d)",
76 dca_length(sig), DSASIGLEN);
77 sig->cd_length = DSASIGLEN;
78 rv = CRYPTO_BUFFER_TOO_SMALL;
79 goto errout;
80 }
81
82 /*
83 * Don't change the data values of the data crypto_data_t structure
84 * yet. Only reset the sig cd_length to zero before writing to it.
85 */
86
87 reqp->dr_job_stat = DS_DSASIGN;
88 reqp->dr_byte_stat = -1;
89 reqp->dr_in = data;
90 reqp->dr_out = sig;
91 reqp->dr_callback = dca_dsa_sign_done;
92
93 reqp->dr_kcf_req = req;
94 /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */
95 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
96 if (err != CRYPTO_SUCCESS) {
97 DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed");
98 rv = err;
99 goto errout;
100 }
101
102
103 /* sync the input buffer */
104 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN,
105 DDI_DMA_SYNC_FORDEV);
106 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
107 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
108 reqp->destroy = TRUE;
109 rv = CRYPTO_DEVICE_ERROR;
110 goto errout;
111 }
112
113 reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
114 reqp->dr_in_next = 0;
115 reqp->dr_in_len = SHA1LEN;
116 reqp->dr_pkt_length = buflen;
117
118 /*
119 * The output requires *two* buffers, r followed by s.
120 */
121 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
122
123 /* r */
124 reqp->dr_out_paddr = reqp->dr_obuf_paddr;
125 reqp->dr_out_len = DSAPARTLEN;
126 reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset;
127
128 /* s */
129 PUTDESC32(reqp, kaddr, DESC_BUFADDR,
130 reqp->dr_obuf_paddr + DSAPARTLEN);
131 PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
132 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
133 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
134
135 /* schedule the work by doing a submit */
136 rv = dca_start(dca, reqp, MCR2, 1);
137
138 errout:
139
140 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
141 (void) dca_free_context(ctx);
142
143 return (rv);
144 }
145
146 static void
dca_dsa_sign_done(dca_request_t * reqp,int errno)147 dca_dsa_sign_done(dca_request_t *reqp, int errno)
148 {
149 if (errno == CRYPTO_SUCCESS) {
150 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN,
151 DDI_DMA_SYNC_FORKERNEL);
152 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
153 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
154 reqp->destroy = TRUE;
155 errno = CRYPTO_DEVICE_ERROR;
156 goto errout;
157 }
158 /*
159 * Set the sig cd_length to zero so it's ready to take the
160 * signature. Have already confirmed its size is adequate.
161 */
162 reqp->dr_out->cd_length = 0;
163 errno = dca_scatter(reqp->dr_obuf_kaddr,
164 reqp->dr_out, DSAPARTLEN, 1);
165 if (errno != CRYPTO_SUCCESS) {
166 DBG(reqp->dr_dca, DWARN,
167 "dca_dsa_sign_done: dca_scatter() failed");
168 goto errout;
169 }
170 errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN,
171 reqp->dr_out, DSAPARTLEN, 1);
172 if (errno != CRYPTO_SUCCESS) {
173 DBG(reqp->dr_dca, DWARN,
174 "dca_dsa_sign_done: dca_scatter() failed");
175 }
176 }
177 errout:
178 ASSERT(reqp->dr_kcf_req != NULL);
179
180 /* notify framework that request is completed */
181 crypto_op_notification(reqp->dr_kcf_req, errno);
182 DBG(reqp->dr_dca, DINTR,
183 "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification",
184 errno);
185
186 /*
187 * For non-atomic operations, reqp will be freed in the kCF
188 * callback function since it may be needed again if
189 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
190 */
191 if (reqp->dr_ctx.atomic) {
192 crypto_ctx_t ctx;
193 ctx.cc_provider_private = reqp;
194 dca_dsactxfree(&ctx);
195 }
196 }
197
198 int
dca_dsa_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)199 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
200 crypto_req_handle_t req)
201 {
202 dca_request_t *reqp = ctx->cc_provider_private;
203 dca_t *dca = ctx->cc_provider;
204 int err;
205 int rv = CRYPTO_QUEUED;
206 caddr_t kaddr;
207
208 /* Impossible for verify to be an in-place operation. */
209 if (sig == NULL) {
210 rv = CRYPTO_ARGUMENTS_BAD;
211 goto errout;
212 }
213
214 if (dca_length(data) != SHA1LEN) {
215 DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN);
216 rv = CRYPTO_DATA_LEN_RANGE;
217 goto errout;
218 }
219
220 if (dca_length(sig) != DSASIGLEN) {
221 DBG(dca, DWARN, "dca_dsa_verify: signature length != %d",
222 DSASIGLEN);
223 rv = CRYPTO_SIGNATURE_LEN_RANGE;
224 goto errout;
225 }
226
227 /* Don't change the data & sig values for verify. */
228
229 reqp->dr_job_stat = DS_DSAVERIFY;
230 reqp->dr_byte_stat = -1;
231
232 /*
233 * Grab h, r and s.
234 */
235 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
236 if (err != CRYPTO_SUCCESS) {
237 DBG(dca, DWARN,
238 "dca_dsa_vrfy: dca_gather() failed for h");
239 rv = err;
240 goto errout;
241 }
242 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1);
243 if (err != CRYPTO_SUCCESS) {
244 DBG(dca, DWARN,
245 "dca_dsa_vrfy: dca_gather() failed for r");
246 rv = err;
247 goto errout;
248 }
249 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN,
250 DSAPARTLEN, 1);
251 if (err != CRYPTO_SUCCESS) {
252 DBG(dca, DWARN,
253 "dca_dsa_vrfy: dca_gather() failed for s");
254 rv = err;
255 goto errout;
256 }
257 /*
258 * As dca_gather() increments the cd_offset and decrements
259 * the cd_length as it copies the data rewind the values ready for
260 * the final compare.
261 */
262 sig->cd_offset -= (DSAPARTLEN * 2);
263 sig->cd_length += (DSAPARTLEN * 2);
264 /* sync the input buffer */
265 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN,
266 DDI_DMA_SYNC_FORDEV);
267
268 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
269 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
270 reqp->destroy = TRUE;
271 rv = CRYPTO_DEVICE_ERROR;
272 goto errout;
273 }
274
275 reqp->dr_in = data;
276 reqp->dr_out = sig;
277 reqp->dr_kcf_req = req;
278 reqp->dr_flags |= DR_SCATTER | DR_GATHER;
279 reqp->dr_callback = dca_dsa_verify_done;
280
281 /*
282 * Input requires three buffers. m, followed by r, followed by s.
283 * In order to deal with things cleanly, we reverse the signature
284 * into the buffer and then fix up the pointers.
285 */
286 reqp->dr_pkt_length = SHA1LEN;
287
288 reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
289 reqp->dr_in_len = SHA1LEN;
290 reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset;
291
292 reqp->dr_out_paddr = reqp->dr_obuf_paddr;
293 reqp->dr_out_len = DSAPARTLEN;
294 reqp->dr_out_next = 0;
295
296 /* setup 1st chain for r */
297 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
298 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN);
299 PUTDESC32(reqp, kaddr, DESC_NEXT,
300 reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE);
301 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
302 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
303
304 /* and 2nd chain for s */
305 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE;
306 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr +
307 SHA1LEN + DSAPARTLEN);
308 PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
309 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
310 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
311
312 /* schedule the work by doing a submit */
313 rv = dca_start(dca, reqp, MCR2, 1);
314
315 errout:
316 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
317 (void) dca_free_context(ctx);
318 }
319 return (rv);
320 }
321
322 static void
dca_dsa_verify_done(dca_request_t * reqp,int errno)323 dca_dsa_verify_done(dca_request_t *reqp, int errno)
324 {
325 if (errno == CRYPTO_SUCCESS) {
326 int count = DSAPARTLEN;
327 crypto_data_t *sig = reqp->dr_out;
328 caddr_t daddr;
329
330 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count,
331 DDI_DMA_SYNC_FORKERNEL);
332 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
333 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
334 reqp->destroy = TRUE;
335 errno = CRYPTO_DEVICE_ERROR;
336 goto errout;
337 }
338
339 /* Can only handle a contiguous data buffer currently. */
340 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) {
341 errno = CRYPTO_SIGNATURE_INVALID;
342 goto errout;
343 }
344
345 if ((daddr = dca_bufdaddr(sig)) == NULL) {
346 errno = CRYPTO_ARGUMENTS_BAD;
347 goto errout;
348 }
349
350 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr,
351 DSAPARTLEN) != 0) {
352 /* VERIFY FAILED */
353 errno = CRYPTO_SIGNATURE_INVALID;
354 }
355 }
356 errout:
357 ASSERT(reqp->dr_kcf_req != NULL);
358
359 /* notify framework that request is completed */
360
361 crypto_op_notification(reqp->dr_kcf_req, errno);
362 DBG(reqp->dr_dca, DINTR,
363 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification",
364 errno);
365
366 /*
367 * For non-atomic operations, reqp will be freed in the kCF
368 * callback function since it may be needed again if
369 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
370 */
371 if (reqp->dr_ctx.atomic) {
372 crypto_ctx_t ctx;
373 ctx.cc_provider_private = reqp;
374 dca_dsactxfree(&ctx);
375 }
376 }
377
378 /* ARGSUSED */
379 int
dca_dsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,int mode)380 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
381 crypto_key_t *key, int kmflag, int mode)
382 {
383 crypto_object_attribute_t *attr;
384 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0;
385 uchar_t *p, *q, *g, *x;
386 dca_request_t *reqp = NULL;
387 dca_t *dca = (dca_t *)ctx->cc_provider;
388 int rv = CRYPTO_SUCCESS;
389 unsigned pbits, padjlen;
390 uint16_t ctxlen;
391 caddr_t kaddr;
392
393 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
394 dca_error(dca,
395 "dca_dsainit: unable to allocate request for DSA");
396 rv = CRYPTO_HOST_MEMORY;
397 goto errout;
398 }
399
400 ctx->cc_provider_private = reqp;
401 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
402
403 if ((attr = dca_get_key_attr(key)) == NULL) {
404 DBG(NULL, DWARN, "dca_dsainit: key attributes missing");
405 rv = CRYPTO_KEY_TYPE_INCONSISTENT;
406 goto errout;
407 }
408
409 /* Prime */
410 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME,
411 (void *) &p, &plen)) {
412 DBG(NULL, DWARN, "dca_dsainit: prime key value not present");
413 rv = CRYPTO_ARGUMENTS_BAD;
414 goto errout;
415 }
416
417 /* Subprime */
418 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME,
419 (void *) &q, &qlen)) {
420 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present");
421 rv = CRYPTO_ARGUMENTS_BAD;
422 goto errout;
423 }
424
425 /* Base */
426 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE,
427 (void *) &g, &glen)) {
428 DBG(NULL, DWARN, "dca_dsainit: base key value not present");
429 rv = CRYPTO_ARGUMENTS_BAD;
430 goto errout;
431 }
432
433 /* Value */
434 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE,
435 (void *) &x, &xlen)) {
436 DBG(NULL, DWARN, "dca_dsainit: value key not present");
437 rv = CRYPTO_ARGUMENTS_BAD;
438 goto errout;
439 }
440
441 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) {
442 rv = CRYPTO_ARGUMENTS_BAD;
443 goto errout;
444 }
445
446 if (plen > DSA_MAX_KEY_LEN) {
447 /* maximum 1Kbit key */
448 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen);
449 rv = CRYPTO_KEY_SIZE_RANGE;
450 goto errout;
451 }
452
453 if (qlen > DSAPARTLEN) {
454 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen);
455 rv = CRYPTO_KEY_SIZE_RANGE;
456 goto errout;
457 }
458
459 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) {
460 DBG(NULL, DWARN,
461 "dca_dsainit: private key is too long (%d)", xlen);
462 rv = CRYPTO_KEY_SIZE_RANGE;
463 goto errout;
464 }
465
466 /*
467 * Setup the key partion of the request.
468 */
469
470 pbits = dca_bitlen(p, plen);
471 padjlen = dca_padfull(pbits);
472
473 /* accounts for leading context words */
474 if (mode == DCA_DSA_SIGN) {
475 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) +
476 DSAPARTLEN;
477 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN);
478 } else {
479 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3);
480 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY);
481 }
482
483 PUTCTX16(reqp, CTX_LENGTH, ctxlen);
484 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1);
485 PUTCTX16(reqp, CTX_DSARSVD, 0);
486 if (mode == DCA_DSA_SIGN)
487 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN);
488 else
489 PUTCTX16(reqp, CTX_DSARNG, 0);
490 PUTCTX16(reqp, CTX_DSAPLEN, pbits);
491
492 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS;
493
494 /* store the bignums */
495 dca_reverse(q, kaddr, qlen, DSAPARTLEN);
496 kaddr += DSAPARTLEN;
497
498 dca_reverse(p, kaddr, plen, padjlen);
499 kaddr += padjlen;
500
501 dca_reverse(g, kaddr, glen, padjlen);
502 kaddr += padjlen;
503
504 if (mode == DCA_DSA_SIGN) {
505 dca_reverse(x, kaddr, xlen, DSAPARTLEN);
506 kaddr += DSAPARTLEN;
507 } else {
508 dca_reverse(x, kaddr, xlen, padjlen);
509 kaddr += padjlen;
510 }
511
512 return (CRYPTO_SUCCESS);
513
514 errout:
515
516 dca_dsactxfree(ctx);
517 return (rv);
518 }
519
520 void
dca_dsactxfree(void * arg)521 dca_dsactxfree(void *arg)
522 {
523 crypto_ctx_t *ctx = (crypto_ctx_t *)arg;
524 dca_request_t *reqp = ctx->cc_provider_private;
525
526 if (reqp == NULL)
527 return;
528
529 reqp->dr_ctx.ctx_cm_type = 0;
530 reqp->dr_ctx.atomic = 0;
531 if (reqp->destroy)
532 dca_destroyreq(reqp);
533 else
534 dca_freereq(reqp);
535
536 ctx->cc_provider_private = NULL;
537 }
538
539 int
dca_dsaatomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * sig,int kmflag,crypto_req_handle_t req,int mode)540 dca_dsaatomic(crypto_provider_handle_t provider,
541 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
542 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig,
543 int kmflag, crypto_req_handle_t req, int mode)
544 {
545 crypto_ctx_t ctx; /* on the stack */
546 int rv;
547
548 ctx.cc_provider = provider;
549 ctx.cc_session = session_id;
550
551 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode);
552 if (rv != CRYPTO_SUCCESS) {
553 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed");
554 return (rv);
555 }
556
557 /*
558 * Set the atomic flag so that the hardware callback function
559 * will free the context.
560 */
561 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
562
563 if (mode == DCA_DSA_SIGN) {
564 rv = dca_dsa_sign(&ctx, data, sig, req);
565 } else {
566 ASSERT(mode == DCA_DSA_VRFY);
567 rv = dca_dsa_verify(&ctx, data, sig, req);
568 }
569
570 /*
571 * The context will be freed in the hardware callback function if it
572 * is queued
573 */
574 if (rv != CRYPTO_QUEUED)
575 dca_dsactxfree(&ctx);
576
577 return (rv);
578 }
579