diff options
author | Ralph Wuerthner <rwuerthn@de.ibm.com> | 2008-04-17 01:46:15 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-04-17 01:47:02 -0400 |
commit | 2f7c8bd6dc6540aa3275c0ad9f657401985c00e9 (patch) | |
tree | 12cb12d661424d332ad960113c8849b3579e7e6a /drivers/s390/crypto/zcrypt_pcixcc.c | |
parent | 893f11286644780fc7d6d415e537644da7bdaaf8 (diff) |
[S390] zcrypt: add support for large random numbers
This patch allows user space applications to access large amounts of
truly random data. The random data source is the build-in hardware
random number generator on the CEX2C cards.
Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/zcrypt_pcixcc.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcixcc.c | 199 |
1 files changed, 198 insertions, 1 deletions
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 70b9ddc8cf9d..3674bfa82b65 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
@@ -356,6 +356,55 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | |||
356 | } | 356 | } |
357 | 357 | ||
358 | /** | 358 | /** |
359 | * Prepare a type6 CPRB message for random number generation | ||
360 | * | ||
361 | * @ap_dev: AP device pointer | ||
362 | * @ap_msg: pointer to AP message | ||
363 | */ | ||
364 | static void rng_type6CPRB_msgX(struct ap_device *ap_dev, | ||
365 | struct ap_message *ap_msg, | ||
366 | unsigned random_number_length) | ||
367 | { | ||
368 | struct { | ||
369 | struct type6_hdr hdr; | ||
370 | struct CPRBX cprbx; | ||
371 | char function_code[2]; | ||
372 | short int rule_length; | ||
373 | char rule[8]; | ||
374 | short int verb_length; | ||
375 | short int key_length; | ||
376 | } __attribute__((packed)) *msg = ap_msg->message; | ||
377 | static struct type6_hdr static_type6_hdrX = { | ||
378 | .type = 0x06, | ||
379 | .offset1 = 0x00000058, | ||
380 | .agent_id = {'C', 'A'}, | ||
381 | .function_code = {'R', 'L'}, | ||
382 | .ToCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
383 | .FromCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
384 | }; | ||
385 | static struct CPRBX static_cprbx = { | ||
386 | .cprb_len = 0x00dc, | ||
387 | .cprb_ver_id = 0x02, | ||
388 | .func_id = {0x54, 0x32}, | ||
389 | .req_parml = sizeof *msg - sizeof(msg->hdr) - | ||
390 | sizeof(msg->cprbx), | ||
391 | .rpl_msgbl = sizeof *msg - sizeof(msg->hdr), | ||
392 | }; | ||
393 | |||
394 | msg->hdr = static_type6_hdrX; | ||
395 | msg->hdr.FromCardLen2 = random_number_length, | ||
396 | msg->cprbx = static_cprbx; | ||
397 | msg->cprbx.rpl_datal = random_number_length, | ||
398 | msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); | ||
399 | memcpy(msg->function_code, msg->hdr.function_code, 0x02); | ||
400 | msg->rule_length = 0x0a; | ||
401 | memcpy(msg->rule, "RANDOM ", 8); | ||
402 | msg->verb_length = 0x02; | ||
403 | msg->key_length = 0x02; | ||
404 | ap_msg->length = sizeof *msg; | ||
405 | } | ||
406 | |||
407 | /** | ||
359 | * Copy results from a type 86 ICA reply message back to user space. | 408 | * Copy results from a type 86 ICA reply message back to user space. |
360 | * | 409 | * |
361 | * @zdev: crypto device pointer | 410 | * @zdev: crypto device pointer |
@@ -509,6 +558,26 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev, | |||
509 | return 0; | 558 | return 0; |
510 | } | 559 | } |
511 | 560 | ||
561 | static int convert_type86_rng(struct zcrypt_device *zdev, | ||
562 | struct ap_message *reply, | ||
563 | char *buffer) | ||
564 | { | ||
565 | struct { | ||
566 | struct type86_hdr hdr; | ||
567 | struct type86_fmt2_ext fmt2; | ||
568 | struct CPRBX cprbx; | ||
569 | } __attribute__((packed)) *msg = reply->message; | ||
570 | char *data = reply->message; | ||
571 | |||
572 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) { | ||
573 | PDEBUG("RNG response error on PCIXCC/CEX2C rc=%hu/rs=%hu\n", | ||
574 | rc, rs); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); | ||
578 | return msg->fmt2.count2; | ||
579 | } | ||
580 | |||
512 | static int convert_response_ica(struct zcrypt_device *zdev, | 581 | static int convert_response_ica(struct zcrypt_device *zdev, |
513 | struct ap_message *reply, | 582 | struct ap_message *reply, |
514 | char __user *outputdata, | 583 | char __user *outputdata, |
@@ -567,6 +636,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, | |||
567 | } | 636 | } |
568 | } | 637 | } |
569 | 638 | ||
639 | static int convert_response_rng(struct zcrypt_device *zdev, | ||
640 | struct ap_message *reply, | ||
641 | char *data) | ||
642 | { | ||
643 | struct type86x_reply *msg = reply->message; | ||
644 | |||
645 | switch (msg->hdr.type) { | ||
646 | case TYPE82_RSP_CODE: | ||
647 | case TYPE88_RSP_CODE: | ||
648 | return -EINVAL; | ||
649 | case TYPE86_RSP_CODE: | ||
650 | if (msg->hdr.reply_code) | ||
651 | return -EINVAL; | ||
652 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
653 | return convert_type86_rng(zdev, reply, data); | ||
654 | /* no break, incorrect cprb version is an unknown response */ | ||
655 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
656 | PRINTK("Unrecognized Message Header: %08x%08x\n", | ||
657 | *(unsigned int *) reply->message, | ||
658 | *(unsigned int *) (reply->message+4)); | ||
659 | zdev->online = 0; | ||
660 | return -EAGAIN; /* repeat the request on a different device. */ | ||
661 | } | ||
662 | } | ||
663 | |||
570 | /** | 664 | /** |
571 | * This function is called from the AP bus code after a crypto request | 665 | * This function is called from the AP bus code after a crypto request |
572 | * "msg" has finished with the reply message "reply". | 666 | * "msg" has finished with the reply message "reply". |
@@ -736,6 +830,42 @@ out_free: | |||
736 | } | 830 | } |
737 | 831 | ||
738 | /** | 832 | /** |
833 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
834 | * device to generate random data. | ||
835 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
836 | * PCIXCC/CEX2C device to the request distributor | ||
837 | * @buffer: pointer to a memory page to return random data | ||
838 | */ | ||
839 | |||
840 | static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev, | ||
841 | char *buffer) | ||
842 | { | ||
843 | struct ap_message ap_msg; | ||
844 | struct response_type resp_type = { | ||
845 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
846 | }; | ||
847 | int rc; | ||
848 | |||
849 | ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
850 | if (!ap_msg.message) | ||
851 | return -ENOMEM; | ||
852 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
853 | atomic_inc_return(&zcrypt_step); | ||
854 | ap_msg.private = &resp_type; | ||
855 | rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); | ||
856 | init_completion(&resp_type.work); | ||
857 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
858 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
859 | if (rc == 0) | ||
860 | rc = convert_response_rng(zdev, &ap_msg, buffer); | ||
861 | else | ||
862 | /* Signal pending. */ | ||
863 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
864 | kfree(ap_msg.message); | ||
865 | return rc; | ||
866 | } | ||
867 | |||
868 | /** | ||
739 | * The crypto operations for a PCIXCC/CEX2C card. | 869 | * The crypto operations for a PCIXCC/CEX2C card. |
740 | */ | 870 | */ |
741 | static struct zcrypt_ops zcrypt_pcixcc_ops = { | 871 | static struct zcrypt_ops zcrypt_pcixcc_ops = { |
@@ -744,6 +874,13 @@ static struct zcrypt_ops zcrypt_pcixcc_ops = { | |||
744 | .send_cprb = zcrypt_pcixcc_send_cprb, | 874 | .send_cprb = zcrypt_pcixcc_send_cprb, |
745 | }; | 875 | }; |
746 | 876 | ||
877 | static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = { | ||
878 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | ||
879 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | ||
880 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
881 | .rng = zcrypt_pcixcc_rng, | ||
882 | }; | ||
883 | |||
747 | /** | 884 | /** |
748 | * Micro-code detection function. Its sends a message to a pcixcc card | 885 | * Micro-code detection function. Its sends a message to a pcixcc card |
749 | * to find out the microcode level. | 886 | * to find out the microcode level. |
@@ -859,6 +996,58 @@ out_free: | |||
859 | } | 996 | } |
860 | 997 | ||
861 | /** | 998 | /** |
999 | * Large random number detection function. Its sends a message to a pcixcc | ||
1000 | * card to find out if large random numbers are supported. | ||
1001 | * @ap_dev: pointer to the AP device. | ||
1002 | * | ||
1003 | * Returns 1 if large random numbers are supported, 0 if not and < 0 on error. | ||
1004 | */ | ||
1005 | static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) | ||
1006 | { | ||
1007 | struct ap_message ap_msg; | ||
1008 | unsigned long long psmid; | ||
1009 | struct { | ||
1010 | struct type86_hdr hdr; | ||
1011 | struct type86_fmt2_ext fmt2; | ||
1012 | struct CPRBX cprbx; | ||
1013 | } __attribute__((packed)) *reply; | ||
1014 | int rc, i; | ||
1015 | |||
1016 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
1017 | if (!ap_msg.message) | ||
1018 | return -ENOMEM; | ||
1019 | |||
1020 | rng_type6CPRB_msgX(ap_dev, &ap_msg, 4); | ||
1021 | rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, | ||
1022 | ap_msg.length); | ||
1023 | if (rc) | ||
1024 | goto out_free; | ||
1025 | |||
1026 | /* Wait for the test message to complete. */ | ||
1027 | for (i = 0; i < 2 * HZ; i++) { | ||
1028 | msleep(1000 / HZ); | ||
1029 | rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096); | ||
1030 | if (rc == 0 && psmid == 0x0102030405060708ULL) | ||
1031 | break; | ||
1032 | } | ||
1033 | |||
1034 | if (i >= 2 * HZ) { | ||
1035 | /* Got no answer. */ | ||
1036 | rc = -ENODEV; | ||
1037 | goto out_free; | ||
1038 | } | ||
1039 | |||
1040 | reply = ap_msg.message; | ||
1041 | if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0) | ||
1042 | rc = 1; | ||
1043 | else | ||
1044 | rc = 0; | ||
1045 | out_free: | ||
1046 | free_page((unsigned long) ap_msg.message); | ||
1047 | return rc; | ||
1048 | } | ||
1049 | |||
1050 | /** | ||
862 | * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device | 1051 | * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device |
863 | * since the bus_match already checked the hardware type. The PCIXCC | 1052 | * since the bus_match already checked the hardware type. The PCIXCC |
864 | * cards come in two flavours: micro code level 2 and micro code level 3. | 1053 | * cards come in two flavours: micro code level 2 and micro code level 3. |
@@ -874,7 +1063,6 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
874 | if (!zdev) | 1063 | if (!zdev) |
875 | return -ENOMEM; | 1064 | return -ENOMEM; |
876 | zdev->ap_dev = ap_dev; | 1065 | zdev->ap_dev = ap_dev; |
877 | zdev->ops = &zcrypt_pcixcc_ops; | ||
878 | zdev->online = 1; | 1066 | zdev->online = 1; |
879 | if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) { | 1067 | if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) { |
880 | rc = zcrypt_pcixcc_mcl(ap_dev); | 1068 | rc = zcrypt_pcixcc_mcl(ap_dev); |
@@ -901,6 +1089,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
901 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; | 1089 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; |
902 | zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; | 1090 | zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; |
903 | } | 1091 | } |
1092 | rc = zcrypt_pcixcc_rng_supported(ap_dev); | ||
1093 | if (rc < 0) { | ||
1094 | zcrypt_device_free(zdev); | ||
1095 | return rc; | ||
1096 | } | ||
1097 | if (rc) | ||
1098 | zdev->ops = &zcrypt_pcixcc_with_rng_ops; | ||
1099 | else | ||
1100 | zdev->ops = &zcrypt_pcixcc_ops; | ||
904 | ap_dev->reply = &zdev->reply; | 1101 | ap_dev->reply = &zdev->reply; |
905 | ap_dev->private = zdev; | 1102 | ap_dev->private = zdev; |
906 | rc = zcrypt_device_register(zdev); | 1103 | rc = zcrypt_device_register(zdev); |