xref: /titanic_50/usr/src/uts/common/crypto/io/dca_rsa.c (revision d8dd99136aadc95161b4031565b92214f8bbc8c8)
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