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