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*d8dd9913Sgm89044 * Copyright 2007 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/note.h>
3888f8b78aSgm89044 #include <sys/crypto/spi.h>
3988f8b78aSgm89044 #include <sys/crypto/dca.h>
4088f8b78aSgm89044
4188f8b78aSgm89044
4288f8b78aSgm89044 static void dca_rsaverifydone(dca_request_t *, int);
4388f8b78aSgm89044 static void dca_rsadone(dca_request_t *, int);
4488f8b78aSgm89044
4588f8b78aSgm89044 /* Exported function prototypes */
4688f8b78aSgm89044 int dca_rsastart(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
4788f8b78aSgm89044 crypto_req_handle_t, int);
4888f8b78aSgm89044 int dca_rsainit(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, int);
4988f8b78aSgm89044 void dca_rsactxfree(void *);
5088f8b78aSgm89044 int dca_rsaatomic(crypto_provider_handle_t, crypto_session_id_t,
5188f8b78aSgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
5288f8b78aSgm89044 int, crypto_req_handle_t, int);
5388f8b78aSgm89044
5488f8b78aSgm89044 /* Local function prototypes */
5588f8b78aSgm89044 static int dca_pkcs1_padding(dca_t *dca, caddr_t buf, int flen, int tlen,
5688f8b78aSgm89044 int private);
5788f8b78aSgm89044 static int dca_pkcs1_unpadding(char *buf, int *tlen, int flen, int mode);
5888f8b78aSgm89044 static int dca_x509_padding(caddr_t buf, int flen, int tlen);
5988f8b78aSgm89044 static int dca_x509_unpadding(char *buf, int tlen, int flen, int mode);
6088f8b78aSgm89044 static int decrypt_error_code(int mode, int decrypt, int verify, int def);
6188f8b78aSgm89044
6288f8b78aSgm89044
dca_rsastart(crypto_ctx_t * ctx,crypto_data_t * in,crypto_data_t * out,crypto_req_handle_t req,int mode)6388f8b78aSgm89044 int dca_rsastart(crypto_ctx_t *ctx, crypto_data_t *in, crypto_data_t *out,
6488f8b78aSgm89044 crypto_req_handle_t req, int mode)
6588f8b78aSgm89044 {
6688f8b78aSgm89044 dca_request_t *reqp = ctx->cc_provider_private;
6788f8b78aSgm89044 dca_t *dca = ctx->cc_provider;
6888f8b78aSgm89044 caddr_t daddr;
6988f8b78aSgm89044 int rv = CRYPTO_QUEUED;
7088f8b78aSgm89044 int len;
7188f8b78aSgm89044
7288f8b78aSgm89044 /* We don't support non-contiguous buffers for RSA */
7388f8b78aSgm89044 if (dca_sgcheck(dca, in, DCA_SG_CONTIG) ||
7488f8b78aSgm89044 dca_sgcheck(dca, out, DCA_SG_CONTIG)) {
7588f8b78aSgm89044 rv = CRYPTO_NOT_SUPPORTED;
7688f8b78aSgm89044 goto errout;
7788f8b78aSgm89044 }
7888f8b78aSgm89044
7988f8b78aSgm89044 len = dca_length(in);
8088f8b78aSgm89044
8188f8b78aSgm89044 /* Extracting the key attributes is now done in dca_rsainit(). */
8288f8b78aSgm89044 if (mode == DCA_RSA_ENC || mode == DCA_RSA_SIGN ||
8388f8b78aSgm89044 mode == DCA_RSA_SIGNR) {
8488f8b78aSgm89044 /*
8588f8b78aSgm89044 * Return length needed to store the output.
8688f8b78aSgm89044 * For sign, sign-recover, and encrypt, the output buffer
8788f8b78aSgm89044 * should not be smaller than modlen since PKCS or X_509
8888f8b78aSgm89044 * padding will be applied
8988f8b78aSgm89044 */
9088f8b78aSgm89044 if (dca_length(out) < reqp->dr_ctx.modlen) {
9188f8b78aSgm89044 DBG(dca, DWARN,
9288f8b78aSgm89044 "dca_rsastart: output buffer too short (%d < %d)",
9388f8b78aSgm89044 dca_length(out), reqp->dr_ctx.modlen);
9488f8b78aSgm89044 out->cd_length = reqp->dr_ctx.modlen;
9588f8b78aSgm89044 rv = CRYPTO_BUFFER_TOO_SMALL;
9688f8b78aSgm89044 goto errout;
9788f8b78aSgm89044 }
9888f8b78aSgm89044 }
9988f8b78aSgm89044 if (out != in && out->cd_length > reqp->dr_ctx.modlen)
10088f8b78aSgm89044 out->cd_length = reqp->dr_ctx.modlen;
10188f8b78aSgm89044
10288f8b78aSgm89044 /* The input length should not be bigger than the modulus */
10388f8b78aSgm89044 if (len > reqp->dr_ctx.modlen) {
10488f8b78aSgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
10588f8b78aSgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
10688f8b78aSgm89044 goto errout;
10788f8b78aSgm89044 }
10888f8b78aSgm89044
10988f8b78aSgm89044 /*
11088f8b78aSgm89044 * For decryption, verify, and verifyRecover, the input length should
11188f8b78aSgm89044 * not be less than the modulus
11288f8b78aSgm89044 */
11388f8b78aSgm89044 if (len < reqp->dr_ctx.modlen && (mode == DCA_RSA_DEC ||
11488f8b78aSgm89044 mode == DCA_RSA_VRFY || mode == DCA_RSA_VRFYR)) {
11588f8b78aSgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
11688f8b78aSgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
11788f8b78aSgm89044 goto errout;
11888f8b78aSgm89044 }
11988f8b78aSgm89044
12088f8b78aSgm89044 /*
12188f8b78aSgm89044 * For decryption and verifyRecover, the output buffer should not
12288f8b78aSgm89044 * be less than the modulus
12388f8b78aSgm89044 */
12488f8b78aSgm89044 if (out->cd_length < reqp->dr_ctx.modlen && (mode == DCA_RSA_DEC ||
12588f8b78aSgm89044 mode == DCA_RSA_VRFYR) &&
12688f8b78aSgm89044 reqp->dr_ctx.ctx_cm_type == RSA_X_509_MECH_INFO_TYPE) {
12788f8b78aSgm89044 out->cd_length = reqp->dr_ctx.modlen;
12888f8b78aSgm89044 rv = CRYPTO_BUFFER_TOO_SMALL;
12988f8b78aSgm89044 goto errout;
13088f8b78aSgm89044 }
13188f8b78aSgm89044
13288f8b78aSgm89044 /* For decrypt and verify, the input should not be less than output */
13388f8b78aSgm89044 if (out && len < out->cd_length) {
13488f8b78aSgm89044 if ((rv = decrypt_error_code(mode,
13588f8b78aSgm89044 CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
13688f8b78aSgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_SUCCESS)) !=
13788f8b78aSgm89044 CRYPTO_SUCCESS)
13888f8b78aSgm89044 goto errout;
13988f8b78aSgm89044 }
14088f8b78aSgm89044
14188f8b78aSgm89044 if ((daddr = dca_bufdaddr(in)) == NULL && len > 0) {
14288f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
14388f8b78aSgm89044 goto errout;
14488f8b78aSgm89044 }
14588f8b78aSgm89044
14688f8b78aSgm89044 if (dca_numcmp(daddr, len, (char *)reqp->dr_ctx.mod,
14788f8b78aSgm89044 reqp->dr_ctx.modlen) > 0) {
14888f8b78aSgm89044 DBG(dca, DWARN,
14988f8b78aSgm89044 "dca_rsastart: input larger (numerically) than modulus!");
15088f8b78aSgm89044 rv = decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
15188f8b78aSgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
15288f8b78aSgm89044 goto errout;
15388f8b78aSgm89044 }
15488f8b78aSgm89044
15588f8b78aSgm89044 reqp->dr_byte_stat = -1;
15688f8b78aSgm89044 reqp->dr_in = in;
15788f8b78aSgm89044 reqp->dr_out = out;
15888f8b78aSgm89044 reqp->dr_kcf_req = req;
15988f8b78aSgm89044 if (mode == DCA_RSA_VRFY)
16088f8b78aSgm89044 reqp->dr_callback = dca_rsaverifydone;
16188f8b78aSgm89044 else
16288f8b78aSgm89044 reqp->dr_callback = dca_rsadone;
16388f8b78aSgm89044
16488f8b78aSgm89044 dca_reverse(daddr, reqp->dr_ibuf_kaddr, len, reqp->dr_pkt_length);
16588f8b78aSgm89044 if (mode == DCA_RSA_ENC || mode == DCA_RSA_SIGN ||
16688f8b78aSgm89044 mode == DCA_RSA_SIGNR) {
16788f8b78aSgm89044 /*
16888f8b78aSgm89044 * Needs to pad appropriately for encrypt, sign, and
16988f8b78aSgm89044 * sign_recover
17088f8b78aSgm89044 */
17188f8b78aSgm89044 if (reqp->dr_ctx.ctx_cm_type == RSA_PKCS_MECH_INFO_TYPE) {
17288f8b78aSgm89044 if ((rv = dca_pkcs1_padding(dca, reqp->dr_ibuf_kaddr,
17388f8b78aSgm89044 len, reqp->dr_ctx.modlen, reqp->dr_ctx.pqfix)) !=
17488f8b78aSgm89044 CRYPTO_QUEUED)
17588f8b78aSgm89044 goto errout;
17688f8b78aSgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
17788f8b78aSgm89044 RSA_X_509_MECH_INFO_TYPE) {
17888f8b78aSgm89044 if ((rv = dca_x509_padding(reqp->dr_ibuf_kaddr,
17988f8b78aSgm89044 len, reqp->dr_pkt_length)) != CRYPTO_QUEUED)
18088f8b78aSgm89044 goto errout;
18188f8b78aSgm89044 }
18288f8b78aSgm89044 }
18388f8b78aSgm89044 reqp->dr_ctx.mode = mode;
18488f8b78aSgm89044
18588f8b78aSgm89044 /*
18688f8b78aSgm89044 * Since the max RSA input size is 256 bytes (2048 bits), the firstx
18788f8b78aSgm89044 * page (at least 4096 bytes) in the pre-mapped buffer is large enough.
18888f8b78aSgm89044 * Therefore, we use this first page for RSA.
18988f8b78aSgm89044 */
19088f8b78aSgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_head.dc_buffer_paddr;
19188f8b78aSgm89044 reqp->dr_in_next = 0;
19288f8b78aSgm89044 reqp->dr_in_len = reqp->dr_pkt_length;
19388f8b78aSgm89044 reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
19488f8b78aSgm89044 reqp->dr_out_next = 0;
19588f8b78aSgm89044 reqp->dr_out_len = reqp->dr_pkt_length;
19688f8b78aSgm89044
19788f8b78aSgm89044 /* schedule the work by doing a submit */
19888f8b78aSgm89044 rv = dca_start(dca, reqp, MCR2, 1);
19988f8b78aSgm89044
20088f8b78aSgm89044
20188f8b78aSgm89044 errout:
20288f8b78aSgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL)
20388f8b78aSgm89044 (void) dca_free_context(ctx);
20488f8b78aSgm89044
20588f8b78aSgm89044 return (rv);
20688f8b78aSgm89044 }
20788f8b78aSgm89044
20888f8b78aSgm89044 void
dca_rsadone(dca_request_t * reqp,int errno)20988f8b78aSgm89044 dca_rsadone(dca_request_t *reqp, int errno)
21088f8b78aSgm89044 {
21188f8b78aSgm89044 if (errno == CRYPTO_SUCCESS) {
21288f8b78aSgm89044 int outsz = reqp->dr_out->cd_length;
21388f8b78aSgm89044 caddr_t daddr;
21488f8b78aSgm89044
21588f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, reqp->dr_out_len,
21688f8b78aSgm89044 DDI_DMA_SYNC_FORKERNEL);
21788f8b78aSgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
21888f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
21988f8b78aSgm89044 reqp->destroy = TRUE;
22088f8b78aSgm89044 errno = CRYPTO_DEVICE_ERROR;
22188f8b78aSgm89044 goto errout;
22288f8b78aSgm89044 }
22388f8b78aSgm89044
22488f8b78aSgm89044 if (reqp->dr_ctx.mode == DCA_RSA_DEC ||
22588f8b78aSgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFY ||
22688f8b78aSgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFYR) {
22788f8b78aSgm89044 /*
22888f8b78aSgm89044 * Needs to unpad appropriately for decrypt, verify,
22988f8b78aSgm89044 * and verify_recover
23088f8b78aSgm89044 */
23188f8b78aSgm89044 if (reqp->dr_ctx.ctx_cm_type ==
23288f8b78aSgm89044 RSA_PKCS_MECH_INFO_TYPE) {
23388f8b78aSgm89044 errno = dca_pkcs1_unpadding(
23488f8b78aSgm89044 reqp->dr_obuf_kaddr, &outsz,
23588f8b78aSgm89044 reqp->dr_ctx.modlen, reqp->dr_ctx.mode);
23688f8b78aSgm89044
23788f8b78aSgm89044 /* check for bad data errors */
23888f8b78aSgm89044 if (errno != CRYPTO_SUCCESS &&
23988f8b78aSgm89044 errno != CRYPTO_BUFFER_TOO_SMALL) {
24088f8b78aSgm89044 goto errout;
24188f8b78aSgm89044 }
24288f8b78aSgm89044 if (dca_bufdaddr(reqp->dr_out) == NULL) {
24388f8b78aSgm89044 errno = CRYPTO_BUFFER_TOO_SMALL;
24488f8b78aSgm89044 }
24588f8b78aSgm89044 if (errno == CRYPTO_BUFFER_TOO_SMALL) {
24688f8b78aSgm89044 reqp->dr_out->cd_length = outsz;
24788f8b78aSgm89044 goto errout;
24888f8b78aSgm89044 }
24988f8b78aSgm89044 /* Reset the output data length */
25088f8b78aSgm89044 reqp->dr_out->cd_length = outsz;
25188f8b78aSgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
25288f8b78aSgm89044 RSA_X_509_MECH_INFO_TYPE) {
25388f8b78aSgm89044 if ((errno = dca_x509_unpadding(
25488f8b78aSgm89044 reqp->dr_obuf_kaddr, outsz,
25588f8b78aSgm89044 reqp->dr_pkt_length, reqp->dr_ctx.mode)) !=
25688f8b78aSgm89044 CRYPTO_SUCCESS)
25788f8b78aSgm89044 goto errout;
25888f8b78aSgm89044 }
25988f8b78aSgm89044 }
26088f8b78aSgm89044
26188f8b78aSgm89044 if ((daddr = dca_bufdaddr(reqp->dr_out)) == NULL) {
26288f8b78aSgm89044 DBG(reqp->dr_dca, DINTR,
26388f8b78aSgm89044 "dca_rsadone: reqp->dr_out is bad");
26488f8b78aSgm89044 errno = CRYPTO_ARGUMENTS_BAD;
26588f8b78aSgm89044 goto errout;
26688f8b78aSgm89044 }
26788f8b78aSgm89044 /*
26888f8b78aSgm89044 * Note that there may be some number of null bytes
26988f8b78aSgm89044 * at the end of the source (result), but we don't care
27088f8b78aSgm89044 * about them -- they are place holders only and are
27188f8b78aSgm89044 * truncated here.
27288f8b78aSgm89044 */
27388f8b78aSgm89044 dca_reverse(reqp->dr_obuf_kaddr, daddr, outsz, outsz);
27488f8b78aSgm89044 }
27588f8b78aSgm89044 errout:
27688f8b78aSgm89044 ASSERT(reqp->dr_kcf_req != NULL);
27788f8b78aSgm89044
27888f8b78aSgm89044 /* notify framework that request is completed */
27988f8b78aSgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
28088f8b78aSgm89044 DBG(reqp->dr_dca, DINTR,
28188f8b78aSgm89044 "dca_rsadone: returning 0x%x to the kef via crypto_op_notification",
28288f8b78aSgm89044 errno);
28388f8b78aSgm89044
28488f8b78aSgm89044 /*
28588f8b78aSgm89044 * For non-atomic operations, reqp will be freed in the kCF
28688f8b78aSgm89044 * callback function since it may be needed again if
28788f8b78aSgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
28888f8b78aSgm89044 */
28988f8b78aSgm89044 if (reqp->dr_ctx.atomic) {
29088f8b78aSgm89044 crypto_ctx_t ctx;
29188f8b78aSgm89044 ctx.cc_provider_private = reqp;
29288f8b78aSgm89044 dca_rsactxfree(&ctx);
29388f8b78aSgm89044 }
29488f8b78aSgm89044 }
29588f8b78aSgm89044
29688f8b78aSgm89044 void
dca_rsaverifydone(dca_request_t * reqp,int errno)29788f8b78aSgm89044 dca_rsaverifydone(dca_request_t *reqp, int errno)
29888f8b78aSgm89044 {
29988f8b78aSgm89044 if (errno == CRYPTO_SUCCESS) {
30088f8b78aSgm89044 char scratch[RSA_MAX_KEY_LEN];
30188f8b78aSgm89044 int outsz = reqp->dr_out->cd_length;
30288f8b78aSgm89044 caddr_t daddr;
30388f8b78aSgm89044
30488f8b78aSgm89044 /*
30588f8b78aSgm89044 * ASSUMPTION: the signature length was already
30688f8b78aSgm89044 * checked on the way in, and it is a valid length.
30788f8b78aSgm89044 */
30888f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, outsz,
30988f8b78aSgm89044 DDI_DMA_SYNC_FORKERNEL);
31088f8b78aSgm89044 if (dca_check_dma_handle(reqp->dr_dca, reqp->dr_obuf_dmah,
31188f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
31288f8b78aSgm89044 reqp->destroy = TRUE;
31388f8b78aSgm89044 errno = CRYPTO_DEVICE_ERROR;
31488f8b78aSgm89044 goto errout;
31588f8b78aSgm89044 }
31688f8b78aSgm89044
31788f8b78aSgm89044 if (reqp->dr_ctx.mode == DCA_RSA_DEC ||
31888f8b78aSgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFY ||
31988f8b78aSgm89044 reqp->dr_ctx.mode == DCA_RSA_VRFYR) {
32088f8b78aSgm89044 /*
32188f8b78aSgm89044 * Needs to unpad appropriately for decrypt, verify,
32288f8b78aSgm89044 * and verify_recover
32388f8b78aSgm89044 */
32488f8b78aSgm89044 if (reqp->dr_ctx.ctx_cm_type ==
32588f8b78aSgm89044 RSA_PKCS_MECH_INFO_TYPE) {
32688f8b78aSgm89044 errno = dca_pkcs1_unpadding(
32788f8b78aSgm89044 reqp->dr_obuf_kaddr, &outsz,
32888f8b78aSgm89044 reqp->dr_ctx.modlen, reqp->dr_ctx.mode);
32988f8b78aSgm89044
33088f8b78aSgm89044 /* check for bad data errors */
33188f8b78aSgm89044 if (errno != CRYPTO_SUCCESS &&
33288f8b78aSgm89044 errno != CRYPTO_BUFFER_TOO_SMALL) {
33388f8b78aSgm89044 goto errout;
33488f8b78aSgm89044 }
33588f8b78aSgm89044 if (dca_bufdaddr(reqp->dr_out) == NULL) {
33688f8b78aSgm89044 errno = CRYPTO_BUFFER_TOO_SMALL;
33788f8b78aSgm89044 }
33888f8b78aSgm89044 if (errno == CRYPTO_BUFFER_TOO_SMALL) {
33988f8b78aSgm89044 reqp->dr_out->cd_length = outsz;
34088f8b78aSgm89044 goto errout;
34188f8b78aSgm89044 }
34288f8b78aSgm89044 /* Reset the output data length */
34388f8b78aSgm89044 reqp->dr_out->cd_length = outsz;
34488f8b78aSgm89044 } else if (reqp->dr_ctx.ctx_cm_type ==
34588f8b78aSgm89044 RSA_X_509_MECH_INFO_TYPE) {
34688f8b78aSgm89044 if ((errno = dca_x509_unpadding(
34788f8b78aSgm89044 reqp->dr_obuf_kaddr, outsz,
34888f8b78aSgm89044 reqp->dr_pkt_length, reqp->dr_ctx.mode)) !=
34988f8b78aSgm89044 CRYPTO_SUCCESS)
35088f8b78aSgm89044 goto errout;
35188f8b78aSgm89044 }
35288f8b78aSgm89044 }
35388f8b78aSgm89044
35488f8b78aSgm89044 dca_reverse(reqp->dr_obuf_kaddr, scratch, outsz, outsz);
35588f8b78aSgm89044
35688f8b78aSgm89044 if ((daddr = dca_bufdaddr(reqp->dr_out)) == NULL) {
35788f8b78aSgm89044 errno = CRYPTO_ARGUMENTS_BAD;
35888f8b78aSgm89044 goto errout;
35988f8b78aSgm89044 }
36088f8b78aSgm89044 if (dca_numcmp(daddr, reqp->dr_out->cd_length, scratch,
36188f8b78aSgm89044 outsz) != 0) {
36288f8b78aSgm89044 /* VERIFY FAILED */
36388f8b78aSgm89044 errno = CRYPTO_SIGNATURE_INVALID;
36488f8b78aSgm89044 }
36588f8b78aSgm89044 }
36688f8b78aSgm89044 errout:
36788f8b78aSgm89044 ASSERT(reqp->dr_kcf_req != NULL);
36888f8b78aSgm89044
36988f8b78aSgm89044 /* notify framework that request is completed */
37088f8b78aSgm89044 crypto_op_notification(reqp->dr_kcf_req, errno);
37188f8b78aSgm89044 DBG(reqp->dr_dca, DINTR,
37288f8b78aSgm89044 "dca_rsaverifydone: rtn 0x%x to the kef via crypto_op_notification",
37388f8b78aSgm89044 errno);
37488f8b78aSgm89044
37588f8b78aSgm89044 /*
37688f8b78aSgm89044 * For non-atomic operations, reqp will be freed in the kCF
37788f8b78aSgm89044 * callback function since it may be needed again if
37888f8b78aSgm89044 * CRYPTO_BUFFER_TOO_SMALL is returned to kCF
37988f8b78aSgm89044 */
38088f8b78aSgm89044 if (reqp->dr_ctx.atomic) {
38188f8b78aSgm89044 crypto_ctx_t ctx;
38288f8b78aSgm89044 ctx.cc_provider_private = reqp;
38388f8b78aSgm89044 dca_rsactxfree(&ctx);
38488f8b78aSgm89044 }
38588f8b78aSgm89044 }
38688f8b78aSgm89044
38788f8b78aSgm89044 /*
38888f8b78aSgm89044 * Setup either a public or a private RSA key for subsequent uses
38988f8b78aSgm89044 */
39088f8b78aSgm89044 int
dca_rsainit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag)39188f8b78aSgm89044 dca_rsainit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
39288f8b78aSgm89044 crypto_key_t *key, int kmflag)
39388f8b78aSgm89044 {
39488f8b78aSgm89044 crypto_object_attribute_t *attr;
39588f8b78aSgm89044 unsigned expname = 0;
39688f8b78aSgm89044 void *attrdata;
39788f8b78aSgm89044 int rv;
39888f8b78aSgm89044
39988f8b78aSgm89044 uchar_t *exp;
40088f8b78aSgm89044 uchar_t *p;
40188f8b78aSgm89044 uchar_t *q;
40288f8b78aSgm89044 uchar_t *dp;
40388f8b78aSgm89044 uchar_t *dq;
40488f8b78aSgm89044 uchar_t *pinv;
40588f8b78aSgm89044
40688f8b78aSgm89044 unsigned explen = 0;
40788f8b78aSgm89044 unsigned plen = 0;
40888f8b78aSgm89044 unsigned qlen = 0;
40988f8b78aSgm89044 unsigned dplen = 0;
41088f8b78aSgm89044 unsigned dqlen = 0;
41188f8b78aSgm89044 unsigned pinvlen = 0;
41288f8b78aSgm89044
41388f8b78aSgm89044 unsigned modbits, expbits, pbits, qbits;
41488f8b78aSgm89044 unsigned modfix, expfix, pqfix = 0;
41588f8b78aSgm89044 uint16_t ctxlen;
41688f8b78aSgm89044 caddr_t kaddr;
41788f8b78aSgm89044 dca_request_t *reqp = NULL;
41888f8b78aSgm89044 dca_t *dca = (dca_t *)ctx->cc_provider;
41988f8b78aSgm89044
42088f8b78aSgm89044 DBG(NULL, DENTRY, "dca_rsainit: start");
42188f8b78aSgm89044
42288f8b78aSgm89044 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
42388f8b78aSgm89044 DBG(NULL, DWARN,
42488f8b78aSgm89044 "dca_rsainit: unable to allocate request for RSA");
42588f8b78aSgm89044 rv = CRYPTO_HOST_MEMORY;
42688f8b78aSgm89044 goto errout;
42788f8b78aSgm89044 }
42888f8b78aSgm89044
42988f8b78aSgm89044 reqp->dr_ctx.ctx_cm_type = mechanism->cm_type;
43088f8b78aSgm89044 ctx->cc_provider_private = reqp;
43188f8b78aSgm89044
43288f8b78aSgm89044 /*
43388f8b78aSgm89044 * Key type can be either RAW, or REFERENCE, or ATTR_LIST (VALUE).
43488f8b78aSgm89044 * Only ATTR_LIST is supported on Deimos for RSA.
43588f8b78aSgm89044 */
43688f8b78aSgm89044 if ((attr = dca_get_key_attr(key)) == NULL) {
43788f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: key attributes missing");
43888f8b78aSgm89044 rv = CRYPTO_KEY_TYPE_INCONSISTENT;
43988f8b78aSgm89044 goto errout;
44088f8b78aSgm89044 }
44188f8b78aSgm89044
44288f8b78aSgm89044 if (dca_find_attribute(attr, key->ck_count, CKA_PUBLIC_EXPONENT))
44388f8b78aSgm89044 expname = CKA_PUBLIC_EXPONENT;
44488f8b78aSgm89044
44588f8b78aSgm89044 /*
44688f8b78aSgm89044 * RSA public key has only public exponent. RSA private key must have
44788f8b78aSgm89044 * private exponent. However, it may also have public exponent.
44888f8b78aSgm89044 * Thus, the existance of a private exponent indicates a private key.
44988f8b78aSgm89044 */
45088f8b78aSgm89044 if (dca_find_attribute(attr, key->ck_count, CKA_PRIVATE_EXPONENT))
45188f8b78aSgm89044 expname = CKA_PRIVATE_EXPONENT;
45288f8b78aSgm89044
45388f8b78aSgm89044 if (!expname) {
45488f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: no exponent in key");
45588f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
45688f8b78aSgm89044 goto errout;
45788f8b78aSgm89044 }
45888f8b78aSgm89044
45988f8b78aSgm89044 /* Modulus */
46088f8b78aSgm89044 if ((rv = dca_attr_lookup_uint8_array(attr, key->ck_count, CKA_MODULUS,
46188f8b78aSgm89044 &attrdata, &(reqp->dr_ctx.modlen))) != CRYPTO_SUCCESS) {
46288f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: failed to retrieve modulus");
46388f8b78aSgm89044 goto errout;
46488f8b78aSgm89044 }
46588f8b78aSgm89044 if ((reqp->dr_ctx.modlen == 0) ||
46688f8b78aSgm89044 (reqp->dr_ctx.modlen > RSA_MAX_KEY_LEN)) {
46788f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: bad modulus size");
46888f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
46988f8b78aSgm89044 goto errout;
47088f8b78aSgm89044 }
47188f8b78aSgm89044 if ((reqp->dr_ctx.mod = kmem_alloc(reqp->dr_ctx.modlen, kmflag)) ==
47288f8b78aSgm89044 NULL) {
47388f8b78aSgm89044 rv = CRYPTO_HOST_MEMORY;
47488f8b78aSgm89044 goto errout;
47588f8b78aSgm89044 }
47688f8b78aSgm89044 bcopy(attrdata, reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
47788f8b78aSgm89044
47888f8b78aSgm89044 /* Exponent */
47988f8b78aSgm89044 if ((rv = dca_attr_lookup_uint8_array(attr, key->ck_count, expname,
48088f8b78aSgm89044 (void **) &exp, &explen)) != CRYPTO_SUCCESS) {
48188f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: failed to retrieve exponent");
48288f8b78aSgm89044 goto errout;
48388f8b78aSgm89044 }
48488f8b78aSgm89044 if ((explen == 0) || (explen > RSA_MAX_KEY_LEN)) {
48588f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: bad exponent size");
48688f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
48788f8b78aSgm89044 goto errout;
48888f8b78aSgm89044 }
48988f8b78aSgm89044
49088f8b78aSgm89044 /* Lookup private attributes */
49188f8b78aSgm89044 if (expname == CKA_PRIVATE_EXPONENT) {
49288f8b78aSgm89044 /* Prime 1 */
49388f8b78aSgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
49488f8b78aSgm89044 CKA_PRIME_1, (void **)&q, &qlen);
49588f8b78aSgm89044
49688f8b78aSgm89044 /* Prime 2 */
49788f8b78aSgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
49888f8b78aSgm89044 CKA_PRIME_2, (void **)&p, &plen);
49988f8b78aSgm89044
50088f8b78aSgm89044 /* Exponent 1 */
50188f8b78aSgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
50288f8b78aSgm89044 CKA_EXPONENT_1, (void **)&dq, &dqlen);
50388f8b78aSgm89044
50488f8b78aSgm89044 /* Exponent 2 */
50588f8b78aSgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
50688f8b78aSgm89044 CKA_EXPONENT_2, (void **)&dp, &dplen);
50788f8b78aSgm89044
50888f8b78aSgm89044 /* Coefficient */
50988f8b78aSgm89044 (void) dca_attr_lookup_uint8_array(attr, key->ck_count,
51088f8b78aSgm89044 CKA_COEFFICIENT, (void **)&pinv, &pinvlen);
51188f8b78aSgm89044 }
51288f8b78aSgm89044
51388f8b78aSgm89044 modbits = dca_bitlen(reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
51488f8b78aSgm89044 expbits = dca_bitlen(exp, explen);
51588f8b78aSgm89044
51688f8b78aSgm89044 if ((modfix = dca_padfull(modbits)) == 0) {
51788f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsainit: modulus too long");
51888f8b78aSgm89044 rv = CRYPTO_KEY_SIZE_RANGE;
51988f8b78aSgm89044 goto errout;
52088f8b78aSgm89044 }
52188f8b78aSgm89044 expfix = ROUNDUP(explen, sizeof (uint32_t));
52288f8b78aSgm89044
52388f8b78aSgm89044 if (plen && qlen && dplen && dqlen && pinvlen) {
52488f8b78aSgm89044 unsigned pfix, qfix;
52588f8b78aSgm89044 qbits = dca_bitlen(q, qlen);
52688f8b78aSgm89044 pbits = dca_bitlen(p, plen);
52788f8b78aSgm89044 qfix = dca_padhalf(qbits);
52888f8b78aSgm89044 pfix = dca_padhalf(pbits);
52988f8b78aSgm89044 if (pfix & qfix)
53088f8b78aSgm89044 pqfix = max(pfix, qfix);
53188f8b78aSgm89044 }
53288f8b78aSgm89044
53388f8b78aSgm89044 if (pqfix) {
53488f8b78aSgm89044 reqp->dr_job_stat = DS_RSAPRIVATE;
53588f8b78aSgm89044 reqp->dr_pkt_length = 2 * pqfix;
53688f8b78aSgm89044 } else {
53788f8b78aSgm89044 reqp->dr_job_stat = DS_RSAPUBLIC;
53888f8b78aSgm89044 reqp->dr_pkt_length = modfix;
53988f8b78aSgm89044 }
54088f8b78aSgm89044
54188f8b78aSgm89044 if (pqfix) {
54288f8b78aSgm89044 /*
54388f8b78aSgm89044 * NOTE: chip's notion of p vs. q is reversed from
54488f8b78aSgm89044 * PKCS#11. We use the chip's notion in our variable
54588f8b78aSgm89044 * naming.
54688f8b78aSgm89044 */
54788f8b78aSgm89044 ctxlen = 8 + pqfix * 5;
54888f8b78aSgm89044
54988f8b78aSgm89044 /* write out the context structure */
55088f8b78aSgm89044 PUTCTX16(reqp, CTX_CMD, CMD_RSAPRIVATE);
55188f8b78aSgm89044 PUTCTX16(reqp, CTX_LENGTH, ctxlen);
55288f8b78aSgm89044 /* exponent and modulus length in bits!!! */
55388f8b78aSgm89044 PUTCTX16(reqp, CTX_RSAQLEN, qbits);
55488f8b78aSgm89044 PUTCTX16(reqp, CTX_RSAPLEN, pbits);
55588f8b78aSgm89044
55688f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_RSABIGNUMS;
55788f8b78aSgm89044
55888f8b78aSgm89044 /* store the bignums */
55988f8b78aSgm89044 dca_reverse(p, kaddr, plen, pqfix);
56088f8b78aSgm89044 kaddr += pqfix;
56188f8b78aSgm89044
56288f8b78aSgm89044 dca_reverse(q, kaddr, qlen, pqfix);
56388f8b78aSgm89044 kaddr += pqfix;
56488f8b78aSgm89044
56588f8b78aSgm89044 dca_reverse(dp, kaddr, dplen, pqfix);
56688f8b78aSgm89044 kaddr += pqfix;
56788f8b78aSgm89044
56888f8b78aSgm89044 dca_reverse(dq, kaddr, dqlen, pqfix);
56988f8b78aSgm89044 kaddr += pqfix;
57088f8b78aSgm89044
57188f8b78aSgm89044 dca_reverse(pinv, kaddr, pinvlen, pqfix);
57288f8b78aSgm89044 kaddr += pqfix;
57388f8b78aSgm89044 } else {
57488f8b78aSgm89044 ctxlen = 8 + modfix + expfix;
57588f8b78aSgm89044 /* write out the context structure */
57688f8b78aSgm89044 PUTCTX16(reqp, CTX_CMD, CMD_RSAPUBLIC);
57788f8b78aSgm89044 PUTCTX16(reqp, CTX_LENGTH, (uint16_t)ctxlen);
57888f8b78aSgm89044 /* exponent and modulus length in bits!!! */
57988f8b78aSgm89044 PUTCTX16(reqp, CTX_RSAEXPLEN, expbits);
58088f8b78aSgm89044 PUTCTX16(reqp, CTX_RSAMODLEN, modbits);
58188f8b78aSgm89044
58288f8b78aSgm89044 kaddr = reqp->dr_ctx_kaddr + CTX_RSABIGNUMS;
58388f8b78aSgm89044
58488f8b78aSgm89044 /* store the bignums */
58588f8b78aSgm89044 dca_reverse(reqp->dr_ctx.mod, kaddr, reqp->dr_ctx.modlen,
58688f8b78aSgm89044 modfix);
58788f8b78aSgm89044 kaddr += modfix;
58888f8b78aSgm89044
58988f8b78aSgm89044 dca_reverse(exp, kaddr, explen, expfix);
59088f8b78aSgm89044 kaddr += expfix;
59188f8b78aSgm89044 }
59288f8b78aSgm89044
59388f8b78aSgm89044 reqp->dr_ctx.pqfix = pqfix;
59488f8b78aSgm89044
59588f8b78aSgm89044 errout:
59688f8b78aSgm89044 if (rv != CRYPTO_SUCCESS)
59788f8b78aSgm89044 dca_rsactxfree(ctx);
59888f8b78aSgm89044
59988f8b78aSgm89044 return (rv);
60088f8b78aSgm89044 }
60188f8b78aSgm89044
60288f8b78aSgm89044 void
dca_rsactxfree(void * arg)60388f8b78aSgm89044 dca_rsactxfree(void *arg)
60488f8b78aSgm89044 {
60588f8b78aSgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg;
60688f8b78aSgm89044 dca_request_t *reqp = ctx->cc_provider_private;
60788f8b78aSgm89044
60888f8b78aSgm89044 if (reqp == NULL)
60988f8b78aSgm89044 return;
61088f8b78aSgm89044
61188f8b78aSgm89044 if (reqp->dr_ctx.mod)
61288f8b78aSgm89044 kmem_free(reqp->dr_ctx.mod, reqp->dr_ctx.modlen);
61388f8b78aSgm89044
61488f8b78aSgm89044 reqp->dr_ctx.mode = 0;
61588f8b78aSgm89044 reqp->dr_ctx.ctx_cm_type = 0;
61688f8b78aSgm89044 reqp->dr_ctx.mod = NULL;
61788f8b78aSgm89044 reqp->dr_ctx.modlen = 0;
61888f8b78aSgm89044 reqp->dr_ctx.pqfix = 0;
61988f8b78aSgm89044 reqp->dr_ctx.atomic = 0;
62088f8b78aSgm89044
62188f8b78aSgm89044 if (reqp->destroy)
62288f8b78aSgm89044 dca_destroyreq(reqp);
62388f8b78aSgm89044 else
62488f8b78aSgm89044 dca_freereq(reqp);
62588f8b78aSgm89044
62688f8b78aSgm89044 ctx->cc_provider_private = NULL;
62788f8b78aSgm89044 }
62888f8b78aSgm89044
62988f8b78aSgm89044 int
dca_rsaatomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * input,crypto_data_t * output,int kmflag,crypto_req_handle_t req,int mode)63088f8b78aSgm89044 dca_rsaatomic(crypto_provider_handle_t provider,
63188f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
63288f8b78aSgm89044 crypto_key_t *key, crypto_data_t *input, crypto_data_t *output,
63388f8b78aSgm89044 int kmflag, crypto_req_handle_t req, int mode)
63488f8b78aSgm89044 {
63588f8b78aSgm89044 crypto_ctx_t ctx; /* on the stack */
63688f8b78aSgm89044 int rv;
63788f8b78aSgm89044
63888f8b78aSgm89044 ctx.cc_provider = provider;
63988f8b78aSgm89044 ctx.cc_session = session_id;
64088f8b78aSgm89044
64188f8b78aSgm89044 rv = dca_rsainit(&ctx, mechanism, key, kmflag);
64288f8b78aSgm89044 if (rv != CRYPTO_SUCCESS) {
64388f8b78aSgm89044 DBG(NULL, DWARN, "dca_rsaatomic: dca_rsainit() failed");
64488f8b78aSgm89044 /* The content of ctx should have been freed already */
64588f8b78aSgm89044 return (rv);
64688f8b78aSgm89044 }
64788f8b78aSgm89044
64888f8b78aSgm89044 /*
64988f8b78aSgm89044 * Set the atomic flag so that the hardware callback function
65088f8b78aSgm89044 * will free the context.
65188f8b78aSgm89044 */
65288f8b78aSgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
65388f8b78aSgm89044
654*d8dd9913Sgm89044 /* check for inplace ops */
655*d8dd9913Sgm89044 if (input == output) {
656*d8dd9913Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_flags
657*d8dd9913Sgm89044 |= DR_INPLACE;
658*d8dd9913Sgm89044 }
659*d8dd9913Sgm89044
66088f8b78aSgm89044 rv = dca_rsastart(&ctx, input, output, req, mode);
66188f8b78aSgm89044
66288f8b78aSgm89044 /*
66388f8b78aSgm89044 * The context will be freed in the hardware callback function if it
66488f8b78aSgm89044 * is queued
66588f8b78aSgm89044 */
66688f8b78aSgm89044 if (rv != CRYPTO_QUEUED)
66788f8b78aSgm89044 dca_rsactxfree(&ctx);
66888f8b78aSgm89044
66988f8b78aSgm89044 return (rv);
67088f8b78aSgm89044 }
67188f8b78aSgm89044
67288f8b78aSgm89044
67388f8b78aSgm89044 /*
67488f8b78aSgm89044 * For RSA_PKCS padding and unpadding:
67588f8b78aSgm89044 * 1. The minimum padding is 11 bytes.
67688f8b78aSgm89044 * 2. The first and the last bytes must 0.
67788f8b78aSgm89044 * 3. The second byte is 1 for private and 2 for public keys.
67888f8b78aSgm89044 * 4. Pad with 0xff for private and non-zero random for public keys.
67988f8b78aSgm89044 */
68088f8b78aSgm89044 static int
dca_pkcs1_padding(dca_t * dca,caddr_t buf,int flen,int tlen,int private)68188f8b78aSgm89044 dca_pkcs1_padding(dca_t *dca, caddr_t buf, int flen, int tlen, int private)
68288f8b78aSgm89044 {
68388f8b78aSgm89044 int i;
68488f8b78aSgm89044
68588f8b78aSgm89044 DBG(NULL, DENTRY,
68688f8b78aSgm89044 "dca_pkcs1_padding: tlen: %d, flen: %d: private: %d\n",
68788f8b78aSgm89044 tlen, flen, private);
68888f8b78aSgm89044
68988f8b78aSgm89044 if (flen > tlen - 11)
69088f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
69188f8b78aSgm89044
69288f8b78aSgm89044 if (private) {
69388f8b78aSgm89044 /* Padding for private encrypt */
69488f8b78aSgm89044 buf[flen] = '\0';
69588f8b78aSgm89044 for (i = flen + 1; i < tlen - 2; i++) {
69688f8b78aSgm89044 buf[i] = (unsigned char) 0xff;
69788f8b78aSgm89044 }
69888f8b78aSgm89044 buf[tlen - 2] = 1;
69988f8b78aSgm89044 buf[tlen - 1] = 0;
70088f8b78aSgm89044 } else {
70188f8b78aSgm89044 /* Padding for public encrypt */
70288f8b78aSgm89044 buf[flen] = '\0';
70388f8b78aSgm89044
70488f8b78aSgm89044 if (dca_random_buffer(dca, &buf[flen+1], tlen - flen - 3) !=
70588f8b78aSgm89044 CRYPTO_SUCCESS)
70688f8b78aSgm89044 return (CRYPTO_RANDOM_NO_RNG);
70788f8b78aSgm89044
70888f8b78aSgm89044 buf[tlen - 2] = 2;
70988f8b78aSgm89044 buf[tlen - 1] = 0;
71088f8b78aSgm89044 }
71188f8b78aSgm89044
71288f8b78aSgm89044 return (CRYPTO_QUEUED);
71388f8b78aSgm89044 }
71488f8b78aSgm89044
71588f8b78aSgm89044 static int
dca_pkcs1_unpadding(char * buf,int * tlen,int flen,int mode)71688f8b78aSgm89044 dca_pkcs1_unpadding(char *buf, int *tlen, int flen, int mode)
71788f8b78aSgm89044 {
71888f8b78aSgm89044 int i;
71988f8b78aSgm89044 const unsigned char *p;
72088f8b78aSgm89044 unsigned char type;
72188f8b78aSgm89044
72288f8b78aSgm89044 DBG(NULL, DENTRY, "dca_pkcs1_unpadding: tlen: %d, flen: %d\n",
72388f8b78aSgm89044 *tlen, flen);
72488f8b78aSgm89044
72588f8b78aSgm89044 p = (unsigned char *) buf + (flen-1);
72688f8b78aSgm89044 if (*(p--) != 0)
72788f8b78aSgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
72888f8b78aSgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
72988f8b78aSgm89044
73088f8b78aSgm89044 /* It is ok if the data length is 0 after removing the padding */
73188f8b78aSgm89044 type = *(p--);
73288f8b78aSgm89044 if (type == 01) {
73388f8b78aSgm89044 for (i = flen - 3; i >= 0; i--) {
73488f8b78aSgm89044 if (*p != 0xff) {
73588f8b78aSgm89044 if (*p == '\0') {
73688f8b78aSgm89044 p--;
73788f8b78aSgm89044 break;
73888f8b78aSgm89044 } else {
73988f8b78aSgm89044 return decrypt_error_code(mode,
74088f8b78aSgm89044 CRYPTO_ENCRYPTED_DATA_INVALID,
74188f8b78aSgm89044 CRYPTO_SIGNATURE_INVALID,
74288f8b78aSgm89044 CRYPTO_DATA_INVALID);
74388f8b78aSgm89044 }
74488f8b78aSgm89044 }
74588f8b78aSgm89044 p--;
74688f8b78aSgm89044 }
74788f8b78aSgm89044 } else if (type == 02) {
74888f8b78aSgm89044 for (i = flen - 3; i >= 0; i--) {
74988f8b78aSgm89044 if (*p == '\0') {
75088f8b78aSgm89044 p--;
75188f8b78aSgm89044 break;
75288f8b78aSgm89044 }
75388f8b78aSgm89044 p--;
75488f8b78aSgm89044 }
75588f8b78aSgm89044 } else {
75688f8b78aSgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
75788f8b78aSgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
75888f8b78aSgm89044 }
75988f8b78aSgm89044
76088f8b78aSgm89044 /* i < 0 means did not find the end of the padding */
76188f8b78aSgm89044 if (i < 0)
76288f8b78aSgm89044 return decrypt_error_code(mode, CRYPTO_ENCRYPTED_DATA_INVALID,
76388f8b78aSgm89044 CRYPTO_SIGNATURE_INVALID, CRYPTO_DATA_INVALID);
76488f8b78aSgm89044
76588f8b78aSgm89044 if (i > *tlen) {
76688f8b78aSgm89044 *tlen = i;
76788f8b78aSgm89044 return (CRYPTO_BUFFER_TOO_SMALL);
76888f8b78aSgm89044 }
76988f8b78aSgm89044
77088f8b78aSgm89044 if (flen - i < 11)
77188f8b78aSgm89044 return decrypt_error_code(mode,
77288f8b78aSgm89044 CRYPTO_ENCRYPTED_DATA_LEN_RANGE,
77388f8b78aSgm89044 CRYPTO_SIGNATURE_LEN_RANGE, CRYPTO_DATA_LEN_RANGE);
77488f8b78aSgm89044
77588f8b78aSgm89044 /* Return the unpadded length to the caller */
77688f8b78aSgm89044 *tlen = i;
77788f8b78aSgm89044
77888f8b78aSgm89044 return (CRYPTO_SUCCESS);
77988f8b78aSgm89044 }
78088f8b78aSgm89044
78188f8b78aSgm89044 /*
78288f8b78aSgm89044 * For RSA_X_509 padding and unpadding, pad all 0s before actual data.
78388f8b78aSgm89044 * Note that the data will be in reverse order.
78488f8b78aSgm89044 */
78588f8b78aSgm89044 static int
dca_x509_padding(caddr_t buf,int flen,int tlen)78688f8b78aSgm89044 dca_x509_padding(caddr_t buf, int flen, int tlen)
78788f8b78aSgm89044 {
78888f8b78aSgm89044 DBG(NULL, DENTRY, "dca_x509_padding: tlen: %d, flen: %d\n",
78988f8b78aSgm89044 tlen, flen);
79088f8b78aSgm89044
79188f8b78aSgm89044 bzero(buf+tlen, tlen - flen);
79288f8b78aSgm89044
79388f8b78aSgm89044 return (CRYPTO_QUEUED);
79488f8b78aSgm89044 }
79588f8b78aSgm89044
79688f8b78aSgm89044 /* ARGSUSED */
79788f8b78aSgm89044 static int
dca_x509_unpadding(char * buf,int tlen,int flen,int mode)79888f8b78aSgm89044 dca_x509_unpadding(char *buf, int tlen, int flen, int mode)
79988f8b78aSgm89044 {
80088f8b78aSgm89044 int i;
80188f8b78aSgm89044 const unsigned char *p;
80288f8b78aSgm89044
80388f8b78aSgm89044 DBG(NULL, DENTRY, "dca_x509_unpadding: tlen: %d, flen: %d\n",
80488f8b78aSgm89044 tlen, flen);
80588f8b78aSgm89044
80688f8b78aSgm89044 p = (unsigned char *) buf + flen;
80788f8b78aSgm89044 for (i = tlen; i < flen; i++) {
80888f8b78aSgm89044 if (*(--p) != 0)
80988f8b78aSgm89044 return (CRYPTO_SIGNATURE_INVALID);
81088f8b78aSgm89044 }
81188f8b78aSgm89044
81288f8b78aSgm89044 return (CRYPTO_SUCCESS);
81388f8b78aSgm89044 }
81488f8b78aSgm89044
decrypt_error_code(int mode,int decrypt,int verify,int def)81588f8b78aSgm89044 static int decrypt_error_code(int mode, int decrypt, int verify, int def)
81688f8b78aSgm89044 {
81788f8b78aSgm89044 switch (mode) {
81888f8b78aSgm89044 case DCA_RSA_DEC:
81988f8b78aSgm89044 return (decrypt);
82088f8b78aSgm89044 case DCA_RSA_VRFY:
82188f8b78aSgm89044 case DCA_RSA_VRFYR:
82288f8b78aSgm89044 return (verify);
82388f8b78aSgm89044 default:
82488f8b78aSgm89044 return (def);
82588f8b78aSgm89044 }
82688f8b78aSgm89044 }
827