linux/drivers/s390/crypto/zcrypt_pcica.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/s390/crypto/zcrypt_pcica.c
   3 *
   4 *  zcrypt 2.1.0
   5 *
   6 *  Copyright (C)  2001, 2006 IBM Corporation
   7 *  Author(s): Robert Burroughs
   8 *             Eric Rossman (edrossma@us.ibm.com)
   9 *
  10 *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
  11 *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
  12 *                                Ralph Wuerthner <rwuerthn@de.ibm.com>
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by
  16 * the Free Software Foundation; either version 2, or (at your option)
  17 * any later version.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22 * GNU General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, write to the Free Software
  26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27 */
  28
  29#include <linux/module.h>
  30#include <linux/init.h>
  31#include <linux/err.h>
  32#include <asm/atomic.h>
  33#include <asm/uaccess.h>
  34
  35#include "ap_bus.h"
  36#include "zcrypt_api.h"
  37#include "zcrypt_error.h"
  38#include "zcrypt_pcica.h"
  39
  40#define PCICA_MIN_MOD_SIZE        1     /*    8 bits    */
  41#define PCICA_MAX_MOD_SIZE      256     /* 2048 bits    */
  42
  43#define PCICA_SPEED_RATING      2800
  44
  45#define PCICA_MAX_MESSAGE_SIZE  0x3a0   /* sizeof(struct type4_lcr)          */
  46#define PCICA_MAX_RESPONSE_SIZE 0x110   /* max outputdatalength + type80_hdr */
  47
  48#define PCICA_CLEANUP_TIME      (15*HZ)
  49
  50static struct ap_device_id zcrypt_pcica_ids[] = {
  51        { AP_DEVICE(AP_DEVICE_TYPE_PCICA) },
  52        { /* end of list */ },
  53};
  54
  55#ifndef CONFIG_ZCRYPT_MONOLITHIC
  56MODULE_DEVICE_TABLE(ap, zcrypt_pcica_ids);
  57MODULE_AUTHOR("IBM Corporation");
  58MODULE_DESCRIPTION("PCICA Cryptographic Coprocessor device driver, "
  59                   "Copyright 2001, 2006 IBM Corporation");
  60MODULE_LICENSE("GPL");
  61#endif
  62
  63static int zcrypt_pcica_probe(struct ap_device *ap_dev);
  64static void zcrypt_pcica_remove(struct ap_device *ap_dev);
  65static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *,
  66                                 struct ap_message *);
  67
  68static struct ap_driver zcrypt_pcica_driver = {
  69        .probe = zcrypt_pcica_probe,
  70        .remove = zcrypt_pcica_remove,
  71        .receive = zcrypt_pcica_receive,
  72        .ids = zcrypt_pcica_ids,
  73        .request_timeout = PCICA_CLEANUP_TIME,
  74};
  75
  76/**
  77 * Convert a ICAMEX message to a type4 MEX message.
  78 *
  79 * @zdev: crypto device pointer
  80 * @zreq: crypto request pointer
  81 * @mex: pointer to user input data
  82 *
  83 * Returns 0 on success or -EFAULT.
  84 */
  85static int ICAMEX_msg_to_type4MEX_msg(struct zcrypt_device *zdev,
  86                                      struct ap_message *ap_msg,
  87                                      struct ica_rsa_modexpo *mex)
  88{
  89        unsigned char *modulus, *exponent, *message;
  90        int mod_len;
  91
  92        mod_len = mex->inputdatalength;
  93
  94        if (mod_len <= 128) {
  95                struct type4_sme *sme = ap_msg->message;
  96                memset(sme, 0, sizeof(*sme));
  97                ap_msg->length = sizeof(*sme);
  98                sme->header.msg_fmt = TYPE4_SME_FMT;
  99                sme->header.msg_len = sizeof(*sme);
 100                sme->header.msg_type_code = TYPE4_TYPE_CODE;
 101                sme->header.request_code = TYPE4_REQU_CODE;
 102                modulus = sme->modulus + sizeof(sme->modulus) - mod_len;
 103                exponent = sme->exponent + sizeof(sme->exponent) - mod_len;
 104                message = sme->message + sizeof(sme->message) - mod_len;
 105        } else {
 106                struct type4_lme *lme = ap_msg->message;
 107                memset(lme, 0, sizeof(*lme));
 108                ap_msg->length = sizeof(*lme);
 109                lme->header.msg_fmt = TYPE4_LME_FMT;
 110                lme->header.msg_len = sizeof(*lme);
 111                lme->header.msg_type_code = TYPE4_TYPE_CODE;
 112                lme->header.request_code = TYPE4_REQU_CODE;
 113                modulus = lme->modulus + sizeof(lme->modulus) - mod_len;
 114                exponent = lme->exponent + sizeof(lme->exponent) - mod_len;
 115                message = lme->message + sizeof(lme->message) - mod_len;
 116        }
 117
 118        if (copy_from_user(modulus, mex->n_modulus, mod_len) ||
 119            copy_from_user(exponent, mex->b_key, mod_len) ||
 120            copy_from_user(message, mex->inputdata, mod_len))
 121                return -EFAULT;
 122        return 0;
 123}
 124
 125/**
 126 * Convert a ICACRT message to a type4 CRT message.
 127 *
 128 * @zdev: crypto device pointer
 129 * @zreq: crypto request pointer
 130 * @crt: pointer to user input data
 131 *
 132 * Returns 0 on success or -EFAULT.
 133 */
 134static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
 135                                      struct ap_message *ap_msg,
 136                                      struct ica_rsa_modexpo_crt *crt)
 137{
 138        unsigned char *p, *q, *dp, *dq, *u, *inp;
 139        int mod_len, short_len, long_len;
 140
 141        mod_len = crt->inputdatalength;
 142        short_len = mod_len / 2;
 143        long_len = mod_len / 2 + 8;
 144
 145        if (mod_len <= 128) {
 146                struct type4_scr *scr = ap_msg->message;
 147                memset(scr, 0, sizeof(*scr));
 148                ap_msg->length = sizeof(*scr);
 149                scr->header.msg_type_code = TYPE4_TYPE_CODE;
 150                scr->header.request_code = TYPE4_REQU_CODE;
 151                scr->header.msg_fmt = TYPE4_SCR_FMT;
 152                scr->header.msg_len = sizeof(*scr);
 153                p = scr->p + sizeof(scr->p) - long_len;
 154                q = scr->q + sizeof(scr->q) - short_len;
 155                dp = scr->dp + sizeof(scr->dp) - long_len;
 156                dq = scr->dq + sizeof(scr->dq) - short_len;
 157                u = scr->u + sizeof(scr->u) - long_len;
 158                inp = scr->message + sizeof(scr->message) - mod_len;
 159        } else {
 160                struct type4_lcr *lcr = ap_msg->message;
 161                memset(lcr, 0, sizeof(*lcr));
 162                ap_msg->length = sizeof(*lcr);
 163                lcr->header.msg_type_code = TYPE4_TYPE_CODE;
 164                lcr->header.request_code = TYPE4_REQU_CODE;
 165                lcr->header.msg_fmt = TYPE4_LCR_FMT;
 166                lcr->header.msg_len = sizeof(*lcr);
 167                p = lcr->p + sizeof(lcr->p) - long_len;
 168                q = lcr->q + sizeof(lcr->q) - short_len;
 169                dp = lcr->dp + sizeof(lcr->dp) - long_len;
 170                dq = lcr->dq + sizeof(lcr->dq) - short_len;
 171                u = lcr->u + sizeof(lcr->u) - long_len;
 172                inp = lcr->message + sizeof(lcr->message) - mod_len;
 173        }
 174
 175        if (copy_from_user(p, crt->np_prime, long_len) ||
 176            copy_from_user(q, crt->nq_prime, short_len) ||
 177            copy_from_user(dp, crt->bp_key, long_len) ||
 178            copy_from_user(dq, crt->bq_key, short_len) ||
 179            copy_from_user(u, crt->u_mult_inv, long_len) ||
 180            copy_from_user(inp, crt->inputdata, mod_len))
 181                return -EFAULT;
 182        return 0;
 183}
 184
 185/**
 186 * Copy results from a type 84 reply message back to user space.
 187 *
 188 * @zdev: crypto device pointer
 189 * @reply: reply AP message.
 190 * @data: pointer to user output data
 191 * @length: size of user output data
 192 *
 193 * Returns 0 on success or -EFAULT.
 194 */
 195static int convert_type84(struct zcrypt_device *zdev,
 196                          struct ap_message *reply,
 197                          char __user *outputdata,
 198                          unsigned int outputdatalength)
 199{
 200        struct type84_hdr *t84h = reply->message;
 201        char *data;
 202
 203        if (t84h->len < sizeof(*t84h) + outputdatalength) {
 204                /* The result is too short, the PCICA card may not do that.. */
 205                zdev->online = 0;
 206                return -EAGAIN; /* repeat the request on a different device. */
 207        }
 208        BUG_ON(t84h->len > PCICA_MAX_RESPONSE_SIZE);
 209        data = reply->message + t84h->len - outputdatalength;
 210        if (copy_to_user(outputdata, data, outputdatalength))
 211                return -EFAULT;
 212        return 0;
 213}
 214
 215static int convert_response(struct zcrypt_device *zdev,
 216                            struct ap_message *reply,
 217                            char __user *outputdata,
 218                            unsigned int outputdatalength)
 219{
 220        /* Response type byte is the second byte in the response. */
 221        switch (((unsigned char *) reply->message)[1]) {
 222        case TYPE82_RSP_CODE:
 223        case TYPE88_RSP_CODE:
 224                return convert_error(zdev, reply);
 225        case TYPE84_RSP_CODE:
 226                return convert_type84(zdev, reply,
 227                                      outputdata, outputdatalength);
 228        default: /* Unknown response type, this should NEVER EVER happen */
 229                PRINTK("Unrecognized Message Header: %08x%08x\n",
 230                       *(unsigned int *) reply->message,
 231                       *(unsigned int *) (reply->message+4));
 232                zdev->online = 0;
 233                return -EAGAIN; /* repeat the request on a different device. */
 234        }
 235}
 236
 237/**
 238 * This function is called from the AP bus code after a crypto request
 239 * "msg" has finished with the reply message "reply".
 240 * It is called from tasklet context.
 241 * @ap_dev: pointer to the AP device
 242 * @msg: pointer to the AP message
 243 * @reply: pointer to the AP reply message
 244 */
 245static void zcrypt_pcica_receive(struct ap_device *ap_dev,
 246                                 struct ap_message *msg,
 247                                 struct ap_message *reply)
 248{
 249        static struct error_hdr error_reply = {
 250                .type = TYPE82_RSP_CODE,
 251                .reply_code = REP82_ERROR_MACHINE_FAILURE,
 252        };
 253        struct type84_hdr *t84h = reply->message;
 254        int length;
 255
 256        /* Copy the reply message to the request message buffer. */
 257        if (IS_ERR(reply))
 258                memcpy(msg->message, &error_reply, sizeof(error_reply));
 259        else if (t84h->code == TYPE84_RSP_CODE) {
 260                length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len);
 261                memcpy(msg->message, reply->message, length);
 262        } else
 263                memcpy(msg->message, reply->message, sizeof error_reply);
 264        complete((struct completion *) msg->private);
 265}
 266
 267static atomic_t zcrypt_step = ATOMIC_INIT(0);
 268
 269/**
 270 * The request distributor calls this function if it picked the PCICA
 271 * device to handle a modexpo request.
 272 * @zdev: pointer to zcrypt_device structure that identifies the
 273 *        PCICA device to the request distributor
 274 * @mex: pointer to the modexpo request buffer
 275 */
 276static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
 277                                 struct ica_rsa_modexpo *mex)
 278{
 279        struct ap_message ap_msg;
 280        struct completion work;
 281        int rc;
 282
 283        ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
 284        if (!ap_msg.message)
 285                return -ENOMEM;
 286        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
 287                                atomic_inc_return(&zcrypt_step);
 288        ap_msg.private = &work;
 289        rc = ICAMEX_msg_to_type4MEX_msg(zdev, &ap_msg, mex);
 290        if (rc)
 291                goto out_free;
 292        init_completion(&work);
 293        ap_queue_message(zdev->ap_dev, &ap_msg);
 294        rc = wait_for_completion_interruptible(&work);
 295        if (rc == 0)
 296                rc = convert_response(zdev, &ap_msg, mex->outputdata,
 297                                      mex->outputdatalength);
 298        else
 299                /* Signal pending. */
 300                ap_cancel_message(zdev->ap_dev, &ap_msg);
 301out_free:
 302        kfree(ap_msg.message);
 303        return rc;
 304}
 305
 306/**
 307 * The request distributor calls this function if it picked the PCICA
 308 * device to handle a modexpo_crt request.
 309 * @zdev: pointer to zcrypt_device structure that identifies the
 310 *        PCICA device to the request distributor
 311 * @crt: pointer to the modexpoc_crt request buffer
 312 */
 313static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
 314                                     struct ica_rsa_modexpo_crt *crt)
 315{
 316        struct ap_message ap_msg;
 317        struct completion work;
 318        int rc;
 319
 320        ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
 321        if (!ap_msg.message)
 322                return -ENOMEM;
 323        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
 324                                atomic_inc_return(&zcrypt_step);
 325        ap_msg.private = &work;
 326        rc = ICACRT_msg_to_type4CRT_msg(zdev, &ap_msg, crt);
 327        if (rc)
 328                goto out_free;
 329        init_completion(&work);
 330        ap_queue_message(zdev->ap_dev, &ap_msg);
 331        rc = wait_for_completion_interruptible(&work);
 332        if (rc == 0)
 333                rc = convert_response(zdev, &ap_msg, crt->outputdata,
 334                                      crt->outputdatalength);
 335        else
 336                /* Signal pending. */
 337                ap_cancel_message(zdev->ap_dev, &ap_msg);
 338out_free:
 339        kfree(ap_msg.message);
 340        return rc;
 341}
 342
 343/**
 344 * The crypto operations for a PCICA card.
 345 */
 346static struct zcrypt_ops zcrypt_pcica_ops = {
 347        .rsa_modexpo = zcrypt_pcica_modexpo,
 348        .rsa_modexpo_crt = zcrypt_pcica_modexpo_crt,
 349};
 350
 351/**
 352 * Probe function for PCICA cards. It always accepts the AP device
 353 * since the bus_match already checked the hardware type.
 354 * @ap_dev: pointer to the AP device.
 355 */
 356static int zcrypt_pcica_probe(struct ap_device *ap_dev)
 357{
 358        struct zcrypt_device *zdev;
 359        int rc;
 360
 361        zdev = zcrypt_device_alloc(PCICA_MAX_RESPONSE_SIZE);
 362        if (!zdev)
 363                return -ENOMEM;
 364        zdev->ap_dev = ap_dev;
 365        zdev->ops = &zcrypt_pcica_ops;
 366        zdev->online = 1;
 367        zdev->user_space_type = ZCRYPT_PCICA;
 368        zdev->type_string = "PCICA";
 369        zdev->min_mod_size = PCICA_MIN_MOD_SIZE;
 370        zdev->max_mod_size = PCICA_MAX_MOD_SIZE;
 371        zdev->speed_rating = PCICA_SPEED_RATING;
 372        ap_dev->reply = &zdev->reply;
 373        ap_dev->private = zdev;
 374        rc = zcrypt_device_register(zdev);
 375        if (rc)
 376                goto out_free;
 377        return 0;
 378
 379out_free:
 380        ap_dev->private = NULL;
 381        zcrypt_device_free(zdev);
 382        return rc;
 383}
 384
 385/**
 386 * This is called to remove the extended PCICA driver information
 387 * if an AP device is removed.
 388 */
 389static void zcrypt_pcica_remove(struct ap_device *ap_dev)
 390{
 391        struct zcrypt_device *zdev = ap_dev->private;
 392
 393        zcrypt_device_unregister(zdev);
 394}
 395
 396int __init zcrypt_pcica_init(void)
 397{
 398        return ap_driver_register(&zcrypt_pcica_driver, THIS_MODULE, "pcica");
 399}
 400
 401void zcrypt_pcica_exit(void)
 402{
 403        ap_driver_unregister(&zcrypt_pcica_driver);
 404}
 405
 406#ifndef CONFIG_ZCRYPT_MONOLITHIC
 407module_init(zcrypt_pcica_init);
 408module_exit(zcrypt_pcica_exit);
 409#endif
 410
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.