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