188f8b78aSgm89044 /* 288f8b78aSgm89044 * CDDL HEADER START 388f8b78aSgm89044 * 488f8b78aSgm89044 * The contents of this file are subject to the terms of the 588f8b78aSgm89044 * Common Development and Distribution License (the "License"). 688f8b78aSgm89044 * You may not use this file except in compliance with the License. 788f8b78aSgm89044 * 888f8b78aSgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 988f8b78aSgm89044 * or http://www.opensolaris.org/os/licensing. 1088f8b78aSgm89044 * See the License for the specific language governing permissions 1188f8b78aSgm89044 * and limitations under the License. 1288f8b78aSgm89044 * 1388f8b78aSgm89044 * When distributing Covered Code, include this CDDL HEADER in each 1488f8b78aSgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1588f8b78aSgm89044 * If applicable, add the following below this CDDL HEADER, with the 1688f8b78aSgm89044 * fields enclosed by brackets "[]" replaced with your own identifying 1788f8b78aSgm89044 * information: Portions Copyright [yyyy] [name of copyright owner] 1888f8b78aSgm89044 * 1988f8b78aSgm89044 * CDDL HEADER END 2088f8b78aSgm89044 */ 2188f8b78aSgm89044 2288f8b78aSgm89044 /* 23*f317a3a3Skrishna * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2488f8b78aSgm89044 * Use is subject to license terms. 2588f8b78aSgm89044 */ 2688f8b78aSgm89044 2788f8b78aSgm89044 #pragma ident "%Z%%M% %I% %E% SMI" 2888f8b78aSgm89044 2988f8b78aSgm89044 /* 3088f8b78aSgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x. 3188f8b78aSgm89044 */ 3288f8b78aSgm89044 3388f8b78aSgm89044 #include <sys/types.h> 3488f8b78aSgm89044 #include <sys/ddi.h> 3588f8b78aSgm89044 #include <sys/sunddi.h> 3688f8b78aSgm89044 #include <sys/kmem.h> 3788f8b78aSgm89044 #include <sys/crypto/spi.h> 3888f8b78aSgm89044 #include <sys/crypto/dca.h> 3988f8b78aSgm89044 4088f8b78aSgm89044 /* 4188f8b78aSgm89044 * DSA implementation. 4288f8b78aSgm89044 */ 4388f8b78aSgm89044 4488f8b78aSgm89044 static void dca_dsa_sign_done(dca_request_t *, int); 4588f8b78aSgm89044 static void dca_dsa_verify_done(dca_request_t *, int); 4688f8b78aSgm89044 4788f8b78aSgm89044 4888f8b78aSgm89044 int dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 4988f8b78aSgm89044 crypto_req_handle_t req); 5088f8b78aSgm89044 int dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 5188f8b78aSgm89044 crypto_req_handle_t req); 5288f8b78aSgm89044 int dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 5388f8b78aSgm89044 crypto_key_t *key, int kmflag, int mode); 5488f8b78aSgm89044 5588f8b78aSgm89044 5688f8b78aSgm89044 int 5788f8b78aSgm89044 dca_dsa_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 5888f8b78aSgm89044 crypto_req_handle_t req) 5988f8b78aSgm89044 { 6088f8b78aSgm89044 dca_request_t *reqp = ctx->cc_provider_private; 6188f8b78aSgm89044 dca_t *dca = ctx->cc_provider; 6288f8b78aSgm89044 int err; 6388f8b78aSgm89044 int rv = CRYPTO_QUEUED; 6488f8b78aSgm89044 caddr_t kaddr; 6588f8b78aSgm89044 size_t buflen; 6688f8b78aSgm89044 6788f8b78aSgm89044 buflen = dca_length(data); 6888f8b78aSgm89044 if (buflen != SHA1LEN) { 6988f8b78aSgm89044 DBG(dca, DWARN, "dca_dsa_sign: data length != %d", SHA1LEN); 7088f8b78aSgm89044 rv = CRYPTO_DATA_LEN_RANGE; 7188f8b78aSgm89044 goto errout; 7288f8b78aSgm89044 } 7388f8b78aSgm89044 7488f8b78aSgm89044 /* Return length needed to store the output. */ 7588f8b78aSgm89044 if (dca_length(sig) < DSASIGLEN) { 7688f8b78aSgm89044 DBG(dca, DWARN, 7788f8b78aSgm89044 "dca_dsa_sign: output buffer too short (%d < %d)", 7888f8b78aSgm89044 dca_length(sig), DSASIGLEN); 7988f8b78aSgm89044 sig->cd_length = DSASIGLEN; 8088f8b78aSgm89044 rv = CRYPTO_BUFFER_TOO_SMALL; 8188f8b78aSgm89044 goto errout; 8288f8b78aSgm89044 } 8388f8b78aSgm89044 8488f8b78aSgm89044 /* 8588f8b78aSgm89044 * Don't change the data values of the data crypto_data_t structure 8688f8b78aSgm89044 * yet. Only reset the sig cd_length to zero before writing to it. 8788f8b78aSgm89044 */ 8888f8b78aSgm89044 8988f8b78aSgm89044 reqp->dr_job_stat = DS_DSASIGN; 9088f8b78aSgm89044 reqp->dr_byte_stat = -1; 9188f8b78aSgm89044 reqp->dr_in = data; 9288f8b78aSgm89044 reqp->dr_out = sig; 9388f8b78aSgm89044 reqp->dr_callback = dca_dsa_sign_done; 9488f8b78aSgm89044 9588f8b78aSgm89044 reqp->dr_kcf_req = req; 9688f8b78aSgm89044 /* dca_gather() increments cd_offset & dec. cd_length by SHA1LEN. */ 9788f8b78aSgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 9888f8b78aSgm89044 if (err != CRYPTO_SUCCESS) { 9988f8b78aSgm89044 DBG(dca, DWARN, "dca_dsa_sign: dca_gather() failed"); 10088f8b78aSgm89044 rv = err; 10188f8b78aSgm89044 goto errout; 10288f8b78aSgm89044 } 10388f8b78aSgm89044 10488f8b78aSgm89044 10588f8b78aSgm89044 /* sync the input buffer */ 10688f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN, 10788f8b78aSgm89044 DDI_DMA_SYNC_FORDEV); 10888f8b78aSgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 10988f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 11088f8b78aSgm89044 reqp->destroy = TRUE; 11188f8b78aSgm89044 rv = CRYPTO_DEVICE_ERROR; 11288f8b78aSgm89044 goto errout; 11388f8b78aSgm89044 } 11488f8b78aSgm89044 11588f8b78aSgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 11688f8b78aSgm89044 reqp->dr_in_next = 0; 11788f8b78aSgm89044 reqp->dr_in_len = SHA1LEN; 11888f8b78aSgm89044 reqp->dr_pkt_length = buflen; 11988f8b78aSgm89044 12088f8b78aSgm89044 /* 12188f8b78aSgm89044 * The output requires *two* buffers, r followed by s. 12288f8b78aSgm89044 */ 12388f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 12488f8b78aSgm89044 12588f8b78aSgm89044 /* r */ 12688f8b78aSgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 12788f8b78aSgm89044 reqp->dr_out_len = DSAPARTLEN; 12888f8b78aSgm89044 reqp->dr_out_next = reqp->dr_ctx_paddr + reqp->dr_offset; 12988f8b78aSgm89044 13088f8b78aSgm89044 /* s */ 13188f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, 13288f8b78aSgm89044 reqp->dr_obuf_paddr + DSAPARTLEN); 13388f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 13488f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 13588f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 13688f8b78aSgm89044 13788f8b78aSgm89044 /* schedule the work by doing a submit */ 13888f8b78aSgm89044 rv = dca_start(dca, reqp, MCR2, 1); 13988f8b78aSgm89044 14088f8b78aSgm89044 errout: 14188f8b78aSgm89044 14288f8b78aSgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) 14388f8b78aSgm89044 (void) dca_free_context(ctx); 14488f8b78aSgm89044 14588f8b78aSgm89044 return (rv); 14688f8b78aSgm89044 } 14788f8b78aSgm89044 14888f8b78aSgm89044 static void 14988f8b78aSgm89044 dca_dsa_sign_done(dca_request_t *reqp, int errno) 15088f8b78aSgm89044 { 15188f8b78aSgm89044 if (errno == CRYPTO_SUCCESS) { 15288f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, DSASIGLEN, 15388f8b78aSgm89044 DDI_DMA_SYNC_FORKERNEL); 15488f8b78aSgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 15588f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 15688f8b78aSgm89044 reqp->destroy = TRUE; 15788f8b78aSgm89044 errno = CRYPTO_DEVICE_ERROR; 15888f8b78aSgm89044 goto errout; 15988f8b78aSgm89044 } 16088f8b78aSgm89044 /* 16188f8b78aSgm89044 * Set the sig cd_length to zero so it's ready to take the 16288f8b78aSgm89044 * signature. Have already confirmed its size is adequate. 16388f8b78aSgm89044 */ 16488f8b78aSgm89044 reqp->dr_out->cd_length = 0; 16588f8b78aSgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr, 16688f8b78aSgm89044 reqp->dr_out, DSAPARTLEN, 1); 16788f8b78aSgm89044 if (errno != CRYPTO_SUCCESS) { 16888f8b78aSgm89044 DBG(reqp->dr_dca, DWARN, 16988f8b78aSgm89044 "dca_dsa_sign_done: dca_scatter() failed"); 17088f8b78aSgm89044 goto errout; 17188f8b78aSgm89044 } 17288f8b78aSgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr+DSAPARTLEN, 17388f8b78aSgm89044 reqp->dr_out, DSAPARTLEN, 1); 17488f8b78aSgm89044 if (errno != CRYPTO_SUCCESS) { 17588f8b78aSgm89044 DBG(reqp->dr_dca, DWARN, 17688f8b78aSgm89044 "dca_dsa_sign_done: dca_scatter() failed"); 17788f8b78aSgm89044 } 17888f8b78aSgm89044 } 17988f8b78aSgm89044 errout: 18088f8b78aSgm89044 ASSERT(reqp->dr_kcf_req != NULL); 18188f8b78aSgm89044 18288f8b78aSgm89044 /* notify framework that request is completed */ 18388f8b78aSgm89044 crypto_op_notification(reqp->dr_kcf_req, errno); 18488f8b78aSgm89044 DBG(reqp->dr_dca, DINTR, 18588f8b78aSgm89044 "dca_dsa_sign_done: rtn 0x%x to kef via crypto_op_notification", 18688f8b78aSgm89044 errno); 18788f8b78aSgm89044 18888f8b78aSgm89044 /* 18988f8b78aSgm89044 * For non-atomic operations, reqp will be freed in the kCF 19088f8b78aSgm89044 * callback function since it may be needed again if 19188f8b78aSgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 19288f8b78aSgm89044 */ 19388f8b78aSgm89044 if (reqp->dr_ctx.atomic) { 19488f8b78aSgm89044 crypto_ctx_t ctx; 19588f8b78aSgm89044 ctx.cc_provider_private = reqp; 19688f8b78aSgm89044 dca_dsactxfree(&ctx); 19788f8b78aSgm89044 } 19888f8b78aSgm89044 } 19988f8b78aSgm89044 20088f8b78aSgm89044 int 20188f8b78aSgm89044 dca_dsa_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *sig, 20288f8b78aSgm89044 crypto_req_handle_t req) 20388f8b78aSgm89044 { 20488f8b78aSgm89044 dca_request_t *reqp = ctx->cc_provider_private; 20588f8b78aSgm89044 dca_t *dca = ctx->cc_provider; 20688f8b78aSgm89044 int err; 20788f8b78aSgm89044 int rv = CRYPTO_QUEUED; 20888f8b78aSgm89044 caddr_t kaddr; 20988f8b78aSgm89044 21088f8b78aSgm89044 /* Impossible for verify to be an in-place operation. */ 21188f8b78aSgm89044 if (sig == NULL) { 21288f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 21388f8b78aSgm89044 goto errout; 21488f8b78aSgm89044 } 21588f8b78aSgm89044 21688f8b78aSgm89044 if (dca_length(data) != SHA1LEN) { 21788f8b78aSgm89044 DBG(dca, DWARN, "dca_dsa_verify: input length != %d", SHA1LEN); 21888f8b78aSgm89044 rv = CRYPTO_DATA_LEN_RANGE; 21988f8b78aSgm89044 goto errout; 22088f8b78aSgm89044 } 22188f8b78aSgm89044 22288f8b78aSgm89044 if (dca_length(sig) != DSASIGLEN) { 22388f8b78aSgm89044 DBG(dca, DWARN, "dca_dsa_verify: signature length != %d", 22488f8b78aSgm89044 DSASIGLEN); 22588f8b78aSgm89044 rv = CRYPTO_SIGNATURE_LEN_RANGE; 22688f8b78aSgm89044 goto errout; 22788f8b78aSgm89044 } 22888f8b78aSgm89044 22988f8b78aSgm89044 /* Don't change the data & sig values for verify. */ 23088f8b78aSgm89044 23188f8b78aSgm89044 reqp->dr_job_stat = DS_DSAVERIFY; 23288f8b78aSgm89044 reqp->dr_byte_stat = -1; 23388f8b78aSgm89044 23488f8b78aSgm89044 /* 23588f8b78aSgm89044 * Grab h, r and s. 23688f8b78aSgm89044 */ 23788f8b78aSgm89044 err = dca_gather(data, reqp->dr_ibuf_kaddr, SHA1LEN, 1); 23888f8b78aSgm89044 if (err != CRYPTO_SUCCESS) { 23988f8b78aSgm89044 DBG(dca, DWARN, 24088f8b78aSgm89044 "dca_dsa_vrfy: dca_gather() failed for h"); 24188f8b78aSgm89044 rv = err; 24288f8b78aSgm89044 goto errout; 24388f8b78aSgm89044 } 24488f8b78aSgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN, DSAPARTLEN, 1); 24588f8b78aSgm89044 if (err != CRYPTO_SUCCESS) { 24688f8b78aSgm89044 DBG(dca, DWARN, 24788f8b78aSgm89044 "dca_dsa_vrfy: dca_gather() failed for r"); 24888f8b78aSgm89044 rv = err; 24988f8b78aSgm89044 goto errout; 25088f8b78aSgm89044 } 25188f8b78aSgm89044 err = dca_gather(sig, reqp->dr_ibuf_kaddr+SHA1LEN+DSAPARTLEN, 25288f8b78aSgm89044 DSAPARTLEN, 1); 25388f8b78aSgm89044 if (err != CRYPTO_SUCCESS) { 25488f8b78aSgm89044 DBG(dca, DWARN, 25588f8b78aSgm89044 "dca_dsa_vrfy: dca_gather() failed for s"); 25688f8b78aSgm89044 rv = err; 25788f8b78aSgm89044 goto errout; 25888f8b78aSgm89044 } 25988f8b78aSgm89044 /* 26088f8b78aSgm89044 * As dca_gather() increments the cd_offset and decrements 26188f8b78aSgm89044 * the cd_length as it copies the data rewind the values ready for 26288f8b78aSgm89044 * the final compare. 26388f8b78aSgm89044 */ 26488f8b78aSgm89044 sig->cd_offset -= (DSAPARTLEN * 2); 26588f8b78aSgm89044 sig->cd_length += (DSAPARTLEN * 2); 26688f8b78aSgm89044 /* sync the input buffer */ 26788f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, SHA1LEN + DSAPARTLEN, 26888f8b78aSgm89044 DDI_DMA_SYNC_FORDEV); 26988f8b78aSgm89044 27088f8b78aSgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 27188f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 27288f8b78aSgm89044 reqp->destroy = TRUE; 27388f8b78aSgm89044 rv = CRYPTO_DEVICE_ERROR; 27488f8b78aSgm89044 goto errout; 27588f8b78aSgm89044 } 27688f8b78aSgm89044 27788f8b78aSgm89044 reqp->dr_in = data; 27888f8b78aSgm89044 reqp->dr_out = sig; 27988f8b78aSgm89044 reqp->dr_kcf_req = req; 28088f8b78aSgm89044 reqp->dr_flags |= DR_SCATTER | DR_GATHER; 28188f8b78aSgm89044 reqp->dr_callback = dca_dsa_verify_done; 28288f8b78aSgm89044 28388f8b78aSgm89044 /* 28488f8b78aSgm89044 * Input requires three buffers. m, followed by r, followed by s. 28588f8b78aSgm89044 * In order to deal with things cleanly, we reverse the signature 28688f8b78aSgm89044 * into the buffer and then fix up the pointers. 28788f8b78aSgm89044 */ 28888f8b78aSgm89044 reqp->dr_pkt_length = SHA1LEN; 28988f8b78aSgm89044 29088f8b78aSgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_paddr; 29188f8b78aSgm89044 reqp->dr_in_len = SHA1LEN; 29288f8b78aSgm89044 reqp->dr_in_next = reqp->dr_ctx_paddr + reqp->dr_offset; 29388f8b78aSgm89044 29488f8b78aSgm89044 reqp->dr_out_paddr = reqp->dr_obuf_paddr; 29588f8b78aSgm89044 reqp->dr_out_len = DSAPARTLEN; 29688f8b78aSgm89044 reqp->dr_out_next = 0; 29788f8b78aSgm89044 29888f8b78aSgm89044 /* setup 1st chain for r */ 29988f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset; 30088f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + SHA1LEN); 30188f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 30288f8b78aSgm89044 reqp->dr_ctx_paddr + reqp->dr_offset + DESC_SIZE); 30388f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 30488f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 30588f8b78aSgm89044 30688f8b78aSgm89044 /* and 2nd chain for s */ 30788f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + reqp->dr_offset + DESC_SIZE; 30888f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_BUFADDR, reqp->dr_ibuf_paddr + 30988f8b78aSgm89044 SHA1LEN + DSAPARTLEN); 31088f8b78aSgm89044 PUTDESC32(reqp, kaddr, DESC_NEXT, 0); 31188f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_RSVD, 0); 31288f8b78aSgm89044 PUTDESC16(reqp, kaddr, DESC_LENGTH, DSAPARTLEN); 31388f8b78aSgm89044 31488f8b78aSgm89044 /* schedule the work by doing a submit */ 31588f8b78aSgm89044 rv = dca_start(dca, reqp, MCR2, 1); 31688f8b78aSgm89044 31788f8b78aSgm89044 errout: 31888f8b78aSgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 31988f8b78aSgm89044 (void) dca_free_context(ctx); 32088f8b78aSgm89044 } 32188f8b78aSgm89044 return (rv); 32288f8b78aSgm89044 } 32388f8b78aSgm89044 32488f8b78aSgm89044 static void 32588f8b78aSgm89044 dca_dsa_verify_done(dca_request_t *reqp, int errno) 32688f8b78aSgm89044 { 32788f8b78aSgm89044 if (errno == CRYPTO_SUCCESS) { 32888f8b78aSgm89044 int count = DSAPARTLEN; 32988f8b78aSgm89044 crypto_data_t *sig = reqp->dr_out; 33088f8b78aSgm89044 caddr_t daddr; 33188f8b78aSgm89044 33288f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, count, 33388f8b78aSgm89044 DDI_DMA_SYNC_FORKERNEL); 33488f8b78aSgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah, 33588f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 33688f8b78aSgm89044 reqp->destroy = TRUE; 33788f8b78aSgm89044 errno = CRYPTO_DEVICE_ERROR; 33888f8b78aSgm89044 goto errout; 33988f8b78aSgm89044 } 34088f8b78aSgm89044 34188f8b78aSgm89044 /* Can only handle a contiguous data buffer currently. */ 34288f8b78aSgm89044 if (dca_sgcheck(reqp->dr_dca, sig, DCA_SG_CONTIG)) { 34388f8b78aSgm89044 errno = CRYPTO_SIGNATURE_INVALID; 34488f8b78aSgm89044 goto errout; 34588f8b78aSgm89044 } 34688f8b78aSgm89044 34788f8b78aSgm89044 if ((daddr = dca_bufdaddr(sig)) == NULL) { 34888f8b78aSgm89044 errno = CRYPTO_ARGUMENTS_BAD; 34988f8b78aSgm89044 goto errout; 35088f8b78aSgm89044 } 35188f8b78aSgm89044 35288f8b78aSgm89044 if (dca_bcmp_reverse(daddr, reqp->dr_obuf_kaddr, 35388f8b78aSgm89044 DSAPARTLEN) != 0) { 35488f8b78aSgm89044 /* VERIFY FAILED */ 35588f8b78aSgm89044 errno = CRYPTO_SIGNATURE_INVALID; 35688f8b78aSgm89044 } 35788f8b78aSgm89044 } 35888f8b78aSgm89044 errout: 35988f8b78aSgm89044 ASSERT(reqp->dr_kcf_req != NULL); 36088f8b78aSgm89044 36188f8b78aSgm89044 /* notify framework that request is completed */ 36288f8b78aSgm89044 36388f8b78aSgm89044 crypto_op_notification(reqp->dr_kcf_req, errno); 36488f8b78aSgm89044 DBG(reqp->dr_dca, DINTR, 36588f8b78aSgm89044 "dca_dsa_verify_done: rtn 0x%x to kef via crypto_op_notification", 36688f8b78aSgm89044 errno); 36788f8b78aSgm89044 36888f8b78aSgm89044 /* 36988f8b78aSgm89044 * For non-atomic operations, reqp will be freed in the kCF 37088f8b78aSgm89044 * callback function since it may be needed again if 37188f8b78aSgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF 37288f8b78aSgm89044 */ 37388f8b78aSgm89044 if (reqp->dr_ctx.atomic) { 37488f8b78aSgm89044 crypto_ctx_t ctx; 37588f8b78aSgm89044 ctx.cc_provider_private = reqp; 37688f8b78aSgm89044 dca_dsactxfree(&ctx); 37788f8b78aSgm89044 } 37888f8b78aSgm89044 } 37988f8b78aSgm89044 38088f8b78aSgm89044 /* ARGSUSED */ 38188f8b78aSgm89044 int 38288f8b78aSgm89044 dca_dsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 38388f8b78aSgm89044 crypto_key_t *key, int kmflag, int mode) 38488f8b78aSgm89044 { 38588f8b78aSgm89044 crypto_object_attribute_t *attr; 38688f8b78aSgm89044 unsigned plen = 0, qlen = 0, glen = 0, xlen = 0; 38788f8b78aSgm89044 uchar_t *p, *q, *g, *x; 38888f8b78aSgm89044 dca_request_t *reqp = NULL; 38988f8b78aSgm89044 dca_t *dca = (dca_t *)ctx->cc_provider; 39088f8b78aSgm89044 int rv = CRYPTO_SUCCESS; 39188f8b78aSgm89044 unsigned pbits, padjlen; 39288f8b78aSgm89044 uint16_t ctxlen; 39388f8b78aSgm89044 caddr_t kaddr; 39488f8b78aSgm89044 39588f8b78aSgm89044 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) { 39688f8b78aSgm89044 dca_error(dca, 39788f8b78aSgm89044 "dca_dsainit: unable to allocate request for DSA"); 39888f8b78aSgm89044 rv = CRYPTO_HOST_MEMORY; 39988f8b78aSgm89044 goto errout; 40088f8b78aSgm89044 } 40188f8b78aSgm89044 40288f8b78aSgm89044 ctx->cc_provider_private = reqp; 40388f8b78aSgm89044 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type; 40488f8b78aSgm89044 40588f8b78aSgm89044 if ((attr = dca_get_key_attr(key)) == NULL) { 40688f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: key attributes missing"); 40788f8b78aSgm89044 rv = CRYPTO_KEY_TYPE_INCONSISTENT; 40888f8b78aSgm89044 goto errout; 40988f8b78aSgm89044 } 41088f8b78aSgm89044 41188f8b78aSgm89044 /* Prime */ 41288f8b78aSgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_PRIME, 41388f8b78aSgm89044 (void *) &p, &plen)) { 41488f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: prime key value not present"); 41588f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 41688f8b78aSgm89044 goto errout; 41788f8b78aSgm89044 } 41888f8b78aSgm89044 41988f8b78aSgm89044 /* Subprime */ 42088f8b78aSgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_SUBPRIME, 42188f8b78aSgm89044 (void *) &q, &qlen)) { 42288f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: subprime key value not present"); 42388f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 42488f8b78aSgm89044 goto errout; 42588f8b78aSgm89044 } 42688f8b78aSgm89044 42788f8b78aSgm89044 /* Base */ 42888f8b78aSgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_BASE, 42988f8b78aSgm89044 (void *) &g, &glen)) { 43088f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: base key value not present"); 43188f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 43288f8b78aSgm89044 goto errout; 43388f8b78aSgm89044 } 43488f8b78aSgm89044 43588f8b78aSgm89044 /* Value */ 43688f8b78aSgm89044 if (dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_VALUE, 43788f8b78aSgm89044 (void *) &x, &xlen)) { 43888f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: value key not present"); 43988f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 44088f8b78aSgm89044 goto errout; 44188f8b78aSgm89044 } 44288f8b78aSgm89044 44388f8b78aSgm89044 if (plen == 0 || qlen == 0 || glen == 0 || xlen == 0) { 44488f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD; 44588f8b78aSgm89044 goto errout; 44688f8b78aSgm89044 } 44788f8b78aSgm89044 44888f8b78aSgm89044 if (plen > DSA_MAX_KEY_LEN) { 44988f8b78aSgm89044 /* maximum 1Kbit key */ 45088f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: maximum 1Kbit key (%d)", plen); 45188f8b78aSgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 45288f8b78aSgm89044 goto errout; 45388f8b78aSgm89044 } 45488f8b78aSgm89044 45588f8b78aSgm89044 if (qlen > DSAPARTLEN) { 45688f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsainit: q is too long (%d)", qlen); 45788f8b78aSgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 45888f8b78aSgm89044 goto errout; 45988f8b78aSgm89044 } 46088f8b78aSgm89044 46188f8b78aSgm89044 if (mode == DCA_DSA_SIGN && xlen > DSAPARTLEN) { 46288f8b78aSgm89044 DBG(NULL, DWARN, 46388f8b78aSgm89044 "dca_dsainit: private key is too long (%d)", xlen); 46488f8b78aSgm89044 rv = CRYPTO_KEY_SIZE_RANGE; 46588f8b78aSgm89044 goto errout; 46688f8b78aSgm89044 } 46788f8b78aSgm89044 46888f8b78aSgm89044 /* 46988f8b78aSgm89044 * Setup the key partion of the request. 47088f8b78aSgm89044 */ 47188f8b78aSgm89044 47288f8b78aSgm89044 pbits = dca_bitlen(p, plen); 47388f8b78aSgm89044 padjlen = dca_padfull(pbits); 47488f8b78aSgm89044 47588f8b78aSgm89044 /* accounts for leading context words */ 47688f8b78aSgm89044 if (mode == DCA_DSA_SIGN) { 47788f8b78aSgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 2) + 47888f8b78aSgm89044 DSAPARTLEN; 47988f8b78aSgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSASIGN); 48088f8b78aSgm89044 } else { 48188f8b78aSgm89044 ctxlen = CTX_DSABIGNUMS + DSAPARTLEN + (padjlen * 3); 48288f8b78aSgm89044 PUTCTX16(reqp, CTX_CMD, CMD_DSAVERIFY); 48388f8b78aSgm89044 } 48488f8b78aSgm89044 48588f8b78aSgm89044 PUTCTX16(reqp, CTX_LENGTH, ctxlen); 48688f8b78aSgm89044 PUTCTX16(reqp, CTX_DSAMSGTYPE, CTX_DSAMSGTYPE_SHA1); 48788f8b78aSgm89044 PUTCTX16(reqp, CTX_DSARSVD, 0); 48888f8b78aSgm89044 if (mode == DCA_DSA_SIGN) 48988f8b78aSgm89044 PUTCTX16(reqp, CTX_DSARNG, CTX_DSARNG_GEN); 49088f8b78aSgm89044 else 49188f8b78aSgm89044 PUTCTX16(reqp, CTX_DSARNG, 0); 49288f8b78aSgm89044 PUTCTX16(reqp, CTX_DSAPLEN, pbits); 49388f8b78aSgm89044 49488f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_DSABIGNUMS; 49588f8b78aSgm89044 49688f8b78aSgm89044 /* store the bignums */ 49788f8b78aSgm89044 dca_reverse(q, kaddr, qlen, DSAPARTLEN); 49888f8b78aSgm89044 kaddr += DSAPARTLEN; 49988f8b78aSgm89044 50088f8b78aSgm89044 dca_reverse(p, kaddr, plen, padjlen); 50188f8b78aSgm89044 kaddr += padjlen; 50288f8b78aSgm89044 50388f8b78aSgm89044 dca_reverse(g, kaddr, glen, padjlen); 50488f8b78aSgm89044 kaddr += padjlen; 50588f8b78aSgm89044 50688f8b78aSgm89044 if (mode == DCA_DSA_SIGN) { 50788f8b78aSgm89044 dca_reverse(x, kaddr, xlen, DSAPARTLEN); 50888f8b78aSgm89044 kaddr += DSAPARTLEN; 50988f8b78aSgm89044 } else { 51088f8b78aSgm89044 dca_reverse(x, kaddr, xlen, padjlen); 51188f8b78aSgm89044 kaddr += padjlen; 51288f8b78aSgm89044 } 51388f8b78aSgm89044 51488f8b78aSgm89044 return (CRYPTO_SUCCESS); 51588f8b78aSgm89044 51688f8b78aSgm89044 errout: 51788f8b78aSgm89044 51888f8b78aSgm89044 dca_dsactxfree(ctx); 51988f8b78aSgm89044 return (rv); 52088f8b78aSgm89044 } 52188f8b78aSgm89044 52288f8b78aSgm89044 void 52388f8b78aSgm89044 dca_dsactxfree(void *arg) 52488f8b78aSgm89044 { 52588f8b78aSgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg; 52688f8b78aSgm89044 dca_request_t *reqp = ctx->cc_provider_private; 52788f8b78aSgm89044 52888f8b78aSgm89044 if (reqp == NULL) 52988f8b78aSgm89044 return; 53088f8b78aSgm89044 53188f8b78aSgm89044 reqp->dr_ctx.ctx_cm_type = 0; 53288f8b78aSgm89044 reqp->dr_ctx.atomic = 0; 53388f8b78aSgm89044 if (reqp->destroy) 53488f8b78aSgm89044 dca_destroyreq(reqp); 53588f8b78aSgm89044 else 53688f8b78aSgm89044 dca_freereq(reqp); 53788f8b78aSgm89044 53888f8b78aSgm89044 ctx->cc_provider_private = NULL; 53988f8b78aSgm89044 } 54088f8b78aSgm89044 54188f8b78aSgm89044 int 54288f8b78aSgm89044 dca_dsaatomic(crypto_provider_handle_t provider, 54388f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 54488f8b78aSgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *sig, 54588f8b78aSgm89044 int kmflag, crypto_req_handle_t req, int mode) 54688f8b78aSgm89044 { 54788f8b78aSgm89044 crypto_ctx_t ctx; /* on the stack */ 54888f8b78aSgm89044 int rv; 54988f8b78aSgm89044 55088f8b78aSgm89044 ctx.cc_provider = provider; 55188f8b78aSgm89044 ctx.cc_session = session_id; 55288f8b78aSgm89044 55388f8b78aSgm89044 rv = dca_dsainit(&ctx, mechanism, key, kmflag, mode); 55488f8b78aSgm89044 if (rv != CRYPTO_SUCCESS) { 55588f8b78aSgm89044 DBG(NULL, DWARN, "dca_dsaatomic: dca_dsainit() failed"); 55688f8b78aSgm89044 return (rv); 55788f8b78aSgm89044 } 55888f8b78aSgm89044 55988f8b78aSgm89044 /* 56088f8b78aSgm89044 * Set the atomic flag so that the hardware callback function 56188f8b78aSgm89044 * will free the context. 56288f8b78aSgm89044 */ 56388f8b78aSgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1; 56488f8b78aSgm89044 56588f8b78aSgm89044 if (mode == DCA_DSA_SIGN) { 56688f8b78aSgm89044 rv = dca_dsa_sign(&ctx, data, sig, req); 56788f8b78aSgm89044 } else { 56888f8b78aSgm89044 ASSERT(mode == DCA_DSA_VRFY); 56988f8b78aSgm89044 rv = dca_dsa_verify(&ctx, data, sig, req); 57088f8b78aSgm89044 } 57188f8b78aSgm89044 57288f8b78aSgm89044 /* 57388f8b78aSgm89044 * The context will be freed in the hardware callback function if it 57488f8b78aSgm89044 * is queued 57588f8b78aSgm89044 */ 57688f8b78aSgm89044 if (rv != CRYPTO_QUEUED) 57788f8b78aSgm89044 dca_dsactxfree(&ctx); 57888f8b78aSgm89044 57988f8b78aSgm89044 return (rv); 58088f8b78aSgm89044 } 581