/*
- * linux/drivers/s390/crypto/z90hardware.c
+ * linux/drivers/s390/misc/z90hardware.c
*
- * z90crypt 1.3.2
+ * z90crypt 1.3.1
*
* Copyright (C) 2001, 2004 IBM Corporation
* Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
+ * Eric Rossman (edrossma@us.ibm.com)
*
* Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
*
*
* 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
+ * 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
#include "z90crypt.h"
#include "z90common.h"
-#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.19 $"
-char z90hardware_version[] __initdata =
+char z90chardware_version[] __initdata =
"z90hardware.o (" VERSION_Z90HARDWARE_C "/"
VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
unsigned char right[4];
unsigned char reserved3[2];
unsigned char reserved4[2];
- unsigned char apfs[4];
+ unsigned char pfs[4];
unsigned int offset1;
unsigned int offset2;
unsigned int offset3;
unsigned char svr_name[8];
};
+struct CPRBX {
+ unsigned short cprb_len;
+ unsigned char cprb_ver_id;
+ unsigned char pad_000[3];
+ unsigned char func_id[2];
+ unsigned char cprb_flags[4];
+ unsigned int req_parml;
+ unsigned int req_datal;
+ unsigned int rpl_msgbl;
+ unsigned int rpld_parml;
+ unsigned int rpl_datal;
+ unsigned int rpld_datal;
+ unsigned int req_extbl;
+ unsigned char pad_001[4];
+ unsigned int rpld_extbl;
+ unsigned char req_parmb[16];
+ unsigned char req_datab[16];
+ unsigned char rpl_parmb[16];
+ unsigned char rpl_datab[16];
+ unsigned char req_extb[16];
+ unsigned char rpl_extb[16];
+ unsigned short ccp_rtcode;
+ unsigned short ccp_rscode;
+ unsigned int mac_data_len;
+ unsigned char logon_id[8];
+ unsigned char mac_value[8];
+ unsigned char mac_content_flgs;
+ unsigned char pad_002;
+ unsigned short domain;
+ unsigned char pad_003[12];
+ unsigned char pad_004[36];
+};
+
struct type6_msg {
struct type6_hdr header;
struct CPRB CPRB;
#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_RESERVED_FIELD 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
unsigned int offset2;
unsigned int count3;
unsigned int offset3;
- unsigned int count4;
+ unsigned int ount4;
unsigned int offset4;
};
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'}
+ {'P','K','C','S','-','1','.','2'}
};
static struct function_and_rules_block static_pke_function_and_rulesX = {
{0x50,0x4B},
{0x00,0x0A},
- {'M','R','P',' ',' ',' ',' ',' '}
+ {'Z','E','R','O','-','P','A','D'}
};
struct T6_keyBlock_hdrX {
#define FIXED_TYPE6_CR_LENX 0x000001E3
+#ifndef MAX_RESPONSE_SIZE
#define MAX_RESPONSE_SIZE 0x00000710
#define MAX_RESPONSEX_SIZE 0x0000077C
+#endif
#define RESPONSE_CPRB_SIZE 0x000006B8
#define RESPONSE_CPRBX_SIZE 0x00000724
*q_depth = t_depth + 1;
switch (t_dev_type) {
case OTHER_HW:
+ case OTHER2_HW:
stat = HD_NOT_THERE;
*dev_type = NILDEV;
break;
*dev_type = PCICC;
break;
case PCIXCC_HW:
- *dev_type = PCIXCC_UNK;
- break;
- case CEX2C_HW:
- *dev_type = CEX2C;
+ *dev_type = PCIXCC;
break;
default:
*dev_type = NILDEV;
default:
stat = HD_NOT_THERE;
break_out = 1;
- break;
}
if (break_out)
break;
switch (stat_word.response_code) {
case AP_RESPONSE_NORMAL:
stat = DEV_ONLINE;
- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+ if (stat_word.q_stat_flags &
+ AP_Q_STATUS_EMPTY)
break_out = 1;
break;
case AP_RESPONSE_Q_NOT_AVAIL:
+ stat = DEV_GONE;
+ break_out = 1;
+ break;
case AP_RESPONSE_DECONFIGURED:
+ stat = DEV_GONE;
+ break_out = 1;
+ break;
case AP_RESPONSE_CHECKSTOPPED:
stat = DEV_GONE;
break_out = 1;
default:
stat = DEV_GONE;
break_out = 1;
- break;
}
if (break_out == 1)
break;
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);
+ print_buffer(msg_ext+12, msg_len);
#endif
ccode = sen(msg_len, msg_ext, &stat_word);
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)
+receive_from_AP(int dev_nr, int cdx, int resplen,
+ unsigned char *resp, unsigned char *psmid)
{
int ccode;
struct ap_status_word stat_word;
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;
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");
- }
+ PRINTK("Common public key used 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))
+ if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len) != 0)
return SEN_RELEASED;
if (is_empty(temp, mod_len))
return SEN_USER_ERROR;
{
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;
+ unsigned char temp_exp[256], *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);
+ if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
return SEN_RELEASED;
- }
- if (is_empty(temp_exp, mod_len)) {
- kfree(temp_exp);
+ if (is_empty(temp_exp, mod_len))
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);
+ if (i >= mod_len)
return SEN_USER_ERROR;
- }
exp_len = mod_len - i;
exp_p += i;
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);
+ if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
return SEN_RELEASED;
- }
- if (is_empty(temp, mod_len)) {
- kfree(temp_exp);
+ if (is_empty(temp, mod_len))
return SEN_USER_ERROR;
- }
- if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
- kfree(temp_exp);
+ if (temp[0] != 0x00 || temp[1] != 0x02)
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);
+ if ((i < 9) || (i > (mod_len - 2)))
return SEN_NOT_AVAIL;
- }
pad_len = i + 1;
vud_len = mod_len - pad_len;
memmove(temp, temp+pad_len, vud_len);
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;
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_p->pubSec.section_length = 12 + 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;
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 *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
{
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;
+ unsigned char temp_exp[256], *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);
+ if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
return SEN_RELEASED;
- }
- if (is_empty(temp_exp, mod_len)) {
- kfree(temp_exp);
+ if (is_empty(temp_exp, mod_len))
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);
+ if (i >= mod_len)
return SEN_USER_ERROR;
- }
exp_len = mod_len - i;
exp_p += i;
PDEBUG("exp_len after computation: %08x\n", exp_len);
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));
+ 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;
- }
+ 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 -= 2;
*((short *)tgt_p) = (short) vud_len;
tgt_p += vud_len;
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;
+ return SEN_RELEASED;
if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
+ 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_p->pubSec.section_length = 12 + 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;
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 *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;
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));
+ 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;
(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 (dev_type == PCIXCC) {
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);
+ cdx, msg_l_p, (struct type6_msg *) msg_p);
else
return ICAMEX_msg_to_type6MEX_msgX(
(struct ica_rsa_modexpo *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p,
- dev_type);
+ cdx, msg_l_p, (struct type6_msg *) msg_p);
}
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;
+ struct type86_hdr *t86h_p = (struct type86_hdr *) response;
+ int rv, reply_code, service_rc, service_rs, src_l;
unsigned char *src_p, *tgt_p;
struct CPRB *cprb_p;
struct CPRBX *cprbx_p;
service_rc = 0;
service_rs = 0;
src_l = 0;
+ rv = 0;
switch (t82h_p->type) {
case TYPE82_RSP_CODE:
reply_code = t82h_p->reply_code;
+ rv = 4;
src_p = (unsigned char *)t82h_p;
PRINTK("Hardware error: Type 82 Message Header: "
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
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)
+ reply_code = t86h_p->reply_code;
+ if (t86h_p->format != TYPE86_FMT2) {
+ rv = 4;
+ break;
+ }
+ if (reply_code != 0) {
+ rv = 4;
break;
+ }
cprb_p = (struct CPRB *)
(response + sizeof(struct type86_fmt2_msg));
cprbx_p = (struct CPRBX *) cprb_p;
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;
- }
+ PDEBUG("8/66 on PCICC\n");
else
PRINTK("service rc/rs: %d/%d\n",
service_rc, service_rs);
- return REC_OPERAND_INV;
+ rv = 8;
}
src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
src_p += 4;
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;
- }
+ PDEBUG("8/66 on PCIXCC\n");
else
PRINTK("service rc/rs: %d/%d\n",
service_rc, service_rs);
- return REC_OPERAND_INV;
+ rv = 8;
}
src_p = (unsigned char *)
cprbx_p + sizeof(struct CPRBX);
}
break;
default:
- return REC_BAD_MESSAGE;
+ break;
}
- if (reply_code)
+ if (rv == 8)
+ return 8;
+ if (rv == 4)
switch (reply_code) {
case REPLY_ERROR_OPERAND_INVALID:
return REC_OPERAND_INV;
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;
+ return 12;
}
if (service_rc != 0)
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;
+ rv = pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l);
+ if (rv != 0)
+ return rv;
}
*respbufflen_p = icaMsg_p->outputdatalength;
if (*respbufflen_p == 0)
PRINTK("Zero *respbufflen_p\n");
- return 0;
+ return rv;
}