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