diff options
Diffstat (limited to 'drivers/s390/crypto/z90hardware.c')
-rw-r--r-- | drivers/s390/crypto/z90hardware.c | 2243 |
1 files changed, 2243 insertions, 0 deletions
diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c new file mode 100644 index 00000000000..beb6a5e0da2 --- /dev/null +++ b/drivers/s390/crypto/z90hardware.c @@ -0,0 +1,2243 @@ +/* + * linux/drivers/s390/crypto/z90hardware.c + * + * z90crypt 1.3.2 + * + * Copyright (C) 2001, 2004 IBM Corporation + * Author(s): Robert Burroughs (burrough@us.ibm.com) + * Eric Rossman (edrossma@us.ibm.com) + * + * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/uaccess.h> +#include <linux/compiler.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/module.h> +#include "z90crypt.h" +#include "z90common.h" + +#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $" + +char z90hardware_version[] __initdata = + "z90hardware.o (" VERSION_Z90HARDWARE_C "/" + VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")"; + +struct cca_token_hdr { + unsigned char token_identifier; + unsigned char version; + unsigned short token_length; + unsigned char reserved[4]; +}; + +#define CCA_TKN_HDR_ID_EXT 0x1E + +struct cca_private_ext_ME_sec { + unsigned char section_identifier; + unsigned char version; + unsigned short section_length; + unsigned char private_key_hash[20]; + unsigned char reserved1[4]; + unsigned char key_format; + unsigned char reserved2; + unsigned char key_name_hash[20]; + unsigned char key_use_flags[4]; + unsigned char reserved3[6]; + unsigned char reserved4[24]; + unsigned char confounder[24]; + unsigned char exponent[128]; + unsigned char modulus[128]; +}; + +#define CCA_PVT_USAGE_ALL 0x80 + +struct cca_public_sec { + unsigned char section_identifier; + unsigned char version; + unsigned short section_length; + unsigned char reserved[2]; + unsigned short exponent_len; + unsigned short modulus_bit_len; + unsigned short modulus_byte_len; + unsigned char exponent[3]; +}; + +struct cca_private_ext_ME { + struct cca_token_hdr pvtMEHdr; + struct cca_private_ext_ME_sec pvtMESec; + struct cca_public_sec pubMESec; +}; + +struct cca_public_key { + struct cca_token_hdr pubHdr; + struct cca_public_sec pubSec; +}; + +struct cca_pvt_ext_CRT_sec { + unsigned char section_identifier; + unsigned char version; + unsigned short section_length; + unsigned char private_key_hash[20]; + unsigned char reserved1[4]; + unsigned char key_format; + unsigned char reserved2; + unsigned char key_name_hash[20]; + unsigned char key_use_flags[4]; + unsigned short p_len; + unsigned short q_len; + unsigned short dp_len; + unsigned short dq_len; + unsigned short u_len; + unsigned short mod_len; + unsigned char reserved3[4]; + unsigned short pad_len; + unsigned char reserved4[52]; + unsigned char confounder[8]; +}; + +#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08 +#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 + +struct cca_private_ext_CRT { + struct cca_token_hdr pvtCrtHdr; + struct cca_pvt_ext_CRT_sec pvtCrtSec; + struct cca_public_sec pubCrtSec; +}; + +struct ap_status_word { + unsigned char q_stat_flags; + unsigned char response_code; + unsigned char reserved[2]; +}; + +#define AP_Q_STATUS_EMPTY 0x80 +#define AP_Q_STATUS_REPLIES_WAITING 0x40 +#define AP_Q_STATUS_ARRAY_FULL 0x20 + +#define AP_RESPONSE_NORMAL 0x00 +#define AP_RESPONSE_Q_NOT_AVAIL 0x01 +#define AP_RESPONSE_RESET_IN_PROGRESS 0x02 +#define AP_RESPONSE_DECONFIGURED 0x03 +#define AP_RESPONSE_CHECKSTOPPED 0x04 +#define AP_RESPONSE_BUSY 0x05 +#define AP_RESPONSE_Q_FULL 0x10 +#define AP_RESPONSE_NO_PENDING_REPLY 0x10 +#define AP_RESPONSE_INDEX_TOO_BIG 0x11 +#define AP_RESPONSE_NO_FIRST_PART 0x13 +#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 + +#define AP_MAX_CDX_BITL 4 +#define AP_RQID_RESERVED_BITL 4 +#define SKIP_BITL (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL) + +struct type4_hdr { + unsigned char reserved1; + unsigned char msg_type_code; + unsigned short msg_len; + unsigned char request_code; + unsigned char msg_fmt; + unsigned short reserved2; +}; + +#define TYPE4_TYPE_CODE 0x04 +#define TYPE4_REQU_CODE 0x40 + +#define TYPE4_SME_LEN 0x0188 +#define TYPE4_LME_LEN 0x0308 +#define TYPE4_SCR_LEN 0x01E0 +#define TYPE4_LCR_LEN 0x03A0 + +#define TYPE4_SME_FMT 0x00 +#define TYPE4_LME_FMT 0x10 +#define TYPE4_SCR_FMT 0x40 +#define TYPE4_LCR_FMT 0x50 + +struct type4_sme { + struct type4_hdr header; + unsigned char message[128]; + unsigned char exponent[128]; + unsigned char modulus[128]; +}; + +struct type4_lme { + struct type4_hdr header; + unsigned char message[256]; + unsigned char exponent[256]; + unsigned char modulus[256]; +}; + +struct type4_scr { + struct type4_hdr header; + unsigned char message[128]; + unsigned char dp[72]; + unsigned char dq[64]; + unsigned char p[72]; + unsigned char q[64]; + unsigned char u[72]; +}; + +struct type4_lcr { + struct type4_hdr header; + unsigned char message[256]; + unsigned char dp[136]; + unsigned char dq[128]; + unsigned char p[136]; + unsigned char q[128]; + unsigned char u[136]; +}; + +union type4_msg { + struct type4_sme sme; + struct type4_lme lme; + struct type4_scr scr; + struct type4_lcr lcr; +}; + +struct type84_hdr { + unsigned char reserved1; + unsigned char code; + unsigned short len; + unsigned char reserved2[4]; +}; + +#define TYPE84_RSP_CODE 0x84 + +struct type6_hdr { + unsigned char reserved1; + unsigned char type; + unsigned char reserved2[2]; + unsigned char right[4]; + unsigned char reserved3[2]; + unsigned char reserved4[2]; + unsigned char apfs[4]; + unsigned int offset1; + unsigned int offset2; + unsigned int offset3; + unsigned int offset4; + unsigned char agent_id[16]; + unsigned char rqid[2]; + unsigned char reserved5[2]; + unsigned char function_code[2]; + unsigned char reserved6[2]; + unsigned int ToCardLen1; + unsigned int ToCardLen2; + unsigned int ToCardLen3; + unsigned int ToCardLen4; + unsigned int FromCardLen1; + unsigned int FromCardLen2; + unsigned int FromCardLen3; + unsigned int FromCardLen4; +}; + +struct CPRB { + unsigned char cprb_len[2]; + unsigned char cprb_ver_id; + unsigned char pad_000; + unsigned char srpi_rtcode[4]; + unsigned char srpi_verb; + unsigned char flags; + unsigned char func_id[2]; + unsigned char checkpoint_flag; + unsigned char resv2; + unsigned char req_parml[2]; + unsigned char req_parmp[4]; + unsigned char req_datal[4]; + unsigned char req_datap[4]; + unsigned char rpl_parml[2]; + unsigned char pad_001[2]; + unsigned char rpl_parmp[4]; + unsigned char rpl_datal[4]; + unsigned char rpl_datap[4]; + unsigned char ccp_rscode[2]; + unsigned char ccp_rtcode[2]; + unsigned char repd_parml[2]; + unsigned char mac_data_len[2]; + unsigned char repd_datal[4]; + unsigned char req_pc[2]; + unsigned char res_origin[8]; + unsigned char mac_value[8]; + unsigned char logon_id[8]; + unsigned char usage_domain[2]; + unsigned char resv3[18]; + unsigned char svr_namel[2]; + unsigned char svr_name[8]; +}; + +struct type6_msg { + struct type6_hdr header; + struct CPRB CPRB; +}; + +union request_msg { + union type4_msg t4msg; + struct type6_msg t6msg; +}; + +struct request_msg_ext { + int q_nr; + unsigned char *psmid; + union request_msg reqMsg; +}; + +struct type82_hdr { + unsigned char reserved1; + unsigned char type; + unsigned char reserved2[2]; + unsigned char reply_code; + unsigned char reserved3[3]; +}; + +#define TYPE82_RSP_CODE 0x82 + +#define REPLY_ERROR_MACHINE_FAILURE 0x10 +#define REPLY_ERROR_PREEMPT_FAILURE 0x12 +#define REPLY_ERROR_CHECKPT_FAILURE 0x14 +#define REPLY_ERROR_MESSAGE_TYPE 0x20 +#define REPLY_ERROR_INVALID_COMM_CD 0x21 +#define REPLY_ERROR_INVALID_MSG_LEN 0x23 +#define REPLY_ERROR_RESERVD_FIELD 0x24 +#define REPLY_ERROR_FORMAT_FIELD 0x29 +#define REPLY_ERROR_INVALID_COMMAND 0x30 +#define REPLY_ERROR_MALFORMED_MSG 0x40 +#define REPLY_ERROR_RESERVED_FIELDO 0x50 +#define REPLY_ERROR_WORD_ALIGNMENT 0x60 +#define REPLY_ERROR_MESSAGE_LENGTH 0x80 +#define REPLY_ERROR_OPERAND_INVALID 0x82 +#define REPLY_ERROR_OPERAND_SIZE 0x84 +#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85 +#define REPLY_ERROR_RESERVED_FIELD 0x88 +#define REPLY_ERROR_TRANSPORT_FAIL 0x90 +#define REPLY_ERROR_PACKET_TRUNCATED 0xA0 +#define REPLY_ERROR_ZERO_BUFFER_LEN 0xB0 + +struct type86_hdr { + unsigned char reserved1; + unsigned char type; + unsigned char format; + unsigned char reserved2; + unsigned char reply_code; + unsigned char reserved3[3]; +}; + +#define TYPE86_RSP_CODE 0x86 +#define TYPE86_FMT2 0x02 + +struct type86_fmt2_msg { + struct type86_hdr hdr; + unsigned char reserved[4]; + unsigned char apfs[4]; + unsigned int count1; + unsigned int offset1; + unsigned int count2; + unsigned int offset2; + unsigned int count3; + unsigned int offset3; + unsigned int count4; + unsigned int offset4; +}; + +static struct type6_hdr static_type6_hdr = { + 0x00, + 0x06, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + 0x00000058, + 0x00000000, + 0x00000000, + 0x00000000, + {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50, + 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01}, + {0x00,0x00}, + {0x00,0x00}, + {0x50,0x44}, + {0x00,0x00}, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static struct type6_hdr static_type6_hdrX = { + 0x00, + 0x06, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + 0x00000058, + 0x00000000, + 0x00000000, + 0x00000000, + {0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x50,0x44}, + {0x00,0x00}, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static struct CPRB static_cprb = { + {0x70,0x00}, + 0x41, + 0x00, + {0x00,0x00,0x00,0x00}, + 0x00, + 0x00, + {0x54,0x32}, + 0x01, + 0x00, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00}, + {0x08,0x00}, + {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20} +}; + +struct function_and_rules_block { + unsigned char function_code[2]; + unsigned char ulen[2]; + unsigned char only_rule[8]; +}; + +static struct function_and_rules_block static_pkd_function_and_rules = { + {0x50,0x44}, + {0x0A,0x00}, + {'P','K','C','S','-','1','.','2'} +}; + +static struct function_and_rules_block static_pke_function_and_rules = { + {0x50,0x4B}, + {0x0A,0x00}, + {'P','K','C','S','-','1','.','2'} +}; + +struct T6_keyBlock_hdr { + unsigned char blen[2]; + unsigned char ulen[2]; + unsigned char flags[2]; +}; + +static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = { + {0x89,0x01}, + {0x87,0x01}, + {0x00} +}; + +static struct CPRBX static_cprbx = { + 0x00DC, + 0x02, + {0x00,0x00,0x00}, + {0x54,0x32}, + {0x00,0x00,0x00,0x00}, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + {0x00,0x00,0x00,0x00}, + 0x00000000, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + 0x0000, + 0x0000, + 0x00000000, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + 0x00, + 0x00, + 0x0000, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = { + {0x50,0x44}, + {0x00,0x0A}, + {'P','K','C','S','-','1','.','2'} +}; + +static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = { + {0x50,0x4B}, + {0x00,0x0A}, + {'Z','E','R','O','-','P','A','D'} +}; + +static struct function_and_rules_block static_pkd_function_and_rulesX = { + {0x50,0x44}, + {0x00,0x0A}, + {'Z','E','R','O','-','P','A','D'} +}; + +static struct function_and_rules_block static_pke_function_and_rulesX = { + {0x50,0x4B}, + {0x00,0x0A}, + {'M','R','P',' ',' ',' ',' ',' '} +}; + +struct T6_keyBlock_hdrX { + unsigned short blen; + unsigned short ulen; + unsigned char flags[2]; +}; + +static unsigned char static_pad[256] = { +0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57, +0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39, +0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D, +0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F, +0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45, +0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F, +0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D, +0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9, +0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B, +0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD, +0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1, +0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23, +0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43, +0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F, +0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD, +0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09 +}; + +static struct cca_private_ext_ME static_pvt_me_key = { + { + 0x1E, + 0x00, + 0x0183, + {0x00,0x00,0x00,0x00} + }, + + { + 0x02, + 0x00, + 0x016C, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + 0x00, + 0x00, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x80,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} + }, + + { + 0x04, + 0x00, + 0x000F, + {0x00,0x00}, + 0x0003, + 0x0000, + 0x0000, + {0x01,0x00,0x01} + } +}; + +static struct cca_public_key static_public_key = { + { + 0x1E, + 0x00, + 0x0000, + {0x00,0x00,0x00,0x00} + }, + + { + 0x04, + 0x00, + 0x0000, + {0x00,0x00}, + 0x0000, + 0x0000, + 0x0000, + {0x01,0x00,0x01} + } +}; + +#define FIXED_TYPE6_ME_LEN 0x0000025F + +#define FIXED_TYPE6_ME_EN_LEN 0x000000F0 + +#define FIXED_TYPE6_ME_LENX 0x000002CB + +#define FIXED_TYPE6_ME_EN_LENX 0x0000015C + +static struct cca_public_sec static_cca_pub_sec = { + 0x04, + 0x00, + 0x000f, + {0x00,0x00}, + 0x0003, + 0x0000, + 0x0000, + {0x01,0x00,0x01} +}; + +#define FIXED_TYPE6_CR_LEN 0x00000177 + +#define FIXED_TYPE6_CR_LENX 0x000001E3 + +#define MAX_RESPONSE_SIZE 0x00000710 + +#define MAX_RESPONSEX_SIZE 0x0000077C + +#define RESPONSE_CPRB_SIZE 0x000006B8 +#define RESPONSE_CPRBX_SIZE 0x00000724 + +#define CALLER_HEADER 12 + +static unsigned char static_PKE_function_code[2] = {0x50, 0x4B}; + +static inline int +testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat) +{ + int ccode; + + asm volatile +#ifdef __s390x__ + (" llgfr 0,%4 \n" + " slgr 1,1 \n" + " lgr 2,1 \n" + "0: .long 0xb2af0000 \n" + "1: ipm %0 \n" + " srl %0,28 \n" + " iihh %0,0 \n" + " iihl %0,0 \n" + " lgr %1,1 \n" + " lgr %3,2 \n" + " srl %3,24 \n" + " sll 2,24 \n" + " srl 2,24 \n" + " lgr %2,2 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h5 \n" + " jg 2b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 8 \n" + " .quad 0b,3b \n" + " .quad 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type) + :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION) + :"cc","0","1","2","memory"); +#else + (" lr 0,%4 \n" + " slr 1,1 \n" + " lr 2,1 \n" + "0: .long 0xb2af0000 \n" + "1: ipm %0 \n" + " srl %0,28 \n" + " lr %1,1 \n" + " lr %3,2 \n" + " srl %3,24 \n" + " sll 2,24 \n" + " srl 2,24 \n" + " lr %2,2 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h5 \n" + " bras 1,4f \n" + " .long 2b \n" + "4: \n" + " l 1,0(1) \n" + " br 1 \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 4 \n" + " .long 0b,3b \n" + " .long 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type) + :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION) + :"cc","0","1","2","memory"); +#endif + return ccode; +} + +static inline int +resetq(int q_nr, struct ap_status_word *stat_p) +{ + int ccode; + + asm volatile +#ifdef __s390x__ + (" llgfr 0,%2 \n" + " lghi 1,1 \n" + " sll 1,24 \n" + " or 0,1 \n" + " slgr 1,1 \n" + " lgr 2,1 \n" + "0: .long 0xb2af0000 \n" + "1: ipm %0 \n" + " srl %0,28 \n" + " iihh %0,0 \n" + " iihl %0,0 \n" + " lgr %1,1 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h3 \n" + " jg 2b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 8 \n" + " .quad 0b,3b \n" + " .quad 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat_p) + :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION) + :"cc","0","1","2","memory"); +#else + (" lr 0,%2 \n" + " lhi 1,1 \n" + " sll 1,24 \n" + " or 0,1 \n" + " slr 1,1 \n" + " lr 2,1 \n" + "0: .long 0xb2af0000 \n" + "1: ipm %0 \n" + " srl %0,28 \n" + " lr %1,1 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h3 \n" + " bras 1,4f \n" + " .long 2b \n" + "4: \n" + " l 1,0(1) \n" + " br 1 \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 4 \n" + " .long 0b,3b \n" + " .long 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat_p) + :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION) + :"cc","0","1","2","memory"); +#endif + return ccode; +} + +static inline int +sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat) +{ + int ccode; + + asm volatile +#ifdef __s390x__ + (" lgr 6,%3 \n" + " llgfr 7,%2 \n" + " llgt 0,0(6) \n" + " lghi 1,64 \n" + " sll 1,24 \n" + " or 0,1 \n" + " la 6,4(6) \n" + " llgt 2,0(6) \n" + " llgt 3,4(6) \n" + " la 6,8(6) \n" + " slr 1,1 \n" + "0: .long 0xb2ad0026 \n" + "1: brc 2,0b \n" + " ipm %0 \n" + " srl %0,28 \n" + " iihh %0,0 \n" + " iihl %0,0 \n" + " lgr %1,1 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h4 \n" + " jg 2b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 8 \n" + " .quad 0b,3b \n" + " .quad 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat) + :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION) + :"cc","0","1","2","3","6","7","memory"); +#else + (" lr 6,%3 \n" + " lr 7,%2 \n" + " l 0,0(6) \n" + " lhi 1,64 \n" + " sll 1,24 \n" + " or 0,1 \n" + " la 6,4(6) \n" + " l 2,0(6) \n" + " l 3,4(6) \n" + " la 6,8(6) \n" + " slr 1,1 \n" + "0: .long 0xb2ad0026 \n" + "1: brc 2,0b \n" + " ipm %0 \n" + " srl %0,28 \n" + " lr %1,1 \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h4 \n" + " bras 1,4f \n" + " .long 2b \n" + "4: \n" + " l 1,0(1) \n" + " br 1 \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 4 \n" + " .long 0b,3b \n" + " .long 1b,3b \n" + ".previous" + :"=d" (ccode),"=d" (*stat) + :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION) + :"cc","0","1","2","3","6","7","memory"); +#endif + return ccode; +} + +static inline int +rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id, + struct ap_status_word *st) +{ + int ccode; + + asm volatile +#ifdef __s390x__ + (" llgfr 0,%2 \n" + " lgr 3,%4 \n" + " lgr 6,%3 \n" + " llgfr 7,%5 \n" + " lghi 1,128 \n" + " sll 1,24 \n" + " or 0,1 \n" + " slgr 1,1 \n" + " lgr 2,1 \n" + " lgr 4,1 \n" + " lgr 5,1 \n" + "0: .long 0xb2ae0046 \n" + "1: brc 2,0b \n" + " brc 4,0b \n" + " ipm %0 \n" + " srl %0,28 \n" + " iihh %0,0 \n" + " iihl %0,0 \n" + " lgr %1,1 \n" + " st 4,0(3) \n" + " st 5,4(3) \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h6 \n" + " jg 2b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 8 \n" + " .quad 0b,3b \n" + " .quad 1b,3b \n" + ".previous" + :"=d"(ccode),"=d"(*st) + :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION) + :"cc","0","1","2","3","4","5","6","7","memory"); +#else + (" lr 0,%2 \n" + " lr 3,%4 \n" + " lr 6,%3 \n" + " lr 7,%5 \n" + " lhi 1,128 \n" + " sll 1,24 \n" + " or 0,1 \n" + " slr 1,1 \n" + " lr 2,1 \n" + " lr 4,1 \n" + " lr 5,1 \n" + "0: .long 0xb2ae0046 \n" + "1: brc 2,0b \n" + " brc 4,0b \n" + " ipm %0 \n" + " srl %0,28 \n" + " lr %1,1 \n" + " st 4,0(3) \n" + " st 5,4(3) \n" + "2: \n" + ".section .fixup,\"ax\" \n" + "3: \n" + " lhi %0,%h6 \n" + " bras 1,4f \n" + " .long 2b \n" + "4: \n" + " l 1,0(1) \n" + " br 1 \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .align 4 \n" + " .long 0b,3b \n" + " .long 1b,3b \n" + ".previous" + :"=d"(ccode),"=d"(*st) + :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION) + :"cc","0","1","2","3","4","5","6","7","memory"); +#endif + return ccode; +} + +static inline void +itoLe2(int *i_p, unsigned char *lechars) +{ + *lechars = *((unsigned char *) i_p + sizeof(int) - 1); + *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2); +} + +static inline void +le2toI(unsigned char *lechars, int *i_p) +{ + unsigned char *ic_p; + *i_p = 0; + ic_p = (unsigned char *) i_p; + *(ic_p + 2) = *(lechars + 1); + *(ic_p + 3) = *(lechars); +} + +static inline int +is_empty(unsigned char *ptr, int len) +{ + return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len); +} + +enum hdstat +query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type) +{ + int q_nr, i, t_depth, t_dev_type; + enum devstat ccode; + struct ap_status_word stat_word; + enum hdstat stat; + int break_out; + + q_nr = (deviceNr << SKIP_BITL) + cdx; + stat = HD_BUSY; + ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word); + PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code); + break_out = 0; + for (i = 0; i < resetNr; i++) { + if (ccode > 3) { + PRINTKC("Exception testing device %d\n", i); + return HD_TSQ_EXCEPTION; + } + switch (ccode) { + case 0: + PDEBUG("t_dev_type %d\n", t_dev_type); + break_out = 1; + stat = HD_ONLINE; + *q_depth = t_depth + 1; + switch (t_dev_type) { + case OTHER_HW: + stat = HD_NOT_THERE; + *dev_type = NILDEV; + break; + case PCICA_HW: + *dev_type = PCICA; + break; + case PCICC_HW: + *dev_type = PCICC; + break; + case PCIXCC_HW: + *dev_type = PCIXCC_UNK; + break; + case CEX2C_HW: + *dev_type = CEX2C; + break; + default: + *dev_type = NILDEV; + break; + } + PDEBUG("available device %d: Q depth = %d, dev " + "type = %d, stat = %02X%02X%02X%02X\n", + deviceNr, *q_depth, *dev_type, + stat_word.q_stat_flags, + stat_word.response_code, + stat_word.reserved[0], + stat_word.reserved[1]); + break; + case 3: + switch (stat_word.response_code) { + case AP_RESPONSE_NORMAL: + stat = HD_ONLINE; + break_out = 1; + *q_depth = t_depth + 1; + *dev_type = t_dev_type; + PDEBUG("cc3, available device " + "%d: Q depth = %d, dev " + "type = %d, stat = " + "%02X%02X%02X%02X\n", + deviceNr, *q_depth, + *dev_type, + stat_word.q_stat_flags, + stat_word.response_code, + stat_word.reserved[0], + stat_word.reserved[1]); + break; + case AP_RESPONSE_Q_NOT_AVAIL: + stat = HD_NOT_THERE; + break_out = 1; + break; + case AP_RESPONSE_RESET_IN_PROGRESS: + PDEBUG("device %d in reset\n", + deviceNr); + break; + case AP_RESPONSE_DECONFIGURED: + stat = HD_DECONFIGURED; + break_out = 1; + break; + case AP_RESPONSE_CHECKSTOPPED: + stat = HD_CHECKSTOPPED; + break_out = 1; + break; + case AP_RESPONSE_BUSY: + PDEBUG("device %d busy\n", + deviceNr); + break; + default: + break; + } + break; + default: + stat = HD_NOT_THERE; + break_out = 1; + break; + } + if (break_out) + break; + + udelay(5); + + ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word); + } + return stat; +} + +enum devstat +reset_device(int deviceNr, int cdx, int resetNr) +{ + int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i; + struct ap_status_word stat_word; + enum devstat stat; + int break_out; + + q_nr = (deviceNr << SKIP_BITL) + cdx; + stat = DEV_GONE; + ccode = resetq(q_nr, &stat_word); + if (ccode > 3) + return DEV_RSQ_EXCEPTION; + + break_out = 0; + for (i = 0; i < resetNr; i++) { + switch (ccode) { + case 0: + stat = DEV_ONLINE; + if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) + break_out = 1; + break; + case 3: + switch (stat_word.response_code) { + case AP_RESPONSE_NORMAL: + stat = DEV_ONLINE; + if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) + break_out = 1; + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + stat = DEV_GONE; + break_out = 1; + break; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + default: + break; + } + break; + default: + stat = DEV_GONE; + break_out = 1; + break; + } + if (break_out == 1) + break; + udelay(5); + + ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word); + if (ccode > 3) { + stat = DEV_TSQ_EXCEPTION; + break; + } + } + PDEBUG("Number of testq's needed for reset: %d\n", i); + + if (i >= resetNr) { + stat = DEV_GONE; + } + + return stat; +} + +#ifdef DEBUG_HYDRA_MSGS +static inline void +print_buffer(unsigned char *buffer, int bufflen) +{ + int i; + for (i = 0; i < bufflen; i += 16) { + PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X " + "%02X%02X%02X%02X %02X%02X%02X%02X\n", i, + buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3], + buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], + buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11], + buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]); + } +} +#endif + +enum devstat +send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext) +{ + struct ap_status_word stat_word; + enum devstat stat; + int ccode; + + ((struct request_msg_ext *) msg_ext)->q_nr = + (dev_nr << SKIP_BITL) + cdx; + PDEBUG("msg_len passed to sen: %d\n", msg_len); + PDEBUG("q number passed to sen: %02x%02x%02x%02x\n", + msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]); + stat = DEV_GONE; + +#ifdef DEBUG_HYDRA_MSGS + PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X " + "%02X%02X%02X%02X\n", + msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3], + msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7], + msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]); + print_buffer(msg_ext+CALLER_HEADER, msg_len); +#endif + + ccode = sen(msg_len, msg_ext, &stat_word); + if (ccode > 3) + return DEV_SEN_EXCEPTION; + + PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n", + ccode, stat_word.q_stat_flags, stat_word.response_code, + stat_word.reserved[0], stat_word.reserved[1]); + switch (ccode) { + case 0: + stat = DEV_ONLINE; + break; + case 1: + stat = DEV_GONE; + break; + case 3: + switch (stat_word.response_code) { + case AP_RESPONSE_NORMAL: + stat = DEV_ONLINE; + break; + case AP_RESPONSE_Q_FULL: + stat = DEV_QUEUE_FULL; + break; + default: + stat = DEV_GONE; + break; + } + break; + default: + stat = DEV_GONE; + break; + } + + return stat; +} + +enum devstat +receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp, + unsigned char *psmid) +{ + int ccode; + struct ap_status_word stat_word; + enum devstat stat; + + memset(resp, 0x00, 8); + + ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid, + &stat_word); + if (ccode > 3) + return DEV_REC_EXCEPTION; + + PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n", + ccode, stat_word.q_stat_flags, stat_word.response_code, + stat_word.reserved[0], stat_word.reserved[1]); + + stat = DEV_GONE; + switch (ccode) { + case 0: + stat = DEV_ONLINE; +#ifdef DEBUG_HYDRA_MSGS + print_buffer(resp, resplen); +#endif + break; + case 3: + switch (stat_word.response_code) { + case AP_RESPONSE_NORMAL: + stat = DEV_ONLINE; + break; + case AP_RESPONSE_NO_PENDING_REPLY: + if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) + stat = DEV_EMPTY; + else + stat = DEV_NO_WORK; + break; + case AP_RESPONSE_INDEX_TOO_BIG: + case AP_RESPONSE_NO_FIRST_PART: + case AP_RESPONSE_MESSAGE_TOO_BIG: + stat = DEV_BAD_MESSAGE; + break; + default: + break; + } + break; + default: + break; + } + + return stat; +} + +static inline int +pad_msg(unsigned char *buffer, int totalLength, int msgLength) +{ + int pad_len; + + for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++) + if (buffer[pad_len] != 0x00) + break; + pad_len -= 3; + if (pad_len < 8) + return SEN_PAD_ERROR; + + buffer[0] = 0x00; + buffer[1] = 0x02; + + memcpy(buffer+2, static_pad, pad_len); + + buffer[pad_len + 2] = 0x00; + + return 0; +} + +static inline int +is_common_public_key(unsigned char *key, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (key[i]) + break; + key += i; + len -= i; + if (((len == 1) && (key[0] == 3)) || + ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1))) + return 1; + + return 0; +} + +static int +ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p, + union type4_msg *z90cMsg_p) +{ + int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len; + unsigned char *mod_tgt, *exp_tgt, *inp_tgt; + union type4_msg *tmp_type4_msg; + + mod_len = icaMex_p->inputdatalength; + + msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) + + CALLER_HEADER; + + memset(z90cMsg_p, 0, msg_size); + + tmp_type4_msg = (union type4_msg *) + ((unsigned char *) z90cMsg_p + CALLER_HEADER); + + tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE; + tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE; + + if (mod_len <= 128) { + tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT; + tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN; + mod_tgt = tmp_type4_msg->sme.modulus; + mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus); + exp_tgt = tmp_type4_msg->sme.exponent; + exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent); + inp_tgt = tmp_type4_msg->sme.message; + inp_tgt_len = sizeof(tmp_type4_msg->sme.message); + } else { + tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT; + tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN; + mod_tgt = tmp_type4_msg->lme.modulus; + mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus); + exp_tgt = tmp_type4_msg->lme.exponent; + exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent); + inp_tgt = tmp_type4_msg->lme.message; + inp_tgt_len = sizeof(tmp_type4_msg->lme.message); + } + + mod_tgt += (mod_tgt_len - mod_len); + if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len)) + return SEN_RELEASED; + if (is_empty(mod_tgt, mod_len)) + return SEN_USER_ERROR; + exp_tgt += (exp_tgt_len - mod_len); + if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len)) + return SEN_RELEASED; + if (is_empty(exp_tgt, mod_len)) + return SEN_USER_ERROR; + inp_tgt += (inp_tgt_len - mod_len); + if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len)) + return SEN_RELEASED; + if (is_empty(inp_tgt, mod_len)) + return SEN_USER_ERROR; + + *z90cMsg_l_p = msg_size - CALLER_HEADER; + + return 0; +} + +static int +ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, + int *z90cMsg_l_p, union type4_msg *z90cMsg_p) +{ + int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len, + dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len; + unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt; + union type4_msg *tmp_type4_msg; + + mod_len = icaMsg_p->inputdatalength; + short_len = mod_len / 2; + long_len = mod_len / 2 + 8; + + tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) + + CALLER_HEADER; + + memset(z90cMsg_p, 0, tmp_size); + + tmp_type4_msg = (union type4_msg *) + ((unsigned char *) z90cMsg_p + CALLER_HEADER); + + tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE; + tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE; + if (mod_len <= 128) { + tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT; + tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN; + p_tgt = tmp_type4_msg->scr.p; + p_tgt_len = sizeof(tmp_type4_msg->scr.p); + q_tgt = tmp_type4_msg->scr.q; + q_tgt_len = sizeof(tmp_type4_msg->scr.q); + dp_tgt = tmp_type4_msg->scr.dp; + dp_tgt_len = sizeof(tmp_type4_msg->scr.dp); + dq_tgt = tmp_type4_msg->scr.dq; + dq_tgt_len = sizeof(tmp_type4_msg->scr.dq); + u_tgt = tmp_type4_msg->scr.u; + u_tgt_len = sizeof(tmp_type4_msg->scr.u); + inp_tgt = tmp_type4_msg->scr.message; + inp_tgt_len = sizeof(tmp_type4_msg->scr.message); + } else { + tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT; + tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN; + p_tgt = tmp_type4_msg->lcr.p; + p_tgt_len = sizeof(tmp_type4_msg->lcr.p); + q_tgt = tmp_type4_msg->lcr.q; + q_tgt_len = sizeof(tmp_type4_msg->lcr.q); + dp_tgt = tmp_type4_msg->lcr.dp; + dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp); + dq_tgt = tmp_type4_msg->lcr.dq; + dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq); + u_tgt = tmp_type4_msg->lcr.u; + u_tgt_len = sizeof(tmp_type4_msg->lcr.u); + inp_tgt = tmp_type4_msg->lcr.message; + inp_tgt_len = sizeof(tmp_type4_msg->lcr.message); + } + + p_tgt += (p_tgt_len - long_len); + if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len)) + return SEN_RELEASED; + if (is_empty(p_tgt, long_len)) + return SEN_USER_ERROR; + q_tgt += (q_tgt_len - short_len); + if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len)) + return SEN_RELEASED; + if (is_empty(q_tgt, short_len)) + return SEN_USER_ERROR; + dp_tgt += (dp_tgt_len - long_len); + if (copy_from_user(dp_tgt, icaMsg_p->bp_key, long_len)) + return SEN_RELEASED; + if (is_empty(dp_tgt, long_len)) + return SEN_USER_ERROR; + dq_tgt += (dq_tgt_len - short_len); + if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len)) + return SEN_RELEASED; + if (is_empty(dq_tgt, short_len)) + return SEN_USER_ERROR; + u_tgt += (u_tgt_len - long_len); + if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv, long_len)) + return SEN_RELEASED; + if (is_empty(u_tgt, long_len)) + return SEN_USER_ERROR; + inp_tgt += (inp_tgt_len - mod_len); + if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len)) + return SEN_RELEASED; + if (is_empty(inp_tgt, mod_len)) + return SEN_USER_ERROR; + + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +static int +ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx, + int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) +{ + int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l; + unsigned char *temp; + struct type6_hdr *tp6Hdr_p; + struct CPRB *cprb_p; + struct cca_private_ext_ME *key_p; + static int deprecated_msg_count = 0; + + mod_len = icaMsg_p->inputdatalength; + tmp_size = FIXED_TYPE6_ME_LEN + mod_len; + total_CPRB_len = tmp_size - sizeof(struct type6_hdr); + parmBlock_l = total_CPRB_len - sizeof(struct CPRB); + tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; + + memset(z90cMsg_p, 0, tmp_size); + + temp = (unsigned char *)z90cMsg_p + CALLER_HEADER; + memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr)); + tp6Hdr_p = (struct type6_hdr *)temp; + tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); + tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; + + temp += sizeof(struct type6_hdr); + memcpy(temp, &static_cprb, sizeof(struct CPRB)); + cprb_p = (struct CPRB *) temp; + cprb_p->usage_domain[0]= (unsigned char)cdx; + itoLe2(&parmBlock_l, cprb_p->req_parml); + itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml); + + temp += sizeof(struct CPRB); + memcpy(temp, &static_pkd_function_and_rules, + sizeof(struct function_and_rules_block)); + + temp += sizeof(struct function_and_rules_block); + vud_len = 2 + icaMsg_p->inputdatalength; + itoLe2(&vud_len, temp); + + temp += 2; + if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) + return SEN_RELEASED; + if (is_empty(temp, mod_len)) + return SEN_USER_ERROR; + + temp += mod_len; + memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr)); + + temp += sizeof(struct T6_keyBlock_hdr); + memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME)); + key_p = (struct cca_private_ext_ME *)temp; + temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent) + - mod_len; + if (copy_from_user(temp, icaMsg_p->b_key, mod_len)) + return SEN_RELEASED; + if (is_empty(temp, mod_len)) + return SEN_USER_ERROR; + + if (is_common_public_key(temp, mod_len)) { + if (deprecated_msg_count < 20) { + PRINTK("Common public key used for modex decrypt\n"); + deprecated_msg_count++; + if (deprecated_msg_count == 20) + PRINTK("No longer issuing messages about common" + " public key for modex decrypt.\n"); + } + return SEN_NOT_AVAIL; + } + + temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus) + - mod_len; + if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len)) + return SEN_RELEASED; + if (is_empty(temp, mod_len)) + return SEN_USER_ERROR; + + key_p->pubMESec.modulus_bit_len = 8 * mod_len; + + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +static int +ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx, + int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) +{ + int mod_len, vud_len, exp_len, key_len; + int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i; + unsigned char *temp_exp, *exp_p, *temp; + struct type6_hdr *tp6Hdr_p; + struct CPRB *cprb_p; + struct cca_public_key *key_p; + struct T6_keyBlock_hdr *keyb_p; + + temp_exp = kmalloc(256, GFP_KERNEL); + if (!temp_exp) + return EGETBUFF; + mod_len = icaMsg_p->inputdatalength; + if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) { + kfree(temp_exp); + return SEN_RELEASED; + } + if (is_empty(temp_exp, mod_len)) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + + exp_p = temp_exp; + for (i = 0; i < mod_len; i++) + if (exp_p[i]) + break; + if (i >= mod_len) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + + exp_len = mod_len - i; + exp_p += i; + + PDEBUG("exp_len after computation: %08x\n", exp_len); + tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len; + total_CPRB_len = tmp_size - sizeof(struct type6_hdr); + parmBlock_l = total_CPRB_len - sizeof(struct CPRB); + tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; + + vud_len = 2 + mod_len; + memset(z90cMsg_p, 0, tmp_size); + + temp = (unsigned char *)z90cMsg_p + CALLER_HEADER; + memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr)); + tp6Hdr_p = (struct type6_hdr *)temp; + tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); + tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; + memcpy(tp6Hdr_p->function_code, static_PKE_function_code, + sizeof(static_PKE_function_code)); + temp += sizeof(struct type6_hdr); + memcpy(temp, &static_cprb, sizeof(struct CPRB)); + cprb_p = (struct CPRB *) temp; + cprb_p->usage_domain[0]= (unsigned char)cdx; + itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml); + temp += sizeof(struct CPRB); + memcpy(temp, &static_pke_function_and_rules, + sizeof(struct function_and_rules_block)); + temp += sizeof(struct function_and_rules_block); + temp += 2; + if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) { + kfree(temp_exp); + return SEN_RELEASED; + } + if (is_empty(temp, mod_len)) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + if ((temp[0] != 0x00) || (temp[1] != 0x02)) { + kfree(temp_exp); + return SEN_NOT_AVAIL; + } + for (i = 2; i < mod_len; i++) + if (temp[i] == 0x00) + break; + if ((i < 9) || (i > (mod_len - 2))) { + kfree(temp_exp); + return SEN_NOT_AVAIL; + } + pad_len = i + 1; + vud_len = mod_len - pad_len; + memmove(temp, temp+pad_len, vud_len); + temp -= 2; + vud_len += 2; + itoLe2(&vud_len, temp); + temp += (vud_len); + keyb_p = (struct T6_keyBlock_hdr *)temp; + temp += sizeof(struct T6_keyBlock_hdr); + memcpy(temp, &static_public_key, sizeof(static_public_key)); + key_p = (struct cca_public_key *)temp; + temp = key_p->pubSec.exponent; + memcpy(temp, exp_p, exp_len); + kfree(temp_exp); + temp += exp_len; + if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len)) + return SEN_RELEASED; + if (is_empty(temp, mod_len)) + return SEN_USER_ERROR; + key_p->pubSec.modulus_bit_len = 8 * mod_len; + key_p->pubSec.modulus_byte_len = mod_len; + key_p->pubSec.exponent_len = exp_len; + key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len; + key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr); + key_p->pubHdr.token_length = key_len; + key_len += 4; + itoLe2(&key_len, keyb_p->ulen); + key_len += 2; + itoLe2(&key_len, keyb_p->blen); + parmBlock_l -= pad_len; + itoLe2(&parmBlock_l, cprb_p->req_parml); + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +static int +ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx, + int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) +{ + int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len; + int long_len, pad_len, keyPartsLen, tmp_l; + unsigned char *tgt_p, *temp; + struct type6_hdr *tp6Hdr_p; + struct CPRB *cprb_p; + struct cca_token_hdr *keyHdr_p; + struct cca_pvt_ext_CRT_sec *pvtSec_p; + struct cca_public_sec *pubSec_p; + + mod_len = icaMsg_p->inputdatalength; + short_len = mod_len / 2; + long_len = 8 + short_len; + keyPartsLen = 3 * long_len + 2 * short_len; + pad_len = (8 - (keyPartsLen % 8)) % 8; + keyPartsLen += pad_len + mod_len; + tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len; + total_CPRB_len = tmp_size - sizeof(struct type6_hdr); + parmBlock_l = total_CPRB_len - sizeof(struct CPRB); + vud_len = 2 + mod_len; + tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; + + memset(z90cMsg_p, 0, tmp_size); + tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; + memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr)); + tp6Hdr_p = (struct type6_hdr *)tgt_p; + tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); + tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; + tgt_p += sizeof(struct type6_hdr); + cprb_p = (struct CPRB *) tgt_p; + memcpy(tgt_p, &static_cprb, sizeof(struct CPRB)); + cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3); + itoLe2(&parmBlock_l, cprb_p->req_parml); + memcpy(cprb_p->rpl_parml, cprb_p->req_parml, + sizeof(cprb_p->req_parml)); + tgt_p += sizeof(struct CPRB); + memcpy(tgt_p, &static_pkd_function_and_rules, + sizeof(struct function_and_rules_block)); + tgt_p += sizeof(struct function_and_rules_block); + itoLe2(&vud_len, tgt_p); + tgt_p += 2; + if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, mod_len)) + return SEN_USER_ERROR; + tgt_p += mod_len; + tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) + + sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen; + itoLe2(&tmp_l, tgt_p); + temp = tgt_p + 2; + tmp_l -= 2; + itoLe2(&tmp_l, temp); + tgt_p += sizeof(struct T6_keyBlock_hdr); + keyHdr_p = (struct cca_token_hdr *)tgt_p; + keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT; + tmp_l -= 4; + keyHdr_p->token_length = tmp_l; + tgt_p += sizeof(struct cca_token_hdr); + pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p; + pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT; + pvtSec_p->section_length = + sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen; + pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL; + pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL; + pvtSec_p->p_len = long_len; + pvtSec_p->q_len = short_len; + pvtSec_p->dp_len = long_len; + pvtSec_p->dq_len = short_len; + pvtSec_p->u_len = long_len; + pvtSec_p->mod_len = mod_len; + pvtSec_p->pad_len = pad_len; + tgt_p += sizeof(struct cca_pvt_ext_CRT_sec); + if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, short_len)) + return SEN_USER_ERROR; + tgt_p += short_len; + if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, short_len)) + return SEN_USER_ERROR; + tgt_p += short_len; + if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + tgt_p += pad_len; + memset(tgt_p, 0xFF, mod_len); + tgt_p += mod_len; + memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec)); + pubSec_p = (struct cca_public_sec *) tgt_p; + pubSec_p->modulus_bit_len = 8 * mod_len; + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +static int +ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx, + int *z90cMsg_l_p, struct type6_msg *z90cMsg_p, + int dev_type) +{ + int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l; + int key_len, i; + unsigned char *temp_exp, *tgt_p, *temp, *exp_p; + struct type6_hdr *tp6Hdr_p; + struct CPRBX *cprbx_p; + struct cca_public_key *key_p; + struct T6_keyBlock_hdrX *keyb_p; + + temp_exp = kmalloc(256, GFP_KERNEL); + if (!temp_exp) + return EGETBUFF; + mod_len = icaMsg_p->inputdatalength; + if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) { + kfree(temp_exp); + return SEN_RELEASED; + } + if (is_empty(temp_exp, mod_len)) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + exp_p = temp_exp; + for (i = 0; i < mod_len; i++) + if (exp_p[i]) + break; + if (i >= mod_len) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + exp_len = mod_len - i; + exp_p += i; + PDEBUG("exp_len after computation: %08x\n", exp_len); + tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len; + total_CPRB_len = tmp_size - sizeof(struct type6_hdr); + parmBlock_l = total_CPRB_len - sizeof(struct CPRBX); + tmp_size = tmp_size + CALLER_HEADER; + vud_len = 2 + mod_len; + memset(z90cMsg_p, 0, tmp_size); + tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; + memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr)); + tp6Hdr_p = (struct type6_hdr *)tgt_p; + tp6Hdr_p->ToCardLen1 = total_CPRB_len; + tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE; + memcpy(tp6Hdr_p->function_code, static_PKE_function_code, + sizeof(static_PKE_function_code)); + tgt_p += sizeof(struct type6_hdr); + memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX)); + cprbx_p = (struct CPRBX *) tgt_p; + cprbx_p->domain = (unsigned short)cdx; + cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE; + tgt_p += sizeof(struct CPRBX); + if (dev_type == PCIXCC_MCL2) + memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2, + sizeof(struct function_and_rules_block)); + else + memcpy(tgt_p, &static_pke_function_and_rulesX, + sizeof(struct function_and_rules_block)); + tgt_p += sizeof(struct function_and_rules_block); + + tgt_p += 2; + if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) { + kfree(temp_exp); + return SEN_RELEASED; + } + if (is_empty(tgt_p, mod_len)) { + kfree(temp_exp); + return SEN_USER_ERROR; + } + tgt_p -= 2; + *((short *)tgt_p) = (short) vud_len; + tgt_p += vud_len; + keyb_p = (struct T6_keyBlock_hdrX *)tgt_p; + tgt_p += sizeof(struct T6_keyBlock_hdrX); + memcpy(tgt_p, &static_public_key, sizeof(static_public_key)); + key_p = (struct cca_public_key *)tgt_p; + temp = key_p->pubSec.exponent; + memcpy(temp, exp_p, exp_len); + kfree(temp_exp); + temp += exp_len; + if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len)) + return SEN_RELEASED; + if (is_empty(temp, mod_len)) + return SEN_USER_ERROR; + key_p->pubSec.modulus_bit_len = 8 * mod_len; + key_p->pubSec.modulus_byte_len = mod_len; + key_p->pubSec.exponent_len = exp_len; + key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len; + key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr); + key_p->pubHdr.token_length = key_len; + key_len += 4; + keyb_p->ulen = (unsigned short)key_len; + key_len += 2; + keyb_p->blen = (unsigned short)key_len; + cprbx_p->req_parml = parmBlock_l; + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +static int +ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx, + int *z90cMsg_l_p, struct type6_msg *z90cMsg_p, + int dev_type) +{ + int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len; + int long_len, pad_len, keyPartsLen, tmp_l; + unsigned char *tgt_p, *temp; + struct type6_hdr *tp6Hdr_p; + struct CPRBX *cprbx_p; + struct cca_token_hdr *keyHdr_p; + struct cca_pvt_ext_CRT_sec *pvtSec_p; + struct cca_public_sec *pubSec_p; + + mod_len = icaMsg_p->inputdatalength; + short_len = mod_len / 2; + long_len = 8 + short_len; + keyPartsLen = 3 * long_len + 2 * short_len; + pad_len = (8 - (keyPartsLen % 8)) % 8; + keyPartsLen += pad_len + mod_len; + tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len; + total_CPRB_len = tmp_size - sizeof(struct type6_hdr); + parmBlock_l = total_CPRB_len - sizeof(struct CPRBX); + vud_len = 2 + mod_len; + tmp_size = tmp_size + CALLER_HEADER; + memset(z90cMsg_p, 0, tmp_size); + tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; + memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr)); + tp6Hdr_p = (struct type6_hdr *)tgt_p; + tp6Hdr_p->ToCardLen1 = total_CPRB_len; + tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE; + tgt_p += sizeof(struct type6_hdr); + cprbx_p = (struct CPRBX *) tgt_p; + memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX)); + cprbx_p->domain = (unsigned short)cdx; + cprbx_p->req_parml = parmBlock_l; + cprbx_p->rpl_msgbl = parmBlock_l; + tgt_p += sizeof(struct CPRBX); + if (dev_type == PCIXCC_MCL2) + memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2, + sizeof(struct function_and_rules_block)); + else + memcpy(tgt_p, &static_pkd_function_and_rulesX, + sizeof(struct function_and_rules_block)); + tgt_p += sizeof(struct function_and_rules_block); + *((short *)tgt_p) = (short) vud_len; + tgt_p += 2; + if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, mod_len)) + return SEN_USER_ERROR; + tgt_p += mod_len; + tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) + + sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen; + *((short *)tgt_p) = (short) tmp_l; + temp = tgt_p + 2; + tmp_l -= 2; + *((short *)temp) = (short) tmp_l; + tgt_p += sizeof(struct T6_keyBlock_hdr); + keyHdr_p = (struct cca_token_hdr *)tgt_p; + keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT; + tmp_l -= 4; + keyHdr_p->token_length = tmp_l; + tgt_p += sizeof(struct cca_token_hdr); + pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p; + pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT; + pvtSec_p->section_length = + sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen; + pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL; + pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL; + pvtSec_p->p_len = long_len; + pvtSec_p->q_len = short_len; + pvtSec_p->dp_len = long_len; + pvtSec_p->dq_len = short_len; + pvtSec_p->u_len = long_len; + pvtSec_p->mod_len = mod_len; + pvtSec_p->pad_len = pad_len; + tgt_p += sizeof(struct cca_pvt_ext_CRT_sec); + if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, short_len)) + return SEN_USER_ERROR; + tgt_p += short_len; + if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, short_len)) + return SEN_USER_ERROR; + tgt_p += short_len; + if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len)) + return SEN_RELEASED; + if (is_empty(tgt_p, long_len)) + return SEN_USER_ERROR; + tgt_p += long_len; + tgt_p += pad_len; + memset(tgt_p, 0xFF, mod_len); + tgt_p += mod_len; + memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec)); + pubSec_p = (struct cca_public_sec *) tgt_p; + pubSec_p->modulus_bit_len = 8 * mod_len; + *z90cMsg_l_p = tmp_size - CALLER_HEADER; + + return 0; +} + +int +convert_request(unsigned char *buffer, int func, unsigned short function, + int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p) +{ + if (dev_type == PCICA) { + if (func == ICARSACRT) + return ICACRT_msg_to_type4CRT_msg( + (struct ica_rsa_modexpo_crt *) buffer, + msg_l_p, (union type4_msg *) msg_p); + else + return ICAMEX_msg_to_type4MEX_msg( + (struct ica_rsa_modexpo *) buffer, + msg_l_p, (union type4_msg *) msg_p); + } + if (dev_type == PCICC) { + if (func == ICARSACRT) + return ICACRT_msg_to_type6CRT_msg( + (struct ica_rsa_modexpo_crt *) buffer, + cdx, msg_l_p, (struct type6_msg *)msg_p); + if (function == PCI_FUNC_KEY_ENCRYPT) + return ICAMEX_msg_to_type6MEX_en_msg( + (struct ica_rsa_modexpo *) buffer, + cdx, msg_l_p, (struct type6_msg *) msg_p); + else + return ICAMEX_msg_to_type6MEX_de_msg( + (struct ica_rsa_modexpo *) buffer, + cdx, msg_l_p, (struct type6_msg *) msg_p); + } + if ((dev_type == PCIXCC_MCL2) || + (dev_type == PCIXCC_MCL3) || + (dev_type == CEX2C)) { + if (func == ICARSACRT) + return ICACRT_msg_to_type6CRT_msgX( + (struct ica_rsa_modexpo_crt *) buffer, + cdx, msg_l_p, (struct type6_msg *) msg_p, + dev_type); + else + return ICAMEX_msg_to_type6MEX_msgX( + (struct ica_rsa_modexpo *) buffer, + cdx, msg_l_p, (struct type6_msg *) msg_p, + dev_type); + } + + return 0; +} + +int ext_bitlens_msg_count = 0; +static inline void +unset_ext_bitlens(void) +{ + if (!ext_bitlens_msg_count) { + PRINTK("Unable to use coprocessors for extended bitlengths. " + "Using PCICAs (if present) for extended bitlengths. " + "This is not an error.\n"); + ext_bitlens_msg_count++; + } + ext_bitlens = 0; +} + +int +convert_response(unsigned char *response, unsigned char *buffer, + int *respbufflen_p, unsigned char *resp_buff) +{ + struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer; + struct type82_hdr *t82h_p = (struct type82_hdr *) response; + struct type84_hdr *t84h_p = (struct type84_hdr *) response; + struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response; + int reply_code, service_rc, service_rs, src_l; + unsigned char *src_p, *tgt_p; + struct CPRB *cprb_p; + struct CPRBX *cprbx_p; + + src_p = 0; + reply_code = 0; + service_rc = 0; + service_rs = 0; + src_l = 0; + switch (t82h_p->type) { + case TYPE82_RSP_CODE: + reply_code = t82h_p->reply_code; + src_p = (unsigned char *)t82h_p; + PRINTK("Hardware error: Type 82 Message Header: " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + src_p[0], src_p[1], src_p[2], src_p[3], + src_p[4], src_p[5], src_p[6], src_p[7]); + break; + case TYPE84_RSP_CODE: + src_l = icaMsg_p->outputdatalength; + src_p = response + (int)t84h_p->len - src_l; + break; + case TYPE86_RSP_CODE: + reply_code = t86m_p->hdr.reply_code; + if (reply_code != 0) + break; + cprb_p = (struct CPRB *) + (response + sizeof(struct type86_fmt2_msg)); + cprbx_p = (struct CPRBX *) cprb_p; + if (cprb_p->cprb_ver_id != 0x02) { + le2toI(cprb_p->ccp_rtcode, &service_rc); + if (service_rc != 0) { + le2toI(cprb_p->ccp_rscode, &service_rs); + if ((service_rc == 8) && (service_rs == 66)) + PDEBUG("Bad block format on PCICC\n"); + else if ((service_rc == 8) && (service_rs == 770)) { + PDEBUG("Invalid key length on PCICC\n"); + unset_ext_bitlens(); + return REC_USE_PCICA; + } + else if ((service_rc == 8) && (service_rs == 783)) { + PDEBUG("Extended bitlengths not enabled" + "on PCICC\n"); + unset_ext_bitlens(); + return REC_USE_PCICA; + } + else + PRINTK("service rc/rs: %d/%d\n", + service_rc, service_rs); + return REC_OPERAND_INV; + } + src_p = (unsigned char *)cprb_p + sizeof(struct CPRB); + src_p += 4; + le2toI(src_p, &src_l); + src_l -= 2; + src_p += 2; + } else { + service_rc = (int)cprbx_p->ccp_rtcode; + if (service_rc != 0) { + service_rs = (int) cprbx_p->ccp_rscode; + if ((service_rc == 8) && (service_rs == 66)) + PDEBUG("Bad block format on PCXICC\n"); + else if ((service_rc == 8) && (service_rs == 770)) { + PDEBUG("Invalid key length on PCIXCC\n"); + unset_ext_bitlens(); + return REC_USE_PCICA; + } + else if ((service_rc == 8) && (service_rs == 783)) { + PDEBUG("Extended bitlengths not enabled" + "on PCIXCC\n"); + unset_ext_bitlens(); + return REC_USE_PCICA; + } + else + PRINTK("service rc/rs: %d/%d\n", + service_rc, service_rs); + return REC_OPERAND_INV; + } + src_p = (unsigned char *) + cprbx_p + sizeof(struct CPRBX); + src_p += 4; + src_l = (int)(*((short *) src_p)); + src_l -= 2; + src_p += 2; + } + break; + default: + return REC_BAD_MESSAGE; + } + + if (reply_code) + switch (reply_code) { + case REPLY_ERROR_OPERAND_INVALID: + return REC_OPERAND_INV; + case REPLY_ERROR_OPERAND_SIZE: + return REC_OPERAND_SIZE; + case REPLY_ERROR_EVEN_MOD_IN_OPND: + return REC_EVEN_MOD; + case REPLY_ERROR_MESSAGE_TYPE: + return WRONG_DEVICE_TYPE; + case REPLY_ERROR_TRANSPORT_FAIL: + PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n", + t86m_p->apfs[0], t86m_p->apfs[1], + t86m_p->apfs[2], t86m_p->apfs[3]); + return REC_HARDWAR_ERR; + default: + PRINTKW("reply code = %d\n", reply_code); + return REC_HARDWAR_ERR; + } + + if (service_rc != 0) + return REC_OPERAND_INV; + + if ((src_l > icaMsg_p->outputdatalength) || + (src_l > RESPBUFFSIZE) || + (src_l <= 0)) + return REC_OPERAND_SIZE; + + PDEBUG("Length returned = %d\n", src_l); + tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l; + memcpy(tgt_p, src_p, src_l); + if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) { + memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l); + if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l)) + return REC_INVALID_PAD; + } + *respbufflen_p = icaMsg_p->outputdatalength; + if (*respbufflen_p == 0) + PRINTK("Zero *respbufflen_p\n"); + + return 0; +} + |