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 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 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 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 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 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 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 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 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 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 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 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