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]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Deimos - cryptographic acceleration based upon Broadcom 582x.
33 #include <sys/types.h>
35 #include <sys/sunddi.h>
37 #include <sys/crypto/spi.h>
38 #include <sys/crypto/dca.h>
44 static void dca_dsa_sign_done(dca_request_t
*, int);
45 static void dca_dsa_verify_done(dca_request_t
*, int);
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
);
57 dca_dsa_sign(crypto_ctx_t
*ctx
, crypto_data_t
*data
, crypto_data_t
*sig
,
58 crypto_req_handle_t req
)
60 dca_request_t
*reqp
= ctx
->cc_provider_private
;
61 dca_t
*dca
= ctx
->cc_provider
;
63 int rv
= CRYPTO_QUEUED
;
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
;
74 /* Return length needed to store the output. */
75 if (dca_length(sig
) < DSASIGLEN
) {
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
;
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.
89 reqp
->dr_job_stat
= DS_DSASIGN
;
90 reqp
->dr_byte_stat
= -1;
93 reqp
->dr_callback
= dca_dsa_sign_done
;
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");
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
;
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
;
121 * The output requires *two* buffers, r followed by s.
123 kaddr
= reqp
->dr_ctx_kaddr
+ reqp
->dr_offset
;
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
;
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
);
137 /* schedule the work by doing a submit */
138 rv
= dca_start(dca
, reqp
, MCR2
, 1);
142 if (rv
!= CRYPTO_QUEUED
&& rv
!= CRYPTO_BUFFER_TOO_SMALL
)
143 (void) dca_free_context(ctx
);
149 dca_dsa_sign_done(dca_request_t
*reqp
, int errno
)
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
;
161 * Set the sig cd_length to zero so it's ready to take the
162 * signature. Have already confirmed its size is adequate.
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");
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");
180 ASSERT(reqp
->dr_kcf_req
!= NULL
);
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",
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
193 if (reqp
->dr_ctx
.atomic
) {
195 ctx
.cc_provider_private
= reqp
;
196 dca_dsactxfree(&ctx
);
201 dca_dsa_verify(crypto_ctx_t
*ctx
, crypto_data_t
*data
, crypto_data_t
*sig
,
202 crypto_req_handle_t req
)
204 dca_request_t
*reqp
= ctx
->cc_provider_private
;
205 dca_t
*dca
= ctx
->cc_provider
;
207 int rv
= CRYPTO_QUEUED
;
210 /* Impossible for verify to be an in-place operation. */
212 rv
= CRYPTO_ARGUMENTS_BAD
;
216 if (dca_length(data
) != SHA1LEN
) {
217 DBG(dca
, DWARN
, "dca_dsa_verify: input length != %d", SHA1LEN
);
218 rv
= CRYPTO_DATA_LEN_RANGE
;
222 if (dca_length(sig
) != DSASIGLEN
) {
223 DBG(dca
, DWARN
, "dca_dsa_verify: signature length != %d",
225 rv
= CRYPTO_SIGNATURE_LEN_RANGE
;
229 /* Don't change the data & sig values for verify. */
231 reqp
->dr_job_stat
= DS_DSAVERIFY
;
232 reqp
->dr_byte_stat
= -1;
237 err
= dca_gather(data
, reqp
->dr_ibuf_kaddr
, SHA1LEN
, 1);
238 if (err
!= CRYPTO_SUCCESS
) {
240 "dca_dsa_vrfy: dca_gather() failed for h");
244 err
= dca_gather(sig
, reqp
->dr_ibuf_kaddr
+SHA1LEN
, DSAPARTLEN
, 1);
245 if (err
!= CRYPTO_SUCCESS
) {
247 "dca_dsa_vrfy: dca_gather() failed for r");
251 err
= dca_gather(sig
, reqp
->dr_ibuf_kaddr
+SHA1LEN
+DSAPARTLEN
,
253 if (err
!= CRYPTO_SUCCESS
) {
255 "dca_dsa_vrfy: dca_gather() failed for s");
260 * As dca_gather() increments the cd_offset and decrements
261 * the cd_length as it copies the data rewind the values ready for
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
);
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
;
279 reqp
->dr_kcf_req
= req
;
280 reqp
->dr_flags
|= DR_SCATTER
| DR_GATHER
;
281 reqp
->dr_callback
= dca_dsa_verify_done
;
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.
288 reqp
->dr_pkt_length
= SHA1LEN
;
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
;
294 reqp
->dr_out_paddr
= reqp
->dr_obuf_paddr
;
295 reqp
->dr_out_len
= DSAPARTLEN
;
296 reqp
->dr_out_next
= 0;
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
);
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
);
314 /* schedule the work by doing a submit */
315 rv
= dca_start(dca
, reqp
, MCR2
, 1);
318 if (rv
!= CRYPTO_QUEUED
&& rv
!= CRYPTO_BUFFER_TOO_SMALL
) {
319 (void) dca_free_context(ctx
);
325 dca_dsa_verify_done(dca_request_t
*reqp
, int errno
)
327 if (errno
== CRYPTO_SUCCESS
) {
328 int count
= DSAPARTLEN
;
329 crypto_data_t
*sig
= reqp
->dr_out
;
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
;
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
;
347 if ((daddr
= dca_bufdaddr(sig
)) == NULL
) {
348 errno
= CRYPTO_ARGUMENTS_BAD
;
352 if (dca_bcmp_reverse(daddr
, reqp
->dr_obuf_kaddr
,
355 errno
= CRYPTO_SIGNATURE_INVALID
;
359 ASSERT(reqp
->dr_kcf_req
!= NULL
);
361 /* notify framework that request is completed */
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",
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
373 if (reqp
->dr_ctx
.atomic
) {
375 ctx
.cc_provider_private
= reqp
;
376 dca_dsactxfree(&ctx
);
382 dca_dsainit(crypto_ctx_t
*ctx
, crypto_mechanism_t
*mechanism
,
383 crypto_key_t
*key
, int kmflag
, int mode
)
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
;
395 if ((reqp
= dca_getreq(dca
, MCR2
, 1)) == NULL
) {
397 "dca_dsainit: unable to allocate request for DSA");
398 rv
= CRYPTO_HOST_MEMORY
;
402 ctx
->cc_provider_private
= reqp
;
403 reqp
->dr_ctx
.ctx_cm_type
= mechanism
->cm_type
;
405 if ((attr
= dca_get_key_attr(key
)) == NULL
) {
406 DBG(NULL
, DWARN
, "dca_dsainit: key attributes missing");
407 rv
= CRYPTO_KEY_TYPE_INCONSISTENT
;
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
;
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
;
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
;
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
;
443 if (plen
== 0 || qlen
== 0 || glen
== 0 || xlen
== 0) {
444 rv
= CRYPTO_ARGUMENTS_BAD
;
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
;
455 if (qlen
> DSAPARTLEN
) {
456 DBG(NULL
, DWARN
, "dca_dsainit: q is too long (%d)", qlen
);
457 rv
= CRYPTO_KEY_SIZE_RANGE
;
461 if (mode
== DCA_DSA_SIGN
&& xlen
> DSAPARTLEN
) {
463 "dca_dsainit: private key is too long (%d)", xlen
);
464 rv
= CRYPTO_KEY_SIZE_RANGE
;
469 * Setup the key partion of the request.
472 pbits
= dca_bitlen(p
, plen
);
473 padjlen
= dca_padfull(pbits
);
475 /* accounts for leading context words */
476 if (mode
== DCA_DSA_SIGN
) {
477 ctxlen
= CTX_DSABIGNUMS
+ DSAPARTLEN
+ (padjlen
* 2) +
479 PUTCTX16(reqp
, CTX_CMD
, CMD_DSASIGN
);
481 ctxlen
= CTX_DSABIGNUMS
+ DSAPARTLEN
+ (padjlen
* 3);
482 PUTCTX16(reqp
, CTX_CMD
, CMD_DSAVERIFY
);
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
);
491 PUTCTX16(reqp
, CTX_DSARNG
, 0);
492 PUTCTX16(reqp
, CTX_DSAPLEN
, pbits
);
494 kaddr
= reqp
->dr_ctx_kaddr
+ CTX_DSABIGNUMS
;
496 /* store the bignums */
497 dca_reverse(q
, kaddr
, qlen
, DSAPARTLEN
);
500 dca_reverse(p
, kaddr
, plen
, padjlen
);
503 dca_reverse(g
, kaddr
, glen
, padjlen
);
506 if (mode
== DCA_DSA_SIGN
) {
507 dca_reverse(x
, kaddr
, xlen
, DSAPARTLEN
);
510 dca_reverse(x
, kaddr
, xlen
, padjlen
);
514 return (CRYPTO_SUCCESS
);
523 dca_dsactxfree(void *arg
)
525 crypto_ctx_t
*ctx
= (crypto_ctx_t
*)arg
;
526 dca_request_t
*reqp
= ctx
->cc_provider_private
;
531 reqp
->dr_ctx
.ctx_cm_type
= 0;
532 reqp
->dr_ctx
.atomic
= 0;
534 dca_destroyreq(reqp
);
538 ctx
->cc_provider_private
= NULL
;
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
)
547 crypto_ctx_t ctx
; /* on the stack */
550 ctx
.cc_provider
= provider
;
551 ctx
.cc_session
= session_id
;
553 rv
= dca_dsainit(&ctx
, mechanism
, key
, kmflag
, mode
);
554 if (rv
!= CRYPTO_SUCCESS
) {
555 DBG(NULL
, DWARN
, "dca_dsaatomic: dca_dsainit() failed");
560 * Set the atomic flag so that the hardware callback function
561 * will free the context.
563 ((dca_request_t
*)ctx
.cc_provider_private
)->dr_ctx
.atomic
= 1;
565 if (mode
== DCA_DSA_SIGN
) {
566 rv
= dca_dsa_sign(&ctx
, data
, sig
, req
);
568 ASSERT(mode
== DCA_DSA_VRFY
);
569 rv
= dca_dsa_verify(&ctx
, data
, sig
, req
);
573 * The context will be freed in the hardware callback function if it
576 if (rv
!= CRYPTO_QUEUED
)
577 dca_dsactxfree(&ctx
);