Commit 58ebaaf0 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: crypto device driver part 1

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The crypto device driver for PCICA & PCICC cards, part 1.
parent 57f8dc81
......@@ -195,6 +195,11 @@ CONFIG_S390_TAPE_BLOCK=y
#
CONFIG_S390_TAPE_34XX=m
#
# Cryptographic devices
#
CONFIG_Z90CRYPT=m
#
# Networking support
#
......
......@@ -164,3 +164,16 @@ config S390_TAPE_34XX
It is safe to say "Y" here.
endmenu
menu "Cryptographic devices"
config Z90CRYPT
tristate "Support for PCI-attached cryptographic adapters"
default "m"
help
Select this option if you want to use a PCI-attached cryptographic
adapter like the PCI Cryptographic Accelerator (PCICA) or the PCI
Cryptographic Coprocessor (PCICC). This option is also available
as a module called z90crypt.ko.
endmenu
......@@ -3,6 +3,7 @@
#
obj-y += s390mach.o sysinfo.o
obj-y += cio/ block/ char/ net/ scsi/
obj-y += cio/ block/ char/ crypto/ net/ scsi/
drivers-y += drivers/s390/built-in.o
#
# S/390 miscellaneous devices
#
z90crypt-objs := z90main.o z90hardware.o
obj-$(CONFIG_Z90CRYPT) += z90crypt.o
/*
* linux/drivers/s390/misc/z90common.h
*
* z90crypt 1.3.1
*
* 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.
*/
#ifndef _Z90COMMON_
#define _Z90COMMON_
#define VERSION_Z90COMMON_H "$Revision: 1.8 $"
#define RESPBUFFSIZE 256
#define PCI_FUNC_KEY_DECRYPT 0x5044
#define PCI_FUNC_KEY_ENCRYPT 0x504B
enum devstat {
DEV_GONE,
DEV_ONLINE,
DEV_QUEUE_FULL,
DEV_EMPTY,
DEV_NO_WORK,
DEV_BAD_MESSAGE,
DEV_TSQ_EXCEPTION,
DEV_RSQ_EXCEPTION,
DEV_SEN_EXCEPTION,
DEV_REC_EXCEPTION
};
enum hdstat {
HD_NOT_THERE,
HD_BUSY,
HD_DECONFIGURED,
HD_CHECKSTOPPED,
HD_ONLINE,
HD_TSQ_EXCEPTION
};
#define Z90C_AMBIGUOUS_DOMAIN 2
#define Z90C_INCORRECT_DOMAIN 3
#define ENOTINIT 4
#define SEN_BUSY 7
#define SEN_USER_ERROR 8
#define SEN_QUEUE_FULL 11
#define SEN_NOT_AVAIL 16
#define SEN_PAD_ERROR 17
#define SEN_RETRY 18
#define SEN_RELEASED 24
#define REC_EMPTY 4
#define REC_BUSY 6
#define REC_OPERAND_INV 8
#define REC_OPERAND_SIZE 9
#define REC_EVEN_MOD 10
#define REC_NO_WORK 11
#define REC_HARDWAR_ERR 12
#define REC_NO_RESPONSE 13
#define REC_RETRY_DEV 14
#define REC_USER_GONE 15
#define REC_BAD_MESSAGE 16
#define REC_INVALID_PAD 17
#define REC_RELEASED 28
#define WRONG_DEVICE_TYPE 20
#define REC_FATAL_ERROR 32
#define SEN_FATAL_ERROR 33
#define TSQ_FATAL_ERROR 34
#define RSQ_FATAL_ERROR 35
#define PCICA 0
#define PCICC 1
#define PCIXCC 2
#define NILDEV -1
#define ANYDEV -1
enum hdevice_type {
PCICC_HW = 3,
PCICA_HW = 4,
PCIXCC_HW = 5,
OTHER_HW = 6,
OTHER2_HW = 7
};
#ifndef DEV_NAME
#define DEV_NAME "z90crypt"
#endif
#define PRINTK(fmt, args...) \
printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
#define PRINTKN(fmt, args...) \
printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
#define PRINTKW(fmt, args...) \
printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
#define PRINTKC(fmt, args...) \
printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
#ifdef Z90CRYPT_DEBUG
#define PDEBUG(fmt, args...) \
printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
#else
#define PDEBUG(fmt, args...) do {} while (0)
#endif
#define UMIN(a,b) ((a) < (b) ? (a) : (b))
#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
#endif
/*
* linux/drivers/s390/misc/z90crypt.h
*
* z90crypt 1.3.1
*
* 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.
*/
#ifndef _LINUX_Z90CRYPT_H_
#define _LINUX_Z90CRYPT_H_
#include <linux/ioctl.h>
#define VERSION_Z90CRYPT_H "$Revision: 1.2 $"
#define z90crypt_VERSION 1
#define z90crypt_RELEASE 3 // 2 = PCIXCC, 3 = rewrite for coding standards
#define z90crypt_VARIANT 1
/**
* struct ica_rsa_modexpo
*
* Requirements:
* - outputdatalength is at least as large as inputdatalength.
* - All key parts are right justified in their fields, padded on
* the left with zeroes.
* - length(b_key) = inputdatalength
* - length(n_modulus) = inputdatalength
*/
struct ica_rsa_modexpo {
char * inputdata;
unsigned int inputdatalength;
char * outputdata;
unsigned int outputdatalength;
char * b_key;
char * n_modulus;
};
/**
* struct ica_rsa_modexpo_crt
*
* Requirements:
* - inputdatalength is even.
* - outputdatalength is at least as large as inputdatalength.
* - All key parts are right justified in their fields, padded on
* the left with zeroes.
* - length(bp_key) = inputdatalength/2 + 8
* - length(bq_key) = inputdatalength/2
* - length(np_key) = inputdatalength/2 + 8
* - length(nq_key) = inputdatalength/2
* - length(u_mult_inv) = inputdatalength/2 + 8
*/
struct ica_rsa_modexpo_crt {
char * inputdata;
unsigned int inputdatalength;
char * outputdata;
unsigned int outputdatalength;
char * bp_key;
char * bq_key;
char * np_prime;
char * nq_prime;
char * u_mult_inv;
};
#define Z90_IOCTL_MAGIC 'z' // NOTE: Need to allocate from linux folks
/**
* Interface notes:
*
* The ioctl()s which are implemented (along with relevant details)
* are:
*
* ICARSAMODEXPO
* Perform an RSA operation using a Modulus-Exponent pair
* This takes an ica_rsa_modexpo struct as its arg.
*
* NOTE: please refer to the comments preceding this structure
* for the implementation details for the contents of the
* block
*
* ICARSACRT
* Perform an RSA operation using a Chinese-Remainder Theorem key
* This takes an ica_rsa_modexpo_crt struct as its arg.
*
* NOTE: please refer to the comments preceding this structure
* for the implementation details for the contents of the
* block
*
* Z90STAT_TOTALCOUNT
* Return an integer count of all device types together.
*
* Z90STAT_PCICACOUNT
* Return an integer count of all PCICAs.
*
* Z90STAT_PCICCCOUNT
* Return an integer count of all PCICCs.
*
* Z90STAT_PCIXCCCOUNT
* Return an integer count of all PCIXCCs.
*
* Z90STAT_REQUESTQ_COUNT
* Return an integer count of the number of entries waiting to be
* sent to a device.
*
* Z90STAT_PENDINGQ_COUNT
* Return an integer count of the number of entries sent to a
* device awaiting the reply.
*
* Z90STAT_TOTALOPEN_COUNT
* Return an integer count of the number of open file handles.
*
* Z90STAT_DOMAIN_INDEX
* Return the integer value of the Cryptographic Domain.
*
* Z90STAT_STATUS_MASK
* Return an 64 element array of unsigned chars for the status of
* all devices.
* 0x01: PCICA
* 0x02: PCICC
* 0x03: PCIXCC
* 0x0d: device is disabled via the proc filesystem
*
* Z90STAT_QDEPTH_MASK
* Return an 64 element array of unsigned chars for the queue
* depth of all devices.
*
* Z90STAT_PERDEV_REQCNT
* Return an 64 element array of unsigned integers for the number
* of successfully completed requests per device since the device
* was detected and made available.
*
* ICAZ90STATUS (deprecated)
* Return some device driver status in a ica_z90_status struct
* This takes an ica_z90_status struct as its arg.
*
* NOTE: this ioctl() is deprecated, and has been replaced with
* single ioctl()s for each type of status being requested
*
* Z90QUIESCE (not recommended)
* Quiesce the driver. This is intended to stop all new
* requests from being processed. Its use is not recommended,
* except in circumstances where there is no other way to stop
* callers from accessing the driver. Its original use was to
* allow the driver to be "drained" of work in preparation for
* a system shutdown.
*
* NOTE: once issued, this ban on new work cannot be undone
* except by unloading and reloading the driver.
*/
/**
* Supported ioctl calls
*/
#define ICARSAMODEXPO _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x05, 0)
#define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x06, 0)
/* DEPRECATED status call (bound for removal SOON) */
#define ICAZ90STATUS _IOR(Z90_IOCTL_MAGIC, 0x10, struct ica_z90_status)
/* unrelated to ICA callers */
#define Z90QUIESCE _IO(Z90_IOCTL_MAGIC, 0x11)
/* New status calls */
#define Z90STAT_TOTALCOUNT _IOR(Z90_IOCTL_MAGIC, 0x40, int)
#define Z90STAT_PCICACOUNT _IOR(Z90_IOCTL_MAGIC, 0x41, int)
#define Z90STAT_PCICCCOUNT _IOR(Z90_IOCTL_MAGIC, 0x42, int)
#define Z90STAT_PCIXCCCOUNT _IOR(Z90_IOCTL_MAGIC, 0x43, int)
#define Z90STAT_REQUESTQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x44, int)
#define Z90STAT_PENDINGQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x45, int)
#define Z90STAT_TOTALOPEN_COUNT _IOR(Z90_IOCTL_MAGIC, 0x46, int)
#define Z90STAT_DOMAIN_INDEX _IOR(Z90_IOCTL_MAGIC, 0x47, int)
#define Z90STAT_STATUS_MASK _IOR(Z90_IOCTL_MAGIC, 0x48, char[64])
#define Z90STAT_QDEPTH_MASK _IOR(Z90_IOCTL_MAGIC, 0x49, char[64])
#define Z90STAT_PERDEV_REQCNT _IOR(Z90_IOCTL_MAGIC, 0x4a, int[64])
/**
* local errno definitions
*/
#define ENOBUFF 129 // filp->private_data->...>work_elem_p->buffer is NULL
#define EWORKPEND 130 // user issues ioctl while another pending
#define ERELEASED 131 // user released while ioctl pending
#define EQUIESCE 132 // z90crypt quiescing (no more work allowed)
#define ETIMEOUT 133 // request timed out
#define EUNKNOWN 134 // some unrecognized error occured
#define EGETBUFF 135 // Error getting buffer
/**
* DEPRECATED STRUCTURES
*/
/**
* This structure is DEPRECATED and the corresponding ioctl() has been
* replaced with individual ioctl()s for each piece of data!
* This structure will NOT survive past version 1.3.1, so switch to the
* new ioctl()s.
*/
#define MASK_LENGTH 64 // mask length
struct ica_z90_status {
int totalcount;
int leedslitecount; // PCICA
int leeds2count; // PCICC
// int PCIXCCCount; is not in struct for backward compatibility
int requestqWaitCount;
int pendingqWaitCount;
int totalOpenCount;
int cryptoDomain;
// status: 0=not there. 1=PCICA. 2=PCICC. 3=PCIXCC
unsigned char status[MASK_LENGTH];
// qdepth: # work elements waiting for each device
unsigned char qdepth[MASK_LENGTH];
};
#endif /* _LINUX_Z90CRYPT_H_ */
/*
* linux/drivers/s390/misc/z90hardware.c
*
* z90crypt 1.3.1
*
* 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.19 $"
char z90chardware_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 pfs[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 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;
};
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_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_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 ount4;
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 = {
{0x50,0x44},
{0x00,0x0A},
{'P','K','C','S','-','1','.','2'}
};
static struct function_and_rules_block static_pke_function_and_rulesX = {
{0x50,0x4B},
{0x00,0x0A},
{'Z','E','R','O','-','P','A','D'}
};
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
#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
#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:
case OTHER2_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;
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;
}
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:
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;
break;
case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY:
default:
break;
}
break;
default:
stat = DEV_GONE;
break_out = 1;
}
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+12, 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;
}
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;
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)) {
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) != 0)
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[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;
mod_len = icaMsg_p->inputdatalength;
if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
return SEN_RELEASED;
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)
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))
return SEN_RELEASED;
if (is_empty(temp, mod_len))
return SEN_USER_ERROR;
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)))
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);
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 = 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;
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 mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
int key_len, i;
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;
mod_len = icaMsg_p->inputdatalength;
if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
return SEN_RELEASED;
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)
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);
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))
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;
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);
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 = 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;
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 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);
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) {
if (func == ICARSACRT)
return ICACRT_msg_to_type6CRT_msgX(
(struct ica_rsa_modexpo_crt *) buffer,
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);
}
return 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_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;
src_p = 0;
reply_code = 0;
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[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 = 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 (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("8/66 on PCICC\n");
else
PRINTK("service rc/rs: %d/%d\n",
service_rc, service_rs);
rv = 8;
}
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("8/66 on PCIXCC\n");
else
PRINTK("service rc/rs: %d/%d\n",
service_rc, service_rs);
rv = 8;
}
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:
break;
}
if (rv == 8)
return 8;
if (rv == 4)
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;
default:
return 12;
}
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);
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 rv;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment