1906Sgm89044 /*
2906Sgm89044 * CDDL HEADER START
3906Sgm89044 *
4906Sgm89044 * The contents of this file are subject to the terms of the
5906Sgm89044 * Common Development and Distribution License (the "License").
6906Sgm89044 * You may not use this file except in compliance with the License.
7906Sgm89044 *
8906Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9906Sgm89044 * or http://www.opensolaris.org/os/licensing.
10906Sgm89044 * See the License for the specific language governing permissions
11906Sgm89044 * and limitations under the License.
12906Sgm89044 *
13906Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each
14906Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15906Sgm89044 * If applicable, add the following below this CDDL HEADER, with the
16906Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying
17906Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner]
18906Sgm89044 *
19906Sgm89044 * CDDL HEADER END
20906Sgm89044 */
21906Sgm89044
22906Sgm89044 /*
23*3096Skrishna * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24906Sgm89044 * Use is subject to license terms.
25906Sgm89044 */
26906Sgm89044
27906Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI"
28906Sgm89044
29906Sgm89044 /*
30906Sgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x.
31906Sgm89044 */
32906Sgm89044
33906Sgm89044 #include <sys/types.h>
34906Sgm89044 #include <sys/ddi.h>
35906Sgm89044 #include <sys/sunddi.h>
36906Sgm89044 #include <sys/kmem.h>
37906Sgm89044 #include <sys/crypto/spi.h>
38906Sgm89044 #include <sys/crypto/dca.h>
39906Sgm89044
40906Sgm89044 /*
41906Sgm89044 * DSA implementation.
42906Sgm89044 */
43906Sgm89044
44906Sgm89044 static void dca_dsa_sign_done(dca_request_t *, int);
45906Sgm89044 static void dca_dsa_verify_done(dca_request_t *, int);
46906Sgm89044
47906Sgm89044
48906Sgm89044 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
49906Sgm89044 crypto_req_handle_t req);
50906Sgm89044 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
51906Sgm89044 crypto_req_handle_t req);
52906Sgm89044 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
53906Sgm89044 crypto_key_t *key, int kmflag, int mode);
54906Sgm89044
55906Sgm89044
56906Sgm89044 int
dca_dsa_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)57906Sgm89044 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
58906Sgm89044 crypto_req_handle_t req)
59906Sgm89044 {
60906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
61906Sgm89044 dca_t *dca = ctx->cc_provider;
62906Sgm89044 int err;
63906Sgm89044 int rv = CRYPTO_QUEUED;
64906Sgm89044 caddr_t kaddr;
65906Sgm89044 size_t buflen;
66906Sgm89044
67906Sgm89044 buflen = dca_length(data);
68906Sgm89044 if (buflen != SHA1LEN) {
69906Sgm89044 DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN);
70906Sgm89044 rv = CRYPTO_DATA_LEN_RANGE;
71906Sgm89044 goto errout;
72906Sgm89044 }
73906Sgm89044
74906Sgm89044 /* Return length needed to store the output. */
75906Sgm89044 if (dca_length(sig) < DSASIGLEN) {
76906Sgm89044 DBG(dca, DWARN,
77906Sgm89044 "dca_dsa_sign: output buffer too short (%d < %d)",
78906Sgm89044 dca_length(sig), DSASIGLEN);
79906Sgm89044 sig->cd_length = DSASIGLEN;
80906Sgm89044 rv = CRYPTO_BUFFER_TOO_SMALL;
81906Sgm89044 goto errout;
82906Sgm89044 }
83906Sgm89044
84906Sgm89044 /*
85906Sgm89044 * Don't change the data values of the data crypto_data_t structure
86906Sgm89044 * yet. Only reset the sig cd_length to zero before writing to it.
87906Sgm89044 */
88906Sgm89044
89906Sgm89044 reqp->dr_job_stat = DS_DSASIGN;
90906Sgm89044 reqp->dr_byte_stat = -1;
91906Sgm89044 reqp->dr_in = data;
92906Sgm89044 reqp->dr_out = sig;
93906Sgm89044 reqp->dr_callback = dca_dsa_sign_done;
94906Sgm89044
95906Sgm89044 reqp->dr_kcf_req = req;
96906Sgm89044 /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */
97906Sgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
98906Sgm89044 if (err != CRYPTO_SUCCESS) {
99906Sgm89044 DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed");
100906Sgm89044 rv = err;
101906Sgm89044 goto errout;
102906Sgm89044 }
103906Sgm89044
104906Sgm89044
105906Sgm89044 /* sync the input buffer */
106906Sgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN,
107906Sgm89044 DDI_DMA_SYNC_FORDEV);
108906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
109906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
110906Sgm89044 reqp->destroy = TRUE;
111906Sgm89044 rv = CRYPTO_DEVICE_ERROR;
112906Sgm89044 goto errout;
113906Sgm89044 }
114906Sgm89044
115906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
116906Sgm89044 reqp->dr_in_next = 0;
117906Sgm89044 reqp->dr_in_len = SHA1LEN;
118906Sgm89044 reqp->dr_pkt_length = buflen;
119906Sgm89044
120906Sgm89044 /*
121906Sgm89044 * The output requires *two* buffers, r followed by s.
122906Sgm89044 */
123906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
124906Sgm89044
125906Sgm89044 /* r */
126906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr;
127906Sgm89044 reqp->dr_out_len = DSAPARTLEN;
128906Sgm89044 reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset;
129906Sgm89044
130906Sgm89044 /* s */
131906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR,
132906Sgm89044 reqp->dr_obuf_paddr + DSAPARTLEN);
133906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
134906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
135906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
136906Sgm89044
137906Sgm89044 /* schedule the work by doing a submit */
138906Sgm89044 rv = dca_start(dca, reqp, MCR2, 1);
139906Sgm89044
140906Sgm89044 errout:
141906Sgm89044
142906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
143906Sgm89044 (void) dca_free_context(ctx);
144906Sgm89044
145906Sgm89044 return (rv);
146906Sgm89044 }
147906Sgm89044
148906Sgm89044 static void
dca_dsa_sign_done(dca_request_t * reqp,int errno)149906Sgm89044 dca_dsa_sign_done(dca_request_t *reqp, int errno)
150906Sgm89044 {
151906Sgm89044 if (errno == CRYPTO_SUCCESS) {
152906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN,
153906Sgm89044 DDI_DMA_SYNC_FORKERNEL);
154906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
155906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
156906Sgm89044 reqp->destroy = TRUE;
157906Sgm89044 errno = CRYPTO_DEVICE_ERROR;
158906Sgm89044 goto errout;
159906Sgm89044 }
160906Sgm89044 /*
161906Sgm89044 * Set the sig cd_length to zero so it's ready to take the
162906Sgm89044 * signature. Have already confirmed its size is adequate.
163906Sgm89044 */
164906Sgm89044 reqp->dr_out->cd_length = 0;
165906Sgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr,
166906Sgm89044 reqp->dr_out, DSAPARTLEN, 1);
167906Sgm89044 if (errno != CRYPTO_SUCCESS) {
168906Sgm89044 DBG(reqp->dr_dca, DWARN,
169906Sgm89044 "dca_dsa_sign_done: dca_scatter() failed");
170906Sgm89044 goto errout;
171906Sgm89044 }
172906Sgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN,
173906Sgm89044 reqp->dr_out, DSAPARTLEN, 1);
174906Sgm89044 if (errno != CRYPTO_SUCCESS) {
175906Sgm89044 DBG(reqp->dr_dca, DWARN,
176906Sgm89044 "dca_dsa_sign_done: dca_scatter() failed");
177906Sgm89044 }
178906Sgm89044 }
179906Sgm89044 errout:
180906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL);
181906Sgm89044
182906Sgm89044 /* notify framework that request is completed */
183906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
184906Sgm89044 DBG(reqp->dr_dca, DINTR,
185906Sgm89044 "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification",
186906Sgm89044 errno);
187906Sgm89044
188906Sgm89044 /*
189906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF
190906Sgm89044 * callback function since it may be needed again if
191906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
192906Sgm89044 */
193906Sgm89044 if (reqp->dr_ctx.atomic) {
194906Sgm89044 crypto_ctx_t ctx;
195906Sgm89044 ctx.cc_provider_private = reqp;
196906Sgm89044 dca_dsactxfree(&ctx);
197906Sgm89044 }
198906Sgm89044 }
199906Sgm89044
200906Sgm89044 int
dca_dsa_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * sig,crypto_req_handle_t req)201906Sgm89044 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig,
202906Sgm89044 crypto_req_handle_t req)
203906Sgm89044 {
204906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
205906Sgm89044 dca_t *dca = ctx->cc_provider;
206906Sgm89044 int err;
207906Sgm89044 int rv = CRYPTO_QUEUED;
208906Sgm89044 caddr_t kaddr;
209906Sgm89044
210906Sgm89044 /* Impossible for verify to be an in-place operation. */
211906Sgm89044 if (sig == NULL) {
212906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
213906Sgm89044 goto errout;
214906Sgm89044 }
215906Sgm89044
216906Sgm89044 if (dca_length(data) != SHA1LEN) {
217906Sgm89044 DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN);
218906Sgm89044 rv = CRYPTO_DATA_LEN_RANGE;
219906Sgm89044 goto errout;
220906Sgm89044 }
221906Sgm89044
222906Sgm89044 if (dca_length(sig) != DSASIGLEN) {
223906Sgm89044 DBG(dca, DWARN, "dca_dsa_verify: signature length != %d",
224906Sgm89044 DSASIGLEN);
225906Sgm89044 rv = CRYPTO_SIGNATURE_LEN_RANGE;
226906Sgm89044 goto errout;
227906Sgm89044 }
228906Sgm89044
229906Sgm89044 /* Don't change the data & sig values for verify. */
230906Sgm89044
231906Sgm89044 reqp->dr_job_stat = DS_DSAVERIFY;
232906Sgm89044 reqp->dr_byte_stat = -1;
233906Sgm89044
234906Sgm89044 /*
235906Sgm89044 * Grab h, r and s.
236906Sgm89044 */
237906Sgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1);
238906Sgm89044 if (err != CRYPTO_SUCCESS) {
239906Sgm89044 DBG(dca, DWARN,
240906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for h");
241906Sgm89044 rv = err;
242906Sgm89044 goto errout;
243906Sgm89044 }
244906Sgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1);
245906Sgm89044 if (err != CRYPTO_SUCCESS) {
246906Sgm89044 DBG(dca, DWARN,
247906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for r");
248906Sgm89044 rv = err;
249906Sgm89044 goto errout;
250906Sgm89044 }
251906Sgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN,
252906Sgm89044 DSAPARTLEN, 1);
253906Sgm89044 if (err != CRYPTO_SUCCESS) {
254906Sgm89044 DBG(dca, DWARN,
255906Sgm89044 "dca_dsa_vrfy: dca_gather() failed for s");
256906Sgm89044 rv = err;
257906Sgm89044 goto errout;
258906Sgm89044 }
259906Sgm89044 /*
260906Sgm89044 * As dca_gather() increments the cd_offset and decrements
261906Sgm89044 * the cd_length as it copies the data rewind the values ready for
262906Sgm89044 * the final compare.
263906Sgm89044 */
264906Sgm89044 sig->cd_offset -= (DSAPARTLEN * 2);
265906Sgm89044 sig->cd_length += (DSAPARTLEN * 2);
266906Sgm89044 /* sync the input buffer */
267906Sgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN,
268906Sgm89044 DDI_DMA_SYNC_FORDEV);
269906Sgm89044
270906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
271906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
272906Sgm89044 reqp->destroy = TRUE;
273906Sgm89044 rv = CRYPTO_DEVICE_ERROR;
274906Sgm89044 goto errout;
275906Sgm89044 }
276906Sgm89044
277906Sgm89044 reqp->dr_in = data;
278906Sgm89044 reqp->dr_out = sig;
279906Sgm89044 reqp->dr_kcf_req = req;
280906Sgm89044 reqp->dr_flags |= DR_SCATTER | DR_GATHER;
281906Sgm89044 reqp->dr_callback = dca_dsa_verify_done;
282906Sgm89044
283906Sgm89044 /*
284906Sgm89044 * Input requires three buffers. m, followed by r, followed by s.
285906Sgm89044 * In order to deal with things cleanly, we reverse the signature
286906Sgm89044 * into the buffer and then fix up the pointers.
287906Sgm89044 */
288906Sgm89044 reqp->dr_pkt_length = SHA1LEN;
289906Sgm89044
290906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr;
291906Sgm89044 reqp->dr_in_len = SHA1LEN;
292906Sgm89044 reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset;
293906Sgm89044
294906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr;
295906Sgm89044 reqp->dr_out_len = DSAPARTLEN;
296906Sgm89044 reqp->dr_out_next = 0;
297906Sgm89044
298906Sgm89044 /* setup 1st chain for r */
299906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset;
300906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN);
301906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT,
302906Sgm89044 reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE);
303906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
304906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
305906Sgm89044
306906Sgm89044 /* and 2nd chain for s */
307906Sgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE;
308906Sgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr +
309906Sgm89044 SHA1LEN + DSAPARTLEN);
310906Sgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0);
311906Sgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0);
312906Sgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN);
313906Sgm89044
314906Sgm89044 /* schedule the work by doing a submit */
315906Sgm89044 rv = dca_start(dca, reqp, MCR2, 1);
316906Sgm89044
317906Sgm89044 errout:
318906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
319906Sgm89044 (void) dca_free_context(ctx);
320906Sgm89044 }
321906Sgm89044 return (rv);
322906Sgm89044 }
323906Sgm89044
324906Sgm89044 static void
dca_dsa_verify_done(dca_request_t * reqp,int errno)325906Sgm89044 dca_dsa_verify_done(dca_request_t *reqp, int errno)
326906Sgm89044 {
327906Sgm89044 if (errno == CRYPTO_SUCCESS) {
328906Sgm89044 int count = DSAPARTLEN;
329906Sgm89044 crypto_data_t *sig = reqp->dr_out;
330906Sgm89044 caddr_t daddr;
331906Sgm89044
332906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count,
333906Sgm89044 DDI_DMA_SYNC_FORKERNEL);
334906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
335906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
336906Sgm89044 reqp->destroy = TRUE;
337906Sgm89044 errno = CRYPTO_DEVICE_ERROR;
338906Sgm89044 goto errout;
339906Sgm89044 }
340906Sgm89044
341906Sgm89044 /* Can only handle a contiguous data buffer currently. */
342906Sgm89044 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) {
343906Sgm89044 errno = CRYPTO_SIGNATURE_INVALID;
344906Sgm89044 goto errout;
345906Sgm89044 }
346906Sgm89044
347906Sgm89044 if ((daddr = dca_bufdaddr(sig)) == NULL) {
348906Sgm89044 errno = CRYPTO_ARGUMENTS_BAD;
349906Sgm89044 goto errout;
350906Sgm89044 }
351906Sgm89044
352906Sgm89044 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr,
353906Sgm89044 DSAPARTLEN) != 0) {
354906Sgm89044 /* VERIFY FAILED */
355906Sgm89044 errno = CRYPTO_SIGNATURE_INVALID;
356906Sgm89044 }
357906Sgm89044 }
358906Sgm89044 errout:
359906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL);
360906Sgm89044
361906Sgm89044 /* notify framework that request is completed */
362906Sgm89044
363906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
364906Sgm89044 DBG(reqp->dr_dca, DINTR,
365906Sgm89044 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification",
366906Sgm89044 errno);
367906Sgm89044
368906Sgm89044 /*
369906Sgm89044 * For non-atomic operations, reqp will be freed in the kCF
370906Sgm89044 * callback function since it may be needed again if
371906Sgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
372906Sgm89044 */
373906Sgm89044 if (reqp->dr_ctx.atomic) {
374906Sgm89044 crypto_ctx_t ctx;
375906Sgm89044 ctx.cc_provider_private = reqp;
376906Sgm89044 dca_dsactxfree(&ctx);
377906Sgm89044 }
378906Sgm89044 }
379906Sgm89044
380906Sgm89044 /* ARGSUSED */
381906Sgm89044 int
dca_dsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,int mode)382906Sgm89044 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
383906Sgm89044 crypto_key_t *key, int kmflag, int mode)
384906Sgm89044 {
385906Sgm89044 crypto_object_attribute_t *attr;
386906Sgm89044 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0;
387906Sgm89044 uchar_t *p, *q, *g, *x;
388906Sgm89044 dca_request_t *reqp = NULL;
389906Sgm89044 dca_t *dca = (dca_t *)ctx->cc_provider;
390906Sgm89044 int rv = CRYPTO_SUCCESS;
391906Sgm89044 unsigned pbits, padjlen;
392906Sgm89044 uint16_t ctxlen;
393906Sgm89044 caddr_t kaddr;
394906Sgm89044
395906Sgm89044 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
396906Sgm89044 dca_error(dca,
397906Sgm89044 "dca_dsainit: unable to allocate request for DSA");
398906Sgm89044 rv = CRYPTO_HOST_MEMORY;
399906Sgm89044 goto errout;
400906Sgm89044 }
401906Sgm89044
402906Sgm89044 ctx->cc_provider_private = reqp;
403906Sgm89044 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
404906Sgm89044
405906Sgm89044 if ((attr = dca_get_key_attr(key)) == NULL) {
406906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: key attributes missing");
407906Sgm89044 rv = CRYPTO_KEY_TYPE_INCONSISTENT;
408906Sgm89044 goto errout;
409906Sgm89044 }
410906Sgm89044
411906Sgm89044 /* Prime */
412906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME,
413906Sgm89044 (void *) &p, &plen)) {
414906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: prime key value not present");
415906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
416906Sgm89044 goto errout;
417906Sgm89044 }
418906Sgm89044
419906Sgm89044 /* Subprime */
420906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME,
421906Sgm89044 (void *) &q, &qlen)) {
422906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present");
423906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
424906Sgm89044 goto errout;
425906Sgm89044 }
426906Sgm89044
427906Sgm89044 /* Base */
428906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE,
429906Sgm89044 (void *) &g, &glen)) {
430906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: base key value not present");
431906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
432906Sgm89044 goto errout;
433906Sgm89044 }
434906Sgm89044
435906Sgm89044 /* Value */
436906Sgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE,
437906Sgm89044 (void *) &x, &xlen)) {
438906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: value key not present");
439906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
440906Sgm89044 goto errout;
441906Sgm89044 }
442906Sgm89044
443906Sgm89044 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) {
444906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD;
445906Sgm89044 goto errout;
446906Sgm89044 }
447906Sgm89044
448906Sgm89044 if (plen > DSA_MAX_KEY_LEN) {
449906Sgm89044 /* maximum 1Kbit key */
450906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen);
451906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE;
452906Sgm89044 goto errout;
453906Sgm89044 }
454906Sgm89044
455906Sgm89044 if (qlen > DSAPARTLEN) {
456906Sgm89044 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen);
457906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE;
458906Sgm89044 goto errout;
459906Sgm89044 }
460906Sgm89044
461906Sgm89044 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) {
462906Sgm89044 DBG(NULL, DWARN,
463906Sgm89044 "dca_dsainit: private key is too long (%d)", xlen);
464906Sgm89044 rv = CRYPTO_KEY_SIZE_RANGE;
465906Sgm89044 goto errout;
466906Sgm89044 }
467906Sgm89044
468906Sgm89044 /*
469906Sgm89044 * Setup the key partion of the request.
470906Sgm89044 */
471906Sgm89044
472906Sgm89044 pbits = dca_bitlen(p, plen);
473906Sgm89044 padjlen = dca_padfull(pbits);
474906Sgm89044
475906Sgm89044 /* accounts for leading context words */
476906Sgm89044 if (mode == DCA_DSA_SIGN) {
477906Sgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) +
478906Sgm89044 DSAPARTLEN;
479906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN);
480906Sgm89044 } else {
481906Sgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3);
482906Sgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY);
483906Sgm89044 }
484906Sgm89044
485906Sgm89044 PUTCTX16(reqp, CTX_LENGTH, ctxlen);
486906Sgm89044 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1);
487906Sgm89044 PUTCTX16(reqp, CTX_DSARSVD, 0);
488906Sgm89044 if (mode == DCA_DSA_SIGN)
489906Sgm89044 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN);
490906Sgm89044 else
491906Sgm89044 PUTCTX16(reqp, CTX_DSARNG, 0);
492906Sgm89044 PUTCTX16(reqp, CTX_DSAPLEN, pbits);
493906Sgm89044
494906Sgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS;
495906Sgm89044
496906Sgm89044 /* store the bignums */
497906Sgm89044 dca_reverse(q, kaddr, qlen, DSAPARTLEN);
498906Sgm89044 kaddr += DSAPARTLEN;
499906Sgm89044
500906Sgm89044 dca_reverse(p, kaddr, plen, padjlen);
501906Sgm89044 kaddr += padjlen;
502906Sgm89044
503906Sgm89044 dca_reverse(g, kaddr, glen, padjlen);
504906Sgm89044 kaddr += padjlen;
505906Sgm89044
506906Sgm89044 if (mode == DCA_DSA_SIGN) {
507906Sgm89044 dca_reverse(x, kaddr, xlen, DSAPARTLEN);
508906Sgm89044 kaddr += DSAPARTLEN;
509906Sgm89044 } else {
510906Sgm89044 dca_reverse(x, kaddr, xlen, padjlen);
511906Sgm89044 kaddr += padjlen;
512906Sgm89044 }
513906Sgm89044
514906Sgm89044 return (CRYPTO_SUCCESS);
515906Sgm89044
516906Sgm89044 errout:
517906Sgm89044
518906Sgm89044 dca_dsactxfree(ctx);
519906Sgm89044 return (rv);
520906Sgm89044 }
521906Sgm89044
522906Sgm89044 void
dca_dsactxfree(void * arg)523906Sgm89044 dca_dsactxfree(void *arg)
524906Sgm89044 {
525906Sgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg;
526906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
527906Sgm89044
528906Sgm89044 if (reqp == NULL)
529906Sgm89044 return;
530906Sgm89044
531906Sgm89044 reqp->dr_ctx.ctx_cm_type = 0;
532906Sgm89044 reqp->dr_ctx.atomic = 0;
533906Sgm89044 if (reqp->destroy)
534906Sgm89044 dca_destroyreq(reqp);
535906Sgm89044 else
536906Sgm89044 dca_freereq(reqp);
537906Sgm89044
538906Sgm89044 ctx->cc_provider_private = NULL;
539906Sgm89044 }
540906Sgm89044
541906Sgm89044 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)542906Sgm89044 dca_dsaatomic(crypto_provider_handle_t provider,
543906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
544906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig,
545906Sgm89044 int kmflag, crypto_req_handle_t req, int mode)
546906Sgm89044 {
547906Sgm89044 crypto_ctx_t ctx; /* on the stack */
548906Sgm89044 int rv;
549906Sgm89044
550906Sgm89044 ctx.cc_provider = provider;
551906Sgm89044 ctx.cc_session = session_id;
552906Sgm89044
553906Sgm89044 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode);
554906Sgm89044 if (rv != CRYPTO_SUCCESS) {
555906Sgm89044 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed");
556906Sgm89044 return (rv);
557906Sgm89044 }
558906Sgm89044
559906Sgm89044 /*
560906Sgm89044 * Set the atomic flag so that the hardware callback function
561906Sgm89044 * will free the context.
562906Sgm89044 */
563906Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
564906Sgm89044
565906Sgm89044 if (mode == DCA_DSA_SIGN) {
566906Sgm89044 rv = dca_dsa_sign(&ctx, data, sig, req);
567906Sgm89044 } else {
568906Sgm89044 ASSERT(mode == DCA_DSA_VRFY);
569906Sgm89044 rv = dca_dsa_verify(&ctx, data, sig, req);
570906Sgm89044 }
571906Sgm89044
572906Sgm89044 /*
573906Sgm89044 * The context will be freed in the hardware callback function if it
574906Sgm89044 * is queued
575906Sgm89044 */
576906Sgm89044 if (rv != CRYPTO_QUEUED)
577906Sgm89044 dca_dsactxfree(&ctx);
578906Sgm89044
579906Sgm89044 return (rv);
580906Sgm89044 }
581