diff options
author | Linus Torvalds | 2019-09-17 14:04:43 -0700 |
---|---|---|
committer | Linus Torvalds | 2019-09-17 14:04:43 -0700 |
commit | d590284419b1d7cc2dc646e9bdde4da19061cf0f (patch) | |
tree | 007a94945a82e3010c1847daeeb8f17d8e988929 /drivers/s390 | |
parent | 1e24aaabdee9e07f19b09bd305ffc069b0b07371 (diff) | |
parent | 2735913c1079b7dd7ec1d746c13a84ec1b5ea276 (diff) |
Merge tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Vasily Gorbik:
- Add support for IBM z15 machines.
- Add SHA3 and CCA AES cipher key support in zcrypt and pkey
refactoring.
- Move to arch_stack_walk infrastructure for the stack unwinder.
- Various kasan fixes and improvements.
- Various command line parsing fixes.
- Improve decompressor phase debuggability.
- Lift no bss usage restriction for the early code.
- Use refcount_t for reference counters for couple of places in mm
code.
- Logging improvements and return code fix in vfio-ccw code.
- Couple of zpci fixes and minor refactoring.
- Remove some outdated documentation.
- Fix secure boot detection.
- Other various minor code clean ups.
* tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (48 commits)
s390: remove pointless drivers-y in drivers/s390/Makefile
s390/cpum_sf: Fix line length and format string
s390/pci: fix MSI message data
s390: add support for IBM z15 machines
s390/crypto: Support for SHA3 via CPACF (MSA6)
s390/startup: add pgm check info printing
s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding
vfio-ccw: fix error return code in vfio_ccw_sch_init()
s390: vfio-ap: fix warning reset not completed
s390/base: remove unused s390_base_mcck_handler
s390/sclp: Fix bit checked for has_sipl
s390/zcrypt: fix wrong handling of cca cipher keygenflags
s390/kasan: add kdump support
s390/setup: avoid using strncmp with hardcoded length
s390/sclp: avoid using strncmp with hardcoded length
s390/module: avoid using strncmp with hardcoded length
s390/pci: avoid using strncmp with hardcoded length
s390/kaslr: reserve memory for kasan usage
s390/mem_detect: provide single get_mem_detect_end
s390/cmma: reuse kstrtobool for option value parsing
...
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/Makefile | 3 | ||||
-rw-r--r-- | drivers/s390/char/Makefile | 3 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/vmcp.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_drv.c | 58 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_fsm.c | 51 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_ops.c | 10 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_private.h | 17 | ||||
-rw-r--r-- | drivers/s390/crypto/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_api.c | 1638 | ||||
-rw-r--r-- | drivers/s390/crypto/vfio_ap_ops.c | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 30 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.h | 7 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.c | 1765 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.h | 217 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_cex4.c | 106 |
16 files changed, 2924 insertions, 989 deletions
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index a863b0462b43..cde73b6a9afb 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -4,6 +4,3 @@ # obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/ - -drivers-y += drivers/s390/built-in.a - diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index b8a8816d94e7..845e12ac5954 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -49,6 +49,3 @@ obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o obj-$(CONFIG_HMC_DRV) += hmcdrv.o - -chkbss := sclp_early_core.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index e71992a3c55f..cc5e84b80c69 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -40,7 +40,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); - sclp.has_sipl = !!(sccb->cbl & 0x02); + sclp.has_sipl = !!(sccb->cbl & 0x4000); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; if (sccb->fac91 & 0x40) diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 0fa1b6b1491a..9e066281e2d0 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -43,6 +43,8 @@ static struct cma *vmcp_cma; static int __init early_parse_vmcp_cma(char *p) { + if (!p) + return 1; vmcp_cma_size = ALIGN(memparse(p, NULL), PAGE_SIZE); return 0; } diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 9208c0e56c33..e401a3d0aa57 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -27,6 +27,9 @@ struct workqueue_struct *vfio_ccw_work_q; static struct kmem_cache *vfio_ccw_io_region; static struct kmem_cache *vfio_ccw_cmd_region; +debug_info_t *vfio_ccw_debug_msg_id; +debug_info_t *vfio_ccw_debug_trace_id; + /* * Helpers */ @@ -164,6 +167,9 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) if (ret) goto out_disable; + VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n", + sch->schid.cssid, sch->schid.ssid, + sch->schid.sch_no); return 0; out_disable: @@ -194,6 +200,9 @@ static int vfio_ccw_sch_remove(struct subchannel *sch) kfree(private->cp.guest_cp); kfree(private); + VFIO_CCW_MSG_EVENT(4, "unbound from subchannel %x.%x.%04x\n", + sch->schid.cssid, sch->schid.ssid, + sch->schid.sch_no); return 0; } @@ -263,27 +272,64 @@ static struct css_driver vfio_ccw_sch_driver = { .sch_event = vfio_ccw_sch_event, }; +static int __init vfio_ccw_debug_init(void) +{ + vfio_ccw_debug_msg_id = debug_register("vfio_ccw_msg", 16, 1, + 11 * sizeof(long)); + if (!vfio_ccw_debug_msg_id) + goto out_unregister; + debug_register_view(vfio_ccw_debug_msg_id, &debug_sprintf_view); + debug_set_level(vfio_ccw_debug_msg_id, 2); + vfio_ccw_debug_trace_id = debug_register("vfio_ccw_trace", 16, 1, 16); + if (!vfio_ccw_debug_trace_id) + goto out_unregister; + debug_register_view(vfio_ccw_debug_trace_id, &debug_hex_ascii_view); + debug_set_level(vfio_ccw_debug_trace_id, 2); + return 0; + +out_unregister: + debug_unregister(vfio_ccw_debug_msg_id); + debug_unregister(vfio_ccw_debug_trace_id); + return -1; +} + +static void vfio_ccw_debug_exit(void) +{ + debug_unregister(vfio_ccw_debug_msg_id); + debug_unregister(vfio_ccw_debug_trace_id); +} + static int __init vfio_ccw_sch_init(void) { - int ret = -ENOMEM; + int ret; + + ret = vfio_ccw_debug_init(); + if (ret) + return ret; vfio_ccw_work_q = create_singlethread_workqueue("vfio-ccw"); - if (!vfio_ccw_work_q) - return -ENOMEM; + if (!vfio_ccw_work_q) { + ret = -ENOMEM; + goto out_err; + } vfio_ccw_io_region = kmem_cache_create_usercopy("vfio_ccw_io_region", sizeof(struct ccw_io_region), 0, SLAB_ACCOUNT, 0, sizeof(struct ccw_io_region), NULL); - if (!vfio_ccw_io_region) + if (!vfio_ccw_io_region) { + ret = -ENOMEM; goto out_err; + } vfio_ccw_cmd_region = kmem_cache_create_usercopy("vfio_ccw_cmd_region", sizeof(struct ccw_cmd_region), 0, SLAB_ACCOUNT, 0, sizeof(struct ccw_cmd_region), NULL); - if (!vfio_ccw_cmd_region) + if (!vfio_ccw_cmd_region) { + ret = -ENOMEM; goto out_err; + } isc_register(VFIO_CCW_ISC); ret = css_driver_register(&vfio_ccw_sch_driver); @@ -298,6 +344,7 @@ out_err: kmem_cache_destroy(vfio_ccw_cmd_region); kmem_cache_destroy(vfio_ccw_io_region); destroy_workqueue(vfio_ccw_work_q); + vfio_ccw_debug_exit(); return ret; } @@ -308,6 +355,7 @@ static void __exit vfio_ccw_sch_exit(void) kmem_cache_destroy(vfio_ccw_io_region); kmem_cache_destroy(vfio_ccw_cmd_region); destroy_workqueue(vfio_ccw_work_q); + vfio_ccw_debug_exit(); } module_init(vfio_ccw_sch_init); module_exit(vfio_ccw_sch_exit); diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index 49d9d3da0282..4a1e727c62d9 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -37,9 +37,14 @@ static int fsm_io_helper(struct vfio_ccw_private *private) goto out; } + VFIO_CCW_TRACE_EVENT(5, "stIO"); + VFIO_CCW_TRACE_EVENT(5, dev_name(&sch->dev)); + /* Issue "Start Subchannel" */ ccode = ssch(sch->schid, orb); + VFIO_CCW_HEX_EVENT(5, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -86,9 +91,14 @@ static int fsm_do_halt(struct vfio_ccw_private *private) spin_lock_irqsave(sch->lock, flags); + VFIO_CCW_TRACE_EVENT(2, "haltIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* Issue "Halt Subchannel" */ ccode = hsch(sch->schid); + VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -122,9 +132,14 @@ static int fsm_do_clear(struct vfio_ccw_private *private) spin_lock_irqsave(sch->lock, flags); + VFIO_CCW_TRACE_EVENT(2, "clearIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* Issue "Clear Subchannel" */ ccode = csch(sch->schid); + VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -149,6 +164,9 @@ static void fsm_notoper(struct vfio_ccw_private *private, { struct subchannel *sch = private->sch; + VFIO_CCW_TRACE_EVENT(2, "notoper"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* * TODO: * Probably we should send the machine check to the guest. @@ -229,6 +247,7 @@ static void fsm_io_request(struct vfio_ccw_private *private, struct ccw_io_region *io_region = private->io_region; struct mdev_device *mdev = private->mdev; char *errstr = "request"; + struct subchannel_id schid = get_schid(private); private->state = VFIO_CCW_STATE_CP_PROCESSING; memcpy(scsw, io_region->scsw_area, sizeof(*scsw)); @@ -239,18 +258,32 @@ static void fsm_io_request(struct vfio_ccw_private *private, /* Don't try to build a cp if transport mode is specified. */ if (orb->tm.b) { io_region->ret_code = -EOPNOTSUPP; + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): transport mode\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); errstr = "transport mode"; goto err_out; } io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), orb); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): cp_init=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp init"; goto err_out; } io_region->ret_code = cp_prefetch(&private->cp); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): cp_prefetch=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp prefetch"; cp_free(&private->cp); goto err_out; @@ -259,23 +292,36 @@ static void fsm_io_request(struct vfio_ccw_private *private, /* Start channel program and wait for I/O interrupt. */ io_region->ret_code = fsm_io_helper(private); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): fsm_io_helper=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp fsm_io_helper"; cp_free(&private->cp); goto err_out; } return; } else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): halt on io_region\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); /* halt is handled via the async cmd region */ io_region->ret_code = -EOPNOTSUPP; goto err_out; } else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): clear on io_region\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); /* clear is handled via the async cmd region */ io_region->ret_code = -EOPNOTSUPP; goto err_out; } err_out: - trace_vfio_ccw_io_fctl(scsw->cmd.fctl, get_schid(private), + trace_vfio_ccw_io_fctl(scsw->cmd.fctl, schid, io_region->ret_code, errstr); } @@ -308,6 +354,9 @@ static void fsm_irq(struct vfio_ccw_private *private, { struct irb *irb = this_cpu_ptr(&cio_irb); + VFIO_CCW_TRACE_EVENT(6, "IRQ"); + VFIO_CCW_TRACE_EVENT(6, dev_name(&private->sch->dev)); + memcpy(&private->irb, irb, sizeof(*irb)); queue_work(vfio_ccw_work_q, &private->io_work); diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index 5eb61116ca6f..f0d71ab77c50 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -124,6 +124,11 @@ static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) private->mdev = mdev; private->state = VFIO_CCW_STATE_IDLE; + VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: create\n", + mdev_uuid(mdev), private->sch->schid.cssid, + private->sch->schid.ssid, + private->sch->schid.sch_no); + return 0; } @@ -132,6 +137,11 @@ static int vfio_ccw_mdev_remove(struct mdev_device *mdev) struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev)); + VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n", + mdev_uuid(mdev), private->sch->schid.cssid, + private->sch->schid.ssid, + private->sch->schid.sch_no); + if ((private->state != VFIO_CCW_STATE_NOT_OPER) && (private->state != VFIO_CCW_STATE_STANDBY)) { if (!vfio_ccw_sch_quiesce(private->sch)) diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h index f1092c3dc1b1..bbe9babf767b 100644 --- a/drivers/s390/cio/vfio_ccw_private.h +++ b/drivers/s390/cio/vfio_ccw_private.h @@ -17,6 +17,7 @@ #include <linux/eventfd.h> #include <linux/workqueue.h> #include <linux/vfio_ccw.h> +#include <asm/debug.h> #include "css.h" #include "vfio_ccw_cp.h" @@ -139,4 +140,20 @@ static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private, extern struct workqueue_struct *vfio_ccw_work_q; + +/* s390 debug feature, similar to base cio */ +extern debug_info_t *vfio_ccw_debug_msg_id; +extern debug_info_t *vfio_ccw_debug_trace_id; + +#define VFIO_CCW_TRACE_EVENT(imp, txt) \ + debug_text_event(vfio_ccw_debug_trace_id, imp, txt) + +#define VFIO_CCW_MSG_EVENT(imp, args...) \ + debug_sprintf_event(vfio_ccw_debug_msg_id, imp, ##args) + +static inline void VFIO_CCW_HEX_EVENT(int level, void *data, int length) +{ + debug_event(vfio_ccw_debug_trace_id, level, data, length); +} + #endif diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index 6ccd93d0b1cb..52aa95c8af4b 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -7,7 +7,7 @@ ap-objs := ap_bus.o ap_card.o ap_queue.o obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o # zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o -zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o +zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o zcrypt_ccamisc.o obj-$(CONFIG_ZCRYPT) += zcrypt.o # adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 7f418d2d8cdf..f76a1d0f54c4 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -2,7 +2,7 @@ /* * pkey device driver * - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017,2019 * Author(s): Harald Freudenberger */ @@ -24,16 +24,14 @@ #include <crypto/aes.h> #include "zcrypt_api.h" +#include "zcrypt_ccamisc.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 protected key interface"); -/* Size of parameter block used for all cca requests/replies */ -#define PARMBSIZE 512 - -/* Size of vardata block used for some of the cca requests/replies */ -#define VARDATASIZE 4096 +#define KEYBLOBBUFSIZE 8192 /* key buffer size used for internal processing */ +#define MAXAPQNSINLIST 64 /* max 64 apqns within a apqn list */ /* mask of available pckmo subfunctions, fetched once at module init */ static cpacf_mask_t pckmo_functions; @@ -62,40 +60,6 @@ static void __exit pkey_debug_exit(void) debug_unregister(debug_info); } -/* Key token types */ -#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */ -#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */ - -/* For TOKTYPE_NON_CCA: */ -#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */ - -/* For TOKTYPE_CCA_INTERNAL: */ -#define TOKVER_CCA_AES 0x04 /* CCA AES key token */ - -/* header part of a key token */ -struct keytoken_header { - u8 type; /* one of the TOKTYPE values */ - u8 res0[3]; - u8 version; /* one of the TOKVER values */ - u8 res1[3]; -} __packed; - -/* inside view of a secure key token (only type 0x01 version 0x04) */ -struct secaeskeytoken { - u8 type; /* 0x01 for internal key token */ - u8 res0[3]; - u8 version; /* should be 0x04 */ - u8 res1[1]; - u8 flag; /* key flags */ - u8 res2[1]; - u64 mkvp; /* master key verification pattern */ - u8 key[32]; /* key value (encrypted) */ - u8 cv[8]; /* control vector */ - u16 bitsize; /* key bit size */ - u16 keysize; /* key byte size */ - u8 tvv[4]; /* token validation value */ -} __packed; - /* inside view of a protected key token (only type 0x00 version 0x01) */ struct protaeskeytoken { u8 type; /* 0x00 for PAES specific key tokens */ @@ -108,557 +72,11 @@ struct protaeskeytoken { } __packed; /* - * Simple check if the token is a valid CCA secure AES key - * token. If keybitsize is given, the bitsize of the key is - * also checked. Returns 0 on success or errno value on failure. - */ -static int check_secaeskeytoken(const u8 *token, int keybitsize) -{ - struct secaeskeytoken *t = (struct secaeskeytoken *) token; - - if (t->type != TOKTYPE_CCA_INTERNAL) { - DEBUG_ERR( - "%s secure token check failed, type mismatch 0x%02x != 0x%02x\n", - __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); - return -EINVAL; - } - if (t->version != TOKVER_CCA_AES) { - DEBUG_ERR( - "%s secure token check failed, version mismatch 0x%02x != 0x%02x\n", - __func__, (int) t->version, TOKVER_CCA_AES); - return -EINVAL; - } - if (keybitsize > 0 && t->bitsize != keybitsize) { - DEBUG_ERR( - "%s secure token check failed, bitsize mismatch %d != %d\n", - __func__, (int) t->bitsize, keybitsize); - return -EINVAL; - } - - return 0; -} - -/* - * Allocate consecutive memory for request CPRB, request param - * block, reply CPRB and reply param block and fill in values - * for the common fields. Returns 0 on success or errno value - * on failure. - */ -static int alloc_and_prep_cprbmem(size_t paramblen, - u8 **pcprbmem, - struct CPRBX **preqCPRB, - struct CPRBX **prepCPRB) -{ - u8 *cprbmem; - size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; - struct CPRBX *preqcblk, *prepcblk; - - /* - * allocate consecutive memory for request CPRB, request param - * block, reply CPRB and reply param block - */ - cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); - if (!cprbmem) - return -ENOMEM; - - preqcblk = (struct CPRBX *) cprbmem; - prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen); - - /* fill request cprb struct */ - preqcblk->cprb_len = sizeof(struct CPRBX); - preqcblk->cprb_ver_id = 0x02; - memcpy(preqcblk->func_id, "T2", 2); - preqcblk->rpl_msgbl = cprbplusparamblen; - if (paramblen) { - preqcblk->req_parmb = - ((u8 *) preqcblk) + sizeof(struct CPRBX); - preqcblk->rpl_parmb = - ((u8 *) prepcblk) + sizeof(struct CPRBX); - } - - *pcprbmem = cprbmem; - *preqCPRB = preqcblk; - *prepCPRB = prepcblk; - - return 0; -} - -/* - * Free the cprb memory allocated with the function above. - * If the scrub value is not zero, the memory is filled - * with zeros before freeing (useful if there was some - * clear key material in there). - */ -static void free_cprbmem(void *mem, size_t paramblen, int scrub) -{ - if (scrub) - memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); - kfree(mem); -} - -/* - * Helper function to prepare the xcrb struct - */ -static inline void prep_xcrb(struct ica_xcRB *pxcrb, - u16 cardnr, - struct CPRBX *preqcblk, - struct CPRBX *prepcblk) -{ - memset(pxcrb, 0, sizeof(*pxcrb)); - pxcrb->agent_ID = 0x4341; /* 'CA' */ - pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); - pxcrb->request_control_blk_length = - preqcblk->cprb_len + preqcblk->req_parml; - pxcrb->request_control_blk_addr = (void __user *) preqcblk; - pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; - pxcrb->reply_control_blk_addr = (void __user *) prepcblk; -} - -/* - * Helper function which calls zcrypt_send_cprb with - * memory management segment adjusted to kernel space - * so that the copy_from_user called within this - * function do in fact copy from kernel space. - */ -static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) -{ - int rc; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - rc = zcrypt_send_cprb(xcrb); - set_fs(old_fs); - - return rc; -} - -/* - * Generate (random) AES secure key. - */ -int pkey_genseckey(u16 cardnr, u16 domain, - u32 keytype, struct pkey_seckey *seckey) -{ - int i, rc, keysize; - int seckeysize; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct kgreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv1 { - u16 len; - char key_form[8]; - char key_length[8]; - char key_type1[8]; - char key_type2[8]; - } lv1; - struct lv2 { - u16 len; - struct keyid { - u16 len; - u16 attr; - u8 data[SECKEYBLOBSIZE]; - } keyid[6]; - } lv2; - } *preqparm; - struct kgrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 keyblocklen; - struct { - u16 toklen; - u16 tokattr; - u8 tok[0]; - /* ... some more data ... */ - } keyblock; - } lv3; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with KG request */ - preqparm = (struct kgreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "KG", 2); - preqparm->rule_array_len = sizeof(preqparm->rule_array_len); - preqparm->lv1.len = sizeof(struct lv1); - memcpy(preqparm->lv1.key_form, "OP ", 8); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: - keysize = 16; - memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); - break; - case PKEY_KEYTYPE_AES_192: - keysize = 24; - memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); - break; - case PKEY_KEYTYPE_AES_256: - keysize = 32; - memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); - break; - default: - DEBUG_ERR( - "%s unknown/unsupported keytype %d\n", - __func__, keytype); - rc = -EINVAL; - goto out; - } - memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); - preqparm->lv2.len = sizeof(struct lv2); - for (i = 0; i < 6; i++) { - preqparm->lv2.keyid[i].len = sizeof(struct keyid); - preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); - } - preqcblk->req_parml = sizeof(struct kgreqparm); - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s secure key generate failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct kgrepparm *) prepcblk->rpl_parmb; - - /* check length of the returned secure key token */ - seckeysize = prepparm->lv3.keyblock.toklen - - sizeof(prepparm->lv3.keyblock.toklen) - - sizeof(prepparm->lv3.keyblock.tokattr); - if (seckeysize != SECKEYBLOBSIZE) { - DEBUG_ERR( - "%s secure token size mismatch %d != %d bytes\n", - __func__, seckeysize, SECKEYBLOBSIZE); - rc = -EIO; - goto out; - } - - /* check secure key token */ - rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize); - if (rc) { - rc = -EIO; - goto out; - } - - /* copy the generated secure key token */ - memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); - -out: - free_cprbmem(mem, PARMBSIZE, 0); - return rc; -} -EXPORT_SYMBOL(pkey_genseckey); - -/* - * Generate an AES secure key with given key value. - */ -int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_seckey *seckey) -{ - int rc, keysize, seckeysize; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct cmreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - char rule_array[8]; - struct lv1 { - u16 len; - u8 clrkey[0]; - } lv1; - struct lv2 { - u16 len; - struct keyid { - u16 len; - u16 attr; - u8 data[SECKEYBLOBSIZE]; - } keyid; - } lv2; - } *preqparm; - struct lv2 *plv2; - struct cmrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 keyblocklen; - struct { - u16 toklen; - u16 tokattr; - u8 tok[0]; - /* ... some more data ... */ - } keyblock; - } lv3; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with CM request */ - preqparm = (struct cmreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "CM", 2); - memcpy(preqparm->rule_array, "AES ", 8); - preqparm->rule_array_len = - sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: - keysize = 16; - break; - case PKEY_KEYTYPE_AES_192: - keysize = 24; - break; - case PKEY_KEYTYPE_AES_256: - keysize = 32; - break; - default: - DEBUG_ERR( - "%s unknown/unsupported keytype %d\n", - __func__, keytype); - rc = -EINVAL; - goto out; - } - preqparm->lv1.len = sizeof(struct lv1) + keysize; - memcpy(preqparm->lv1.clrkey, clrkey->clrkey, keysize); - plv2 = (struct lv2 *) (((u8 *) &preqparm->lv2) + keysize); - plv2->len = sizeof(struct lv2); - plv2->keyid.len = sizeof(struct keyid); - plv2->keyid.attr = 0x30; - preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s clear key import failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct cmrepparm *) prepcblk->rpl_parmb; - - /* check length of the returned secure key token */ - seckeysize = prepparm->lv3.keyblock.toklen - - sizeof(prepparm->lv3.keyblock.toklen) - - sizeof(prepparm->lv3.keyblock.tokattr); - if (seckeysize != SECKEYBLOBSIZE) { - DEBUG_ERR( - "%s secure token size mismatch %d != %d bytes\n", - __func__, seckeysize, SECKEYBLOBSIZE); - rc = -EIO; - goto out; - } - - /* check secure key token */ - rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize); - if (rc) { - rc = -EIO; - goto out; - } - - /* copy the generated secure key token */ - memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); - -out: - free_cprbmem(mem, PARMBSIZE, 1); - return rc; -} -EXPORT_SYMBOL(pkey_clr2seckey); - -/* - * Derive a proteced key from the secure key blob. - */ -int pkey_sec2protkey(u16 cardnr, u16 domain, - const struct pkey_seckey *seckey, - struct pkey_protkey *protkey) -{ - int rc; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct uskreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv1 { - u16 len; - u16 attr_len; - u16 attr_flags; - } lv1; - struct lv2 { - u16 len; - u16 attr_len; - u16 attr_flags; - u8 token[0]; /* cca secure key token */ - } lv2 __packed; - } *preqparm; - struct uskrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 attr_len; - u16 attr_flags; - struct cpacfkeyblock { - u8 version; /* version of this struct */ - u8 flags[2]; - u8 algo; - u8 form; - u8 pad1[3]; - u16 keylen; - u8 key[64]; /* the key (keylen bytes) */ - u16 keyattrlen; - u8 keyattr[32]; - u8 pad2[1]; - u8 vptype; - u8 vp[32]; /* verification pattern */ - } keyblock; - } lv3 __packed; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with USK request */ - preqparm = (struct uskreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "US", 2); - preqparm->rule_array_len = sizeof(preqparm->rule_array_len); - preqparm->lv1.len = sizeof(struct lv1); - preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); - preqparm->lv1.attr_flags = 0x0001; - preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; - preqparm->lv2.attr_len = sizeof(struct lv2) - - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; - preqparm->lv2.attr_flags = 0x0000; - memcpy(preqparm->lv2.token, seckey->seckey, SECKEYBLOBSIZE); - preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s unwrap secure key failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - if (prepcblk->ccp_rscode != 0) { - DEBUG_WARN( - "%s unwrap secure key warning, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct uskrepparm *) prepcblk->rpl_parmb; - - /* check the returned keyblock */ - if (prepparm->lv3.keyblock.version != 0x01) { - DEBUG_ERR( - "%s reply param keyblock version mismatch 0x%02x != 0x01\n", - __func__, (int) prepparm->lv3.keyblock.version); - rc = -EIO; - goto out; - } - - /* copy the tanslated protected key */ - switch (prepparm->lv3.keyblock.keylen) { - case 16+32: - protkey->type = PKEY_KEYTYPE_AES_128; - break; - case 24+32: - protkey->type = PKEY_KEYTYPE_AES_192; - break; - case 32+32: - protkey->type = PKEY_KEYTYPE_AES_256; - break; - default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, prepparm->lv3.keyblock.keylen); - rc = -EIO; - goto out; - } - protkey->len = prepparm->lv3.keyblock.keylen; - memcpy(protkey->protkey, prepparm->lv3.keyblock.key, protkey->len); - -out: - free_cprbmem(mem, PARMBSIZE, 0); - return rc; -} -EXPORT_SYMBOL(pkey_sec2protkey); - -/* * Create a protected key from a clear key value. */ -int pkey_clr2protkey(u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_protkey *protkey) +static int pkey_clr2protkey(u32 keytype, + const struct pkey_clrkey *clrkey, + struct pkey_protkey *protkey) { long fc; int keysize; @@ -707,338 +125,43 @@ int pkey_clr2protkey(u32 keytype, return 0; } -EXPORT_SYMBOL(pkey_clr2protkey); - -/* - * query cryptographic facility from adapter - */ -static int query_crypto_facility(u16 cardnr, u16 domain, - const char *keyword, - u8 *rarray, size_t *rarraylen, - u8 *varray, size_t *varraylen) -{ - int rc; - u16 len; - u8 *mem, *ptr; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct fqreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - char rule_array[8]; - struct lv1 { - u16 len; - u8 data[VARDATASIZE]; - } lv1; - u16 dummylen; - } *preqparm; - size_t parmbsize = sizeof(struct fqreqparm); - struct fqrepparm { - u8 subfunc_code[2]; - u8 lvdata[0]; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with FQ request */ - preqparm = (struct fqreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "FQ", 2); - memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); - preqparm->rule_array_len = - sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - preqparm->lv1.len = sizeof(preqparm->lv1); - preqparm->dummylen = sizeof(preqparm->dummylen); - preqcblk->req_parml = parmbsize; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s unwrap secure key failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct fqrepparm *) prepcblk->rpl_parmb; - ptr = prepparm->lvdata; - - /* check and possibly copy reply rule array */ - len = *((u16 *) ptr); - if (len > sizeof(u16)) { - ptr += sizeof(u16); - len -= sizeof(u16); - if (rarray && rarraylen && *rarraylen > 0) { - *rarraylen = (len > *rarraylen ? *rarraylen : len); - memcpy(rarray, ptr, *rarraylen); - } - ptr += len; - } - /* check and possible copy reply var array */ - len = *((u16 *) ptr); - if (len > sizeof(u16)) { - ptr += sizeof(u16); - len -= sizeof(u16); - if (varray && varraylen && *varraylen > 0) { - *varraylen = (len > *varraylen ? *varraylen : len); - memcpy(varray, ptr, *varraylen); - } - ptr += len; - } - -out: - free_cprbmem(mem, parmbsize, 0); - return rc; -} - -/* - * Fetch the current and old mkvp values via - * query_crypto_facility from adapter. - */ -static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int rc, found = 0; - size_t rlen, vlen; - u8 *rarray, *varray, *pg; - - pg = (u8 *) __get_free_page(GFP_KERNEL); - if (!pg) - return -ENOMEM; - rarray = pg; - varray = pg + PAGE_SIZE/2; - rlen = vlen = PAGE_SIZE/2; - - rc = query_crypto_facility(cardnr, domain, "STATICSA", - rarray, &rlen, varray, &vlen); - if (rc == 0 && rlen > 8*8 && vlen > 184+8) { - if (rarray[8*8] == '2') { - /* current master key state is valid */ - mkvp[0] = *((u64 *)(varray + 184)); - mkvp[1] = *((u64 *)(varray + 172)); - found = 1; - } - } - - free_page((unsigned long) pg); - - return found ? 0 : -ENOENT; -} - -/* struct to hold cached mkvp info for each card/domain */ -struct mkvp_info { - struct list_head list; - u16 cardnr; - u16 domain; - u64 mkvp[2]; -}; - -/* a list with mkvp_info entries */ -static LIST_HEAD(mkvp_list); -static DEFINE_SPINLOCK(mkvp_list_lock); - -static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int rc = -ENOENT; - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64)); - rc = 0; - break; - } - } - spin_unlock_bh(&mkvp_list_lock); - - return rc; -} - -static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int found = 0; - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); - found = 1; - break; - } - } - if (!found) { - ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); - if (!ptr) { - spin_unlock_bh(&mkvp_list_lock); - return; - } - ptr->cardnr = cardnr; - ptr->domain = domain; - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); - list_add(&ptr->list, &mkvp_list); - } - spin_unlock_bh(&mkvp_list_lock); -} - -static void mkvp_cache_scrub(u16 cardnr, u16 domain) -{ - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - list_del(&ptr->list); - kfree(ptr); - break; - } - } - spin_unlock_bh(&mkvp_list_lock); -} - -static void __exit mkvp_cache_free(void) -{ - struct mkvp_info *ptr, *pnext; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) { - list_del(&ptr->list); - kfree(ptr); - } - spin_unlock_bh(&mkvp_list_lock); -} - -/* - * Search for a matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. - */ -int pkey_findcard(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, int verify) -{ - struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; - struct zcrypt_device_status_ext *device_status; - u16 card, dom; - u64 mkvp[2]; - int i, rc, oi = -1; - - /* mkvp must not be zero */ - if (t->mkvp == 0) - return -EINVAL; - - /* fetch status of all crypto cards */ - device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, - sizeof(struct zcrypt_device_status_ext), - GFP_KERNEL); - if (!device_status) - return -ENOMEM; - zcrypt_device_status_mask_ext(device_status); - - /* walk through all crypto cards */ - for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { - card = AP_QID_CARD(device_status[i].qid); - dom = AP_QID_QUEUE(device_status[i].qid); - if (device_status[i].online && - device_status[i].functions & 0x04) { - /* an enabled CCA Coprocessor card */ - /* try cached mkvp */ - if (mkvp_cache_fetch(card, dom, mkvp) == 0 && - t->mkvp == mkvp[0]) { - if (!verify) - break; - /* verify: fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) - break; - } - } - } else { - /* Card is offline and/or not a CCA card. */ - /* del mkvp entry from cache if it exists */ - mkvp_cache_scrub(card, dom); - } - } - if (i >= MAX_ZDEV_ENTRIES_EXT) { - /* nothing found, so this time without cache */ - for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { - if (!(device_status[i].online && - device_status[i].functions & 0x04)) - continue; - card = AP_QID_CARD(device_status[i].qid); - dom = AP_QID_QUEUE(device_status[i].qid); - /* fresh fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) - break; - if (t->mkvp == mkvp[1] && oi < 0) - oi = i; - } - } - if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { - /* old mkvp matched, use this card then */ - card = AP_QID_CARD(device_status[oi].qid); - dom = AP_QID_QUEUE(device_status[oi].qid); - } - } - if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { - if (pcardnr) - *pcardnr = card; - if (pdomain) - *pdomain = dom; - rc = 0; - } else - rc = -ENODEV; - - kfree(device_status); - return rc; -} -EXPORT_SYMBOL(pkey_findcard); /* * Find card and transform secure key into protected key. */ -int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *protkey) +static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) { - u16 cardnr, domain; int rc, verify; + u16 cardnr, domain; + struct keytoken_header *hdr = (struct keytoken_header *)key; /* - * The pkey_sec2protkey call may fail when a card has been + * The cca_xxx2protkey call may fail when a card has been * addressed where the master key was changed after last fetch - * of the mkvp into the cache. So first try without verify then - * with verify enabled (thus refreshing the mkvp for each card). + * of the mkvp into the cache. Try 3 times: First witout verify + * then with verify and last round with verify and old master + * key verification pattern match not ignored. */ - for (verify = 0; verify < 2; verify++) { - rc = pkey_findcard(seckey, &cardnr, &domain, verify); - if (rc) + for (verify = 0; verify < 3; verify++) { + rc = cca_findcard(key, &cardnr, &domain, verify); + if (rc < 0) + continue; + if (rc > 0 && verify < 2) continue; - rc = pkey_sec2protkey(cardnr, domain, seckey, protkey); + switch (hdr->version) { + case TOKVER_CCA_AES: + rc = cca_sec2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + case TOKVER_CCA_VLSC: + rc = cca_cipher2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + default: + return -EINVAL; + } if (rc == 0) break; } @@ -1048,22 +171,20 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey, return rc; } -EXPORT_SYMBOL(pkey_skey2pkey); /* * Verify key and give back some info about the key. */ -int pkey_verifykey(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, - u16 *pkeysize, u32 *pattributes) +static int pkey_verifykey(const struct pkey_seckey *seckey, + u16 *pcardnr, u16 *pdomain, + u16 *pkeysize, u32 *pattributes) { struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; u16 cardnr, domain; - u64 mkvp[2]; int rc; /* check the secure key for valid AES secure key */ - rc = check_secaeskeytoken((u8 *) seckey, 0); + rc = cca_check_secaeskeytoken(debug_info, 3, (u8 *) seckey, 0); if (rc) goto out; if (pattributes) @@ -1072,18 +193,16 @@ int pkey_verifykey(const struct pkey_seckey *seckey, *pkeysize = t->bitsize; /* try to find a card which can handle this key */ - rc = pkey_findcard(seckey, &cardnr, &domain, 1); - if (rc) + rc = cca_findcard(seckey->seckey, &cardnr, &domain, 1); + if (rc < 0) goto out; - /* check mkvp for old mkvp match */ - rc = mkvp_cache_fetch(cardnr, domain, mkvp); - if (rc) - goto out; - if (t->mkvp == mkvp[1] && t->mkvp != mkvp[0]) { + if (rc > 0) { + /* key mkvp matches to old master key mkvp */ DEBUG_DBG("%s secure key has old mkvp\n", __func__); if (pattributes) *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; + rc = 0; } if (pcardnr) @@ -1095,12 +214,11 @@ out: DEBUG_DBG("%s rc=%d\n", __func__, rc); return rc; } -EXPORT_SYMBOL(pkey_verifykey); /* * Generate a random protected key */ -int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) +static int pkey_genprotkey(u32 keytype, struct pkey_protkey *protkey) { struct pkey_clrkey clrkey; int keysize; @@ -1135,12 +253,11 @@ int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) return 0; } -EXPORT_SYMBOL(pkey_genprotkey); /* * Verify if a protected key is still valid */ -int pkey_verifyprotkey(const struct pkey_protkey *protkey) +static int pkey_verifyprotkey(const struct pkey_protkey *protkey) { unsigned long fc; struct { @@ -1181,12 +298,11 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey) return 0; } -EXPORT_SYMBOL(pkey_verifyprotkey); /* * Transform a non-CCA key token into a protected key */ -static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen, +static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -1214,7 +330,7 @@ static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen, /* * Transform a CCA internal key token into a protected key */ -static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen, +static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -1223,44 +339,414 @@ static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen, case TOKVER_CCA_AES: if (keylen != sizeof(struct secaeskeytoken)) return -EINVAL; - - return pkey_skey2pkey((struct pkey_seckey *)key, - protkey); + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + break; default: DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n", __func__, hdr->version); return -EINVAL; } + + return pkey_skey2pkey(key, protkey); } /* * Transform a key blob (of any type) into a protected key */ -int pkey_keyblob2pkey(const __u8 *key, __u32 keylen, +int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { + int rc; struct keytoken_header *hdr = (struct keytoken_header *)key; - if (keylen < sizeof(struct keytoken_header)) + if (keylen < sizeof(struct keytoken_header)) { + DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen); return -EINVAL; + } switch (hdr->type) { case TOKTYPE_NON_CCA: - return pkey_nonccatok2pkey(key, keylen, protkey); + rc = pkey_nonccatok2pkey(key, keylen, protkey); + break; case TOKTYPE_CCA_INTERNAL: - return pkey_ccainttok2pkey(key, keylen, protkey); + rc = pkey_ccainttok2pkey(key, keylen, protkey); + break; default: - DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__, - hdr->type); + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); return -EINVAL; } + + DEBUG_DBG("%s rc=%d\n", __func__, rc); + return rc; + } EXPORT_SYMBOL(pkey_keyblob2pkey); +static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_genseckey(card, dom, ksize, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_gencipherkey(card, dom, ksize, kflags, + keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, const u8 *clrkey, + u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_clr2seckey(card, dom, ksize, + clrkey, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_clr2cipherkey(card, dom, ksize, kflags, + clrkey, keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_verifykey2(const u8 *key, size_t keylen, + u16 *cardnr, u16 *domain, + enum pkey_key_type *ktype, + enum pkey_key_size *ksize, u32 *flags) +{ + int rc; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + rc = cca_check_secaeskeytoken(debug_info, 3, key, 0); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_DATA; + if (ksize) + *ksize = (enum pkey_key_size) t->bitsize; + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX3C, t->mkvp, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX3C, 0, t->mkvp, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else if (hdr->version == TOKVER_CCA_VLSC) { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_CIPHER; + if (ksize) { + *ksize = PKEY_SIZE_UNKNOWN; + if (!t->plfver && t->wpllen == 512) + *ksize = PKEY_SIZE_AES_128; + else if (!t->plfver && t->wpllen == 576) + *ksize = PKEY_SIZE_AES_192; + else if (!t->plfver && t->wpllen == 640) + *ksize = PKEY_SIZE_AES_256; + } + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX6, t->mkvp0, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX6, 0, t->mkvp0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else + rc = -EINVAL; + +out: + kfree(_apqns); + return rc; +} + +static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, size_t keylen, + struct pkey_protkey *pkey) +{ + int i, card, dom, rc; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + if (keylen < sizeof(struct keytoken_header)) + return -EINVAL; + + switch (hdr->type) { + case TOKTYPE_NON_CCA: + return pkey_nonccatok2pkey(key, keylen, pkey); + case TOKTYPE_CCA_INTERNAL: + switch (hdr->version) { + case TOKVER_CCA_AES: + if (keylen != sizeof(struct secaeskeytoken)) + return -EINVAL; + if (cca_check_secaeskeytoken(debug_info, 3, key, 0)) + return -EINVAL; + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1)) + return -EINVAL; + break; + default: + DEBUG_ERR("%s unknown CCA internal token version %d\n", + __func__, hdr->version); + return -EINVAL; + } + break; + default: + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (hdr->version == TOKVER_CCA_AES) + rc = cca_sec2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + else /* TOKVER_CCA_VLSC */ + rc = cca_cipher2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = EINVAL; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL || + flags == 0) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES || hdr->version == TOKVER_CCA_VLSC) { + int minhwtype = ZCRYPT_CEX3C; + u64 cur_mkvp = 0, old_mkvp = 0; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp; + } else { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + minhwtype = ZCRYPT_CEX6; + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp0; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp0; + } + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + +static int pkey_apqns4keytype(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = -EINVAL; + u32 _nr_apqns, *_apqns = NULL; + + if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) { + u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = *((u64 *) cur_mkvp); + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = *((u64 *) alt_mkvp); + if (ktype == PKEY_TYPE_CCA_CIPHER) + minhwtype = ZCRYPT_CEX6; + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + /* * File io functions */ +static void *_copy_key_from_user(void __user *ukey, size_t keylen) +{ + void *kkey; + + if (!ukey || keylen < MINKEYBLOBSIZE || keylen > KEYBLOBBUFSIZE) + return ERR_PTR(-EINVAL); + kkey = kmalloc(keylen, GFP_KERNEL); + if (!kkey) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kkey, ukey, keylen)) { + kfree(kkey); + return ERR_PTR(-EFAULT); + } + + return kkey; +} + +static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns) +{ + void *kapqns = NULL; + size_t nbytes; + + if (uapqns && nr_apqns > 0) { + nbytes = nr_apqns * sizeof(struct pkey_apqn); + kapqns = kmalloc(nbytes, GFP_KERNEL); + if (!kapqns) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kapqns, uapqns, nbytes)) + return ERR_PTR(-EFAULT); + } + + return kapqns; +} + static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1273,9 +759,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kgs, ugs, sizeof(kgs))) return -EFAULT; - rc = pkey_genseckey(kgs.cardnr, kgs.domain, - kgs.keytype, &kgs.seckey); - DEBUG_DBG("%s pkey_genseckey()=%d\n", __func__, rc); + rc = cca_genseckey(kgs.cardnr, kgs.domain, + kgs.keytype, kgs.seckey.seckey); + DEBUG_DBG("%s cca_genseckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ugs, &kgs, sizeof(kgs))) @@ -1288,9 +774,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; - rc = pkey_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, - &kcs.clrkey, &kcs.seckey); - DEBUG_DBG("%s pkey_clr2seckey()=%d\n", __func__, rc); + rc = cca_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, + kcs.clrkey.clrkey, kcs.seckey.seckey); + DEBUG_DBG("%s cca_clr2seckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucs, &kcs, sizeof(kcs))) @@ -1304,9 +790,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_sec2protkey(ksp.cardnr, ksp.domain, - &ksp.seckey, &ksp.protkey); - DEBUG_DBG("%s pkey_sec2protkey()=%d\n", __func__, rc); + rc = cca_sec2protkey(ksp.cardnr, ksp.domain, + ksp.seckey.seckey, ksp.protkey.protkey, + NULL, &ksp.protkey.type); + DEBUG_DBG("%s cca_sec2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1335,10 +822,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kfc, ufc, sizeof(kfc))) return -EFAULT; - rc = pkey_findcard(&kfc.seckey, - &kfc.cardnr, &kfc.domain, 1); - DEBUG_DBG("%s pkey_findcard()=%d\n", __func__, rc); - if (rc) + rc = cca_findcard(kfc.seckey.seckey, + &kfc.cardnr, &kfc.domain, 1); + DEBUG_DBG("%s cca_findcard()=%d\n", __func__, rc); + if (rc < 0) break; if (copy_to_user(ufc, &kfc, sizeof(kfc))) return -EFAULT; @@ -1350,7 +837,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey); + rc = pkey_skey2pkey(ksp.seckey.seckey, &ksp.protkey); DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; @@ -1400,24 +887,148 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, case PKEY_KBLOB2PROTK: { struct pkey_kblob2pkey __user *utp = (void __user *) arg; struct pkey_kblob2pkey ktp; - __u8 __user *ukey; - __u8 *kkey; + u8 *kkey; if (copy_from_user(&ktp, utp, sizeof(ktp))) return -EFAULT; - if (ktp.keylen < MINKEYBLOBSIZE || - ktp.keylen > MAXKEYBLOBSIZE) - return -EINVAL; - ukey = ktp.key; - kkey = kmalloc(ktp.keylen, GFP_KERNEL); - if (kkey == NULL) + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(utp, &ktp, sizeof(ktp))) + return -EFAULT; + break; + } + case PKEY_GENSECK2: { + struct pkey_genseck2 __user *ugs = (void __user *) arg; + struct pkey_genseck2 kgs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kgs, ugs, sizeof(kgs))) + return -EFAULT; + apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); return -ENOMEM; - if (copy_from_user(kkey, ukey, ktp.keylen)) { + } + rc = pkey_genseckey2(apqns, kgs.apqn_entries, + kgs.type, kgs.size, kgs.keygenflags, + kkey, &klen); + DEBUG_DBG("%s pkey_genseckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { kfree(kkey); + break; + } + if (kgs.key) { + if (kgs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kgs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kgs.keylen = klen; + if (copy_to_user(ugs, &kgs, sizeof(kgs))) + rc = -EFAULT; + kfree(kkey); + break; + } + case PKEY_CLR2SECK2: { + struct pkey_clr2seck2 __user *ucs = (void __user *) arg; + struct pkey_clr2seck2 kcs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; + apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); + return -ENOMEM; } - rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); - DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + rc = pkey_clr2seckey2(apqns, kcs.apqn_entries, + kcs.type, kcs.size, kcs.keygenflags, + kcs.clrkey.clrkey, kkey, &klen); + DEBUG_DBG("%s pkey_clr2seckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { + kfree(kkey); + break; + } + if (kcs.key) { + if (kcs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kcs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kcs.keylen = klen; + if (copy_to_user(ucs, &kcs, sizeof(kcs))) + rc = -EFAULT; + memzero_explicit(&kcs, sizeof(kcs)); + kfree(kkey); + break; + } + case PKEY_VERIFYKEY2: { + struct pkey_verifykey2 __user *uvk = (void __user *) arg; + struct pkey_verifykey2 kvk; + u8 *kkey; + + if (copy_from_user(&kvk, uvk, sizeof(kvk))) + return -EFAULT; + kkey = _copy_key_from_user(kvk.key, kvk.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + rc = pkey_verifykey2(kkey, kvk.keylen, + &kvk.cardnr, &kvk.domain, + &kvk.type, &kvk.size, &kvk.flags); + DEBUG_DBG("%s pkey_verifykey2()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(uvk, &kvk, sizeof(kvk))) + return -EFAULT; + break; + } + case PKEY_KBLOB2PROTK2: { + struct pkey_kblob2pkey2 __user *utp = (void __user *) arg; + struct pkey_kblob2pkey2 ktp; + struct pkey_apqn *apqns = NULL; + u8 *kkey; + + if (copy_from_user(&ktp, utp, sizeof(ktp))) + return -EFAULT; + apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_keyblob2pkey2(apqns, ktp.apqn_entries, + kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc); + kfree(apqns); kfree(kkey); if (rc) break; @@ -1425,6 +1036,97 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_APQNS4K: { + struct pkey_apqns4key __user *uak = (void __user *) arg; + struct pkey_apqns4key kak; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + u8 *kkey; + + if (copy_from_user(&kak, uak, sizeof(kak))) + return -EFAULT; + nr_apqns = kak.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + kkey = _copy_key_from_user(kak.key, kak.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_apqns4key(kkey, kak.keylen, kak.flags, + apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4key()=%d\n", __func__, rc); + kfree(kkey); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kak.apqns) { + if (nr_apqns > kak.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kak.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kak.apqn_entries = nr_apqns; + if (copy_to_user(uak, &kak, sizeof(kak))) + rc = -EFAULT; + kfree(apqns); + break; + } + case PKEY_APQNS4KT: { + struct pkey_apqns4keytype __user *uat = (void __user *) arg; + struct pkey_apqns4keytype kat; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + + if (copy_from_user(&kat, uat, sizeof(kat))) + return -EFAULT; + nr_apqns = kat.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + rc = pkey_apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp, + kat.flags, apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4keytype()=%d\n", __func__, rc); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kat.apqns) { + if (nr_apqns > kat.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kat.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kat.apqn_entries = nr_apqns; + if (copy_to_user(uat, &kat, sizeof(kat))) + rc = -EFAULT; + kfree(apqns); + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY; @@ -1567,6 +1269,7 @@ static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, loff_t off, size_t count) { int rc; + struct pkey_seckey *seckey = (struct pkey_seckey *) buf; if (off != 0 || count < sizeof(struct secaeskeytoken)) return -EINVAL; @@ -1574,13 +1277,13 @@ static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, if (count < 2 * sizeof(struct secaeskeytoken)) return -EINVAL; - rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + rc = cca_genseckey(-1, -1, keytype, seckey->seckey); if (rc) return rc; if (is_xts) { - buf += sizeof(struct pkey_seckey); - rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + seckey++; + rc = cca_genseckey(-1, -1, keytype, seckey->seckey); if (rc) return rc; @@ -1716,7 +1419,6 @@ static int __init pkey_init(void) static void __exit pkey_exit(void) { misc_deregister(&pkey_dev); - mkvp_cache_free(); pkey_debug_exit(); } diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 0604b49a4d32..5c0f53c6dde7 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -1143,7 +1143,7 @@ int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, msleep(20); status = ap_tapq(apqn, NULL); } - WARN_ON_ONCE(retry <= 0); + WARN_ON_ONCE(retry2 <= 0); return 0; case AP_RESPONSE_RESET_IN_PROGRESS: case AP_RESPONSE_BUSY: diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1058b4b5cc1e..563801427fe4 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -35,6 +35,7 @@ #include "zcrypt_msgtype6.h" #include "zcrypt_msgtype50.h" +#include "zcrypt_ccamisc.h" /* * Module description. @@ -1160,6 +1161,34 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus) } EXPORT_SYMBOL(zcrypt_device_status_mask_ext); +int zcrypt_device_status_ext(int card, int queue, + struct zcrypt_device_status_ext *devstat) +{ + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + + memset(devstat, 0, sizeof(*devstat)); + + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (card == AP_QID_CARD(zq->queue->qid) && + queue == AP_QID_QUEUE(zq->queue->qid)) { + devstat->hwtype = zc->card->ap_dev.device_type; + devstat->functions = zc->card->functions >> 26; + devstat->qid = zq->queue->qid; + devstat->online = zq->online ? 0x01 : 0x00; + spin_unlock(&zcrypt_list_lock); + return 0; + } + } + } + spin_unlock(&zcrypt_list_lock); + + return -ENODEV; +} +EXPORT_SYMBOL(zcrypt_device_status_ext); + static void zcrypt_status_mask(char status[], size_t max_adapters) { struct zcrypt_card *zc; @@ -1874,6 +1903,7 @@ void __exit zcrypt_api_exit(void) misc_deregister(&zcrypt_misc_device); zcrypt_msgtype6_exit(); zcrypt_msgtype50_exit(); + zcrypt_ccamisc_exit(); zcrypt_debug_exit(); } diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index af67a768a3fc..2d3f2732344f 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -121,9 +121,6 @@ void zcrypt_card_get(struct zcrypt_card *); int zcrypt_card_put(struct zcrypt_card *); int zcrypt_card_register(struct zcrypt_card *); void zcrypt_card_unregister(struct zcrypt_card *); -struct zcrypt_card *zcrypt_card_get_best(unsigned int *, - unsigned int, unsigned int); -void zcrypt_card_put_best(struct zcrypt_card *, unsigned int); struct zcrypt_queue *zcrypt_queue_alloc(size_t); void zcrypt_queue_free(struct zcrypt_queue *); @@ -132,8 +129,6 @@ int zcrypt_queue_put(struct zcrypt_queue *); int zcrypt_queue_register(struct zcrypt_queue *); void zcrypt_queue_unregister(struct zcrypt_queue *); void zcrypt_queue_force_online(struct zcrypt_queue *, int); -struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int); -void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int); int zcrypt_rng_device_add(void); void zcrypt_rng_device_remove(void); @@ -145,5 +140,7 @@ int zcrypt_api_init(void); void zcrypt_api_exit(void); long zcrypt_send_cprb(struct ica_xcRB *xcRB); void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus); +int zcrypt_device_status_ext(int card, int queue, + struct zcrypt_device_status_ext *devstatus); #endif /* _ZCRYPT_API_H_ */ diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c new file mode 100644 index 000000000000..c1db64a2db21 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -0,0 +1,1765 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright IBM Corp. 2019 + * Author(s): Harald Freudenberger <freude@linux.ibm.com> + * Ingo Franzki <ifranzki@linux.ibm.com> + * + * Collection of CCA misc functions used by zcrypt and pkey + */ + +#define KMSG_COMPONENT "zcrypt" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <asm/zcrypt.h> +#include <asm/pkey.h> + +#include "ap_bus.h" +#include "zcrypt_api.h" +#include "zcrypt_debug.h" +#include "zcrypt_msgtype6.h" +#include "zcrypt_ccamisc.h" + +#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__) +#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__) +#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__) +#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__) + +/* Size of parameter block used for all cca requests/replies */ +#define PARMBSIZE 512 + +/* Size of vardata block used for some of the cca requests/replies */ +#define VARDATASIZE 4096 + +struct cca_info_list_entry { + struct list_head list; + u16 cardnr; + u16 domain; + struct cca_info info; +}; + +/* a list with cca_info_list_entry entries */ +static LIST_HEAD(cca_info_list); +static DEFINE_SPINLOCK(cca_info_list_lock); + +/* + * Simple check if the token is a valid CCA secure AES data key + * token. If keybitsize is given, the bitsize of the key is + * also checked. Returns 0 on success or errno value on failure. + */ +int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize) +{ + struct secaeskeytoken *t = (struct secaeskeytoken *) token; + +#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) + + if (t->type != TOKTYPE_CCA_INTERNAL) { + if (dbg) + DBF("%s token check failed, type 0x%02x != 0x%02x\n", + __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); + return -EINVAL; + } + if (t->version != TOKVER_CCA_AES) { + if (dbg) + DBF("%s token check failed, version 0x%02x != 0x%02x\n", + __func__, (int) t->version, TOKVER_CCA_AES); + return -EINVAL; + } + if (keybitsize > 0 && t->bitsize != keybitsize) { + if (dbg) + DBF("%s token check failed, bitsize %d != %d\n", + __func__, (int) t->bitsize, keybitsize); + return -EINVAL; + } + +#undef DBF + + return 0; +} +EXPORT_SYMBOL(cca_check_secaeskeytoken); + +/* + * Simple check if the token is a valid CCA secure AES cipher key + * token. If keybitsize is given, the bitsize of the key is + * also checked. If checkcpacfexport is enabled, the key is also + * checked for the export flag to allow CPACF export. + * Returns 0 on success or errno value on failure. + */ +int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize, + int checkcpacfexport) +{ + struct cipherkeytoken *t = (struct cipherkeytoken *) token; + bool keybitsizeok = true; + +#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) + + if (t->type != TOKTYPE_CCA_INTERNAL) { + if (dbg) + DBF("%s token check failed, type 0x%02x != 0x%02x\n", + __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); + return -EINVAL; + } + if (t->version != TOKVER_CCA_VLSC) { + if (dbg) + DBF("%s token check failed, version 0x%02x != 0x%02x\n", + __func__, (int) t->version, TOKVER_CCA_VLSC); + return -EINVAL; + } + if (t->algtype != 0x02) { + if (dbg) + DBF("%s token check failed, algtype 0x%02x != 0x02\n", + __func__, (int) t->algtype); + return -EINVAL; + } + if (t->keytype != 0x0001) { + if (dbg) + DBF("%s token check failed, keytype 0x%04x != 0x0001\n", + __func__, (int) t->keytype); + return -EINVAL; + } + if (t->plfver != 0x00 && t->plfver != 0x01) { + if (dbg) + DBF("%s token check failed, unknown plfver 0x%02x\n", + __func__, (int) t->plfver); + return -EINVAL; + } + if (t->wpllen != 512 && t->wpllen != 576 && t->wpllen != 640) { + if (dbg) + DBF("%s token check failed, unknown wpllen %d\n", + __func__, (int) t->wpllen); + return -EINVAL; + } + if (keybitsize > 0) { + switch (keybitsize) { + case 128: + if (t->wpllen != (t->plfver ? 640 : 512)) + keybitsizeok = false; + break; + case 192: + if (t->wpllen != (t->plfver ? 640 : 576)) + keybitsizeok = false; + break; + case 256: + if (t->wpllen != 640) + keybitsizeok = false; + break; + default: + keybitsizeok = false; + break; + } + if (!keybitsizeok) { + if (dbg) + DBF("%s token check failed, bitsize %d\n", + __func__, keybitsize); + return -EINVAL; + } + } + if (checkcpacfexport && !(t->kmf1 & KMF1_XPRT_CPAC)) { + if (dbg) + DBF("%s token check failed, XPRT_CPAC bit is 0\n", + __func__); + return -EINVAL; + } + +#undef DBF + + return 0; +} +EXPORT_SYMBOL(cca_check_secaescipherkey); + +/* + * Allocate consecutive memory for request CPRB, request param + * block, reply CPRB and reply param block and fill in values + * for the common fields. Returns 0 on success or errno value + * on failure. + */ +static int alloc_and_prep_cprbmem(size_t paramblen, + u8 **pcprbmem, + struct CPRBX **preqCPRB, + struct CPRBX **prepCPRB) +{ + u8 *cprbmem; + size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; + struct CPRBX *preqcblk, *prepcblk; + + /* + * allocate consecutive memory for request CPRB, request param + * block, reply CPRB and reply param block + */ + cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); + if (!cprbmem) + return -ENOMEM; + + preqcblk = (struct CPRBX *) cprbmem; + prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen); + + /* fill request cprb struct */ + preqcblk->cprb_len = sizeof(struct CPRBX); + preqcblk->cprb_ver_id = 0x02; + memcpy(preqcblk->func_id, "T2", 2); + preqcblk->rpl_msgbl = cprbplusparamblen; + if (paramblen) { + preqcblk->req_parmb = + ((u8 *) preqcblk) + sizeof(struct CPRBX); + preqcblk->rpl_parmb = + ((u8 *) prepcblk) + sizeof(struct CPRBX); + } + + *pcprbmem = cprbmem; + *preqCPRB = preqcblk; + *prepCPRB = prepcblk; + + return 0; +} + +/* + * Free the cprb memory allocated with the function above. + * If the scrub value is not zero, the memory is filled + * with zeros before freeing (useful if there was some + * clear key material in there). + */ +static void free_cprbmem(void *mem, size_t paramblen, int scrub) +{ + if (scrub) + memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); + kfree(mem); +} + +/* + * Helper function to prepare the xcrb struct + */ +static inline void prep_xcrb(struct ica_xcRB *pxcrb, + u16 cardnr, + struct CPRBX *preqcblk, + struct CPRBX *prepcblk) +{ + memset(pxcrb, 0, sizeof(*pxcrb)); + pxcrb->agent_ID = 0x4341; /* 'CA' */ + pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); + pxcrb->request_control_blk_length = + preqcblk->cprb_len + preqcblk->req_parml; + pxcrb->request_control_blk_addr = (void __user *) preqcblk; + pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; + pxcrb->reply_control_blk_addr = (void __user *) prepcblk; +} + +/* + * Helper function which calls zcrypt_send_cprb with + * memory management segment adjusted to kernel space + * so that the copy_from_user called within this + * function do in fact copy from kernel space. + */ +static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) +{ + int rc; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + rc = zcrypt_send_cprb(xcrb); + set_fs(old_fs); + + return rc; +} + +/* + * Generate (random) CCA AES DATA secure key. + */ +int cca_genseckey(u16 cardnr, u16 domain, + u32 keybitsize, u8 seckey[SECKEYBLOBSIZE]) +{ + int i, rc, keysize; + int seckeysize; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct kgreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv1 { + u16 len; + char key_form[8]; + char key_length[8]; + char key_type1[8]; + char key_type2[8]; + } lv1; + struct lv2 { + u16 len; + struct keyid { + u16 len; + u16 attr; + u8 data[SECKEYBLOBSIZE]; + } keyid[6]; + } lv2; + } __packed * preqparm; + struct kgrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 keyblocklen; + struct { + u16 toklen; + u16 tokattr; + u8 tok[0]; + /* ... some more data ... */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with KG request */ + preqparm = (struct kgreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "KG", 2); + preqparm->rule_array_len = sizeof(preqparm->rule_array_len); + preqparm->lv1.len = sizeof(struct lv1); + memcpy(preqparm->lv1.key_form, "OP ", 8); + switch (keybitsize) { + case PKEY_SIZE_AES_128: + case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ + keysize = 16; + memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); + break; + case PKEY_SIZE_AES_192: + case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ + keysize = 24; + memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); + break; + case PKEY_SIZE_AES_256: + case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ + keysize = 32; + memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); + break; + default: + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); + rc = -EINVAL; + goto out; + } + memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); + preqparm->lv2.len = sizeof(struct lv2); + for (i = 0; i < 6; i++) { + preqparm->lv2.keyid[i].len = sizeof(struct keyid); + preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); + } + preqcblk->req_parml = sizeof(struct kgreqparm); + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s secure key generate failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct kgrepparm *) prepcblk->rpl_parmb; + + /* check length of the returned secure key token */ + seckeysize = prepparm->lv3.keyblock.toklen + - sizeof(prepparm->lv3.keyblock.toklen) + - sizeof(prepparm->lv3.keyblock.tokattr); + if (seckeysize != SECKEYBLOBSIZE) { + DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); + rc = -EIO; + goto out; + } + + /* check secure key token */ + rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, + prepparm->lv3.keyblock.tok, 8*keysize); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated secure key token */ + memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_genseckey); + +/* + * Generate an CCA AES DATA secure key with given key value. + */ +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, + const u8 *clrkey, u8 seckey[SECKEYBLOBSIZE]) +{ + int rc, keysize, seckeysize; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct cmreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[8]; + struct lv1 { + u16 len; + u8 clrkey[0]; + } lv1; + struct lv2 { + u16 len; + struct keyid { + u16 len; + u16 attr; + u8 data[SECKEYBLOBSIZE]; + } keyid; + } lv2; + } __packed * preqparm; + struct lv2 *plv2; + struct cmrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 keyblocklen; + struct { + u16 toklen; + u16 tokattr; + u8 tok[0]; + /* ... some more data ... */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with CM request */ + preqparm = (struct cmreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "CM", 2); + memcpy(preqparm->rule_array, "AES ", 8); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); + switch (keybitsize) { + case PKEY_SIZE_AES_128: + case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ + keysize = 16; + break; + case PKEY_SIZE_AES_192: + case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ + keysize = 24; + break; + case PKEY_SIZE_AES_256: + case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ + keysize = 32; + break; + default: + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); + rc = -EINVAL; + goto out; + } + preqparm->lv1.len = sizeof(struct lv1) + keysize; + memcpy(preqparm->lv1.clrkey, clrkey, keysize); + plv2 = (struct lv2 *) (((u8 *) &preqparm->lv2) + keysize); + plv2->len = sizeof(struct lv2); + plv2->keyid.len = sizeof(struct keyid); + plv2->keyid.attr = 0x30; + preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s clear key import failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct cmrepparm *) prepcblk->rpl_parmb; + + /* check length of the returned secure key token */ + seckeysize = prepparm->lv3.keyblock.toklen + - sizeof(prepparm->lv3.keyblock.toklen) + - sizeof(prepparm->lv3.keyblock.tokattr); + if (seckeysize != SECKEYBLOBSIZE) { + DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); + rc = -EIO; + goto out; + } + + /* check secure key token */ + rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, + prepparm->lv3.keyblock.tok, 8*keysize); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated secure key token */ + if (seckey) + memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); + +out: + free_cprbmem(mem, PARMBSIZE, 1); + return rc; +} +EXPORT_SYMBOL(cca_clr2seckey); + +/* + * Derive proteced key from an CCA AES DATA secure key. + */ +int cca_sec2protkey(u16 cardnr, u16 domain, + const u8 seckey[SECKEYBLOBSIZE], + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct uskreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv1 { + u16 len; + u16 attr_len; + u16 attr_flags; + } lv1; + struct lv2 { + u16 len; + u16 attr_len; + u16 attr_flags; + u8 token[0]; /* cca secure key token */ + } lv2; + } __packed * preqparm; + struct uskrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 attr_len; + u16 attr_flags; + struct cpacfkeyblock { + u8 version; /* version of this struct */ + u8 flags[2]; + u8 algo; + u8 form; + u8 pad1[3]; + u16 len; + u8 key[64]; /* the key (len bytes) */ + u16 keyattrlen; + u8 keyattr[32]; + u8 pad2[1]; + u8 vptype; + u8 vp[32]; /* verification pattern */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with USK request */ + preqparm = (struct uskreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "US", 2); + preqparm->rule_array_len = sizeof(preqparm->rule_array_len); + preqparm->lv1.len = sizeof(struct lv1); + preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); + preqparm->lv1.attr_flags = 0x0001; + preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; + preqparm->lv2.attr_len = sizeof(struct lv2) + - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; + preqparm->lv2.attr_flags = 0x0000; + memcpy(preqparm->lv2.token, seckey, SECKEYBLOBSIZE); + preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + if (prepcblk->ccp_rscode != 0) { + DEBUG_WARN("%s unwrap secure key warning, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct uskrepparm *) prepcblk->rpl_parmb; + + /* check the returned keyblock */ + if (prepparm->lv3.keyblock.version != 0x01) { + DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->lv3.keyblock.version); + rc = -EIO; + goto out; + } + + /* copy the tanslated protected key */ + switch (prepparm->lv3.keyblock.len) { + case 16+32: + /* AES 128 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_128; + break; + case 24+32: + /* AES 192 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_192; + break; + case 32+32: + /* AES 256 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keylen %d\n", + __func__, prepparm->lv3.keyblock.len); + rc = -EIO; + goto out; + } + memcpy(protkey, prepparm->lv3.keyblock.key, prepparm->lv3.keyblock.len); + if (protkeylen) + *protkeylen = prepparm->lv3.keyblock.len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_sec2protkey); + +/* + * AES cipher key skeleton created with CSNBKTB2 with these flags: + * INTERNAL, NO-KEY, AES, CIPHER, ANY-MODE, NOEX-SYM, NOEXAASY, + * NOEXUASY, XPRTCPAC, NOEX-RAW, NOEX-DES, NOEX-AES, NOEX-RSA + * used by cca_gencipherkey() and cca_clr2cipherkey(). + */ +static const u8 aes_cipher_key_skeleton[] = { + 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x01, 0x02, 0xc0, 0x00, 0xff, + 0x00, 0x03, 0x08, 0xc8, 0x00, 0x00, 0x00, 0x00 }; +#define SIZEOF_SKELETON (sizeof(aes_cipher_key_skeleton)) + +/* + * Generate (random) CCA AES CIPHER secure key. + */ +int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + u8 *keybuf, size_t *keybufsize) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct gkreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[2*8]; + struct { + u16 len; + u8 key_type_1[8]; + u8 key_type_2[8]; + u16 clear_key_bit_len; + u16 key_name_1_len; + u16 key_name_2_len; + u16 user_data_1_len; + u16 user_data_2_len; + u8 key_name_1[0]; + u8 key_name_2[0]; + u8 user_data_1[0]; + u8 user_data_2[0]; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; + u8 kek_id_1[0]; + } tlv1; + struct { + u16 len; + u16 flag; + u8 kek_id_2[0]; + } tlv2; + struct { + u16 len; + u16 flag; + u8 gen_key_id_1[SIZEOF_SKELETON]; + } tlv3; + struct { + u16 len; + u16 flag; + u8 gen_key_id_1_label[0]; + } tlv4; + struct { + u16 len; + u16 flag; + u8 gen_key_id_2[0]; + } tlv5; + struct { + u16 len; + u16 flag; + u8 gen_key_id_2_label[0]; + } tlv6; + } kb; + } __packed * preqparm; + struct gkrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; + u8 gen_key[0]; /* 120-136 bytes */ + } tlv1; + } kb; + } __packed * prepparm; + struct cipherkeytoken *t; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + preqcblk->req_parml = sizeof(struct gkreqparm); + + /* prepare request param block with GK request */ + preqparm = (struct gkreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "GK", 2); + preqparm->rule_array_len = sizeof(uint16_t) + 2 * 8; + memcpy(preqparm->rule_array, "AES OP ", 2*8); + + /* prepare vud block */ + preqparm->vud.len = sizeof(preqparm->vud); + switch (keybitsize) { + case 128: + case 192: + case 256: + break; + default: + DEBUG_ERR( + "%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); + rc = -EINVAL; + goto out; + } + preqparm->vud.clear_key_bit_len = keybitsize; + memcpy(preqparm->vud.key_type_1, "TOKEN ", 8); + memset(preqparm->vud.key_type_2, ' ', sizeof(preqparm->vud.key_type_2)); + + /* prepare kb block */ + preqparm->kb.len = sizeof(preqparm->kb); + preqparm->kb.tlv1.len = sizeof(preqparm->kb.tlv1); + preqparm->kb.tlv1.flag = 0x0030; + preqparm->kb.tlv2.len = sizeof(preqparm->kb.tlv2); + preqparm->kb.tlv2.flag = 0x0030; + preqparm->kb.tlv3.len = sizeof(preqparm->kb.tlv3); + preqparm->kb.tlv3.flag = 0x0030; + memcpy(preqparm->kb.tlv3.gen_key_id_1, + aes_cipher_key_skeleton, SIZEOF_SKELETON); + preqparm->kb.tlv4.len = sizeof(preqparm->kb.tlv4); + preqparm->kb.tlv4.flag = 0x0030; + preqparm->kb.tlv5.len = sizeof(preqparm->kb.tlv5); + preqparm->kb.tlv5.flag = 0x0030; + preqparm->kb.tlv6.len = sizeof(preqparm->kb.tlv6); + preqparm->kb.tlv6.flag = 0x0030; + + /* patch the skeleton key token export flags inside the kb block */ + if (keygenflags) { + t = (struct cipherkeytoken *) preqparm->kb.tlv3.gen_key_id_1; + t->kmf1 |= (u16) (keygenflags & 0x0000FF00); + t->kmf1 &= (u16) ~(keygenflags & 0x000000FF); + } + + /* prepare xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s cipher key generate failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct gkrepparm *) prepcblk->rpl_parmb; + + /* do some plausibility checks on the key block */ + if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || + prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { + DEBUG_ERR("%s reply with invalid or unknown key block\n", + __func__); + rc = -EIO; + goto out; + } + + /* and some checks on the generated key */ + rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR, + prepparm->kb.tlv1.gen_key, + keybitsize, 1); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated vlsc key token */ + t = (struct cipherkeytoken *) prepparm->kb.tlv1.gen_key; + if (keybuf) { + if (*keybufsize >= t->len) + memcpy(keybuf, t, t->len); + else + rc = -EINVAL; + } + *keybufsize = t->len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_gencipherkey); + +/* + * Helper function, does a the CSNBKPI2 CPRB. + */ +static int _ip_cprb_helper(u16 cardnr, u16 domain, + const char *rule_array_1, + const char *rule_array_2, + const char *rule_array_3, + const u8 *clr_key_value, + int clr_key_bit_size, + u8 *key_token, + int *key_token_size) +{ + int rc, n; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct rule_array_block { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[0]; + } __packed * preq_ra_block; + struct vud_block { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0064 */ + u16 clr_key_bit_len; + } tlv1; + struct { + u16 len; + u16 flag; /* 0x0063 */ + u8 clr_key[0]; /* clear key value bytes */ + } tlv2; + } __packed * preq_vud_block; + struct key_block { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0030 */ + u8 key_token[0]; /* key skeleton */ + } tlv1; + } __packed * preq_key_block; + struct iprepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0030 */ + u8 key_token[0]; /* key token */ + } tlv1; + } kb; + } __packed * prepparm; + struct cipherkeytoken *t; + int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + preqcblk->req_parml = 0; + + /* prepare request param block with IP request */ + preq_ra_block = (struct rule_array_block *) preqcblk->req_parmb; + memcpy(preq_ra_block->subfunc_code, "IP", 2); + preq_ra_block->rule_array_len = sizeof(uint16_t) + 2 * 8; + memcpy(preq_ra_block->rule_array, rule_array_1, 8); + memcpy(preq_ra_block->rule_array + 8, rule_array_2, 8); + preqcblk->req_parml = sizeof(struct rule_array_block) + 2 * 8; + if (rule_array_3) { + preq_ra_block->rule_array_len += 8; + memcpy(preq_ra_block->rule_array + 16, rule_array_3, 8); + preqcblk->req_parml += 8; + } + + /* prepare vud block */ + preq_vud_block = (struct vud_block *) + (preqcblk->req_parmb + preqcblk->req_parml); + n = complete ? 0 : (clr_key_bit_size + 7) / 8; + preq_vud_block->len = sizeof(struct vud_block) + n; + preq_vud_block->tlv1.len = sizeof(preq_vud_block->tlv1); + preq_vud_block->tlv1.flag = 0x0064; + preq_vud_block->tlv1.clr_key_bit_len = complete ? 0 : clr_key_bit_size; + preq_vud_block->tlv2.len = sizeof(preq_vud_block->tlv2) + n; + preq_vud_block->tlv2.flag = 0x0063; + if (!complete) + memcpy(preq_vud_block->tlv2.clr_key, clr_key_value, n); + preqcblk->req_parml += preq_vud_block->len; + + /* prepare key block */ + preq_key_block = (struct key_block *) + (preqcblk->req_parmb + preqcblk->req_parml); + n = *key_token_size; + preq_key_block->len = sizeof(struct key_block) + n; + preq_key_block->tlv1.len = sizeof(preq_key_block->tlv1) + n; + preq_key_block->tlv1.flag = 0x0030; + memcpy(preq_key_block->tlv1.key_token, key_token, *key_token_size); + preqcblk->req_parml += preq_key_block->len; + + /* prepare xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s CSNBKPI2 failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct iprepparm *) prepcblk->rpl_parmb; + + /* do some plausibility checks on the key block */ + if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || + prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { + DEBUG_ERR("%s reply with invalid or unknown key block\n", + __func__); + rc = -EIO; + goto out; + } + + /* do not check the key here, it may be incomplete */ + + /* copy the vlsc key token back */ + t = (struct cipherkeytoken *) prepparm->kb.tlv1.key_token; + memcpy(key_token, t, t->len); + *key_token_size = t->len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} + +/* + * Build CCA AES CIPHER secure key with a given clear key value. + */ +int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, + const u8 *clrkey, u8 *keybuf, size_t *keybufsize) +{ + int rc; + u8 *token; + int tokensize; + u8 exorbuf[32]; + struct cipherkeytoken *t; + + /* fill exorbuf with random data */ + get_random_bytes(exorbuf, sizeof(exorbuf)); + + /* allocate space for the key token to build */ + token = kmalloc(MAXCCAVLSCTOKENSIZE, GFP_KERNEL); + if (!token) + return -ENOMEM; + + /* prepare the token with the key skeleton */ + tokensize = SIZEOF_SKELETON; + memcpy(token, aes_cipher_key_skeleton, tokensize); + + /* patch the skeleton key token export flags */ + if (keygenflags) { + t = (struct cipherkeytoken *) token; + t->kmf1 |= (u16) (keygenflags & 0x0000FF00); + t->kmf1 &= (u16) ~(keygenflags & 0x000000FF); + } + + /* + * Do the key import with the clear key value in 4 steps: + * 1/4 FIRST import with only random data + * 2/4 EXOR the clear key + * 3/4 EXOR the very same random data again + * 4/4 COMPLETE the secure cipher key import + */ + rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART", + exorbuf, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, + clrkey, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, + exorbuf, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL, + NULL, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + + /* copy the generated key token */ + if (keybuf) { + if (tokensize > *keybufsize) + rc = -EINVAL; + else + memcpy(keybuf, token, tokensize); + } + *keybufsize = tokensize; + +out: + kfree(token); + return rc; +} +EXPORT_SYMBOL(cca_clr2cipherkey); + +/* + * Derive proteced key from CCA AES cipher secure key. + */ +int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct aureqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + u8 rule_array[8]; + struct { + u16 len; + u16 tk_blob_len; + u16 tk_blob_tag; + u8 tk_blob[66]; + } vud; + struct { + u16 len; + u16 cca_key_token_len; + u16 cca_key_token_flags; + u8 cca_key_token[0]; // 64 or more + } kb; + } __packed * preqparm; + struct aurepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + u16 sublen; + u16 tag; + struct cpacfkeyblock { + u8 version; /* version of this struct */ + u8 flags[2]; + u8 algo; + u8 form; + u8 pad1[3]; + u16 keylen; + u8 key[64]; /* the key (keylen bytes) */ + u16 keyattrlen; + u8 keyattr[32]; + u8 pad2[1]; + u8 vptype; + u8 vp[32]; /* verification pattern */ + } ckb; + } vud; + struct { + u16 len; + } kb; + } __packed * prepparm; + int keytoklen = ((struct cipherkeytoken *)ckey)->len; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with AU request */ + preqparm = (struct aureqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "AU", 2); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + + sizeof(preqparm->rule_array); + memcpy(preqparm->rule_array, "EXPT-SK ", 8); + /* vud, tk blob */ + preqparm->vud.len = sizeof(preqparm->vud); + preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) + + 2 * sizeof(uint16_t); + preqparm->vud.tk_blob_tag = 0x00C2; + /* kb, cca token */ + preqparm->kb.len = keytoklen + 3 * sizeof(uint16_t); + preqparm->kb.cca_key_token_len = keytoklen + 2 * sizeof(uint16_t); + memcpy(preqparm->kb.cca_key_token, ckey, keytoklen); + /* now fill length of param block into cprb */ + preqcblk->req_parml = sizeof(struct aureqparm) + keytoklen; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + if (prepcblk->ccp_rscode != 0) { + DEBUG_WARN( + "%s unwrap secure key warning, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct aurepparm *) prepcblk->rpl_parmb; + + /* check the returned keyblock */ + if (prepparm->vud.ckb.version != 0x01) { + DEBUG_ERR( + "%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->vud.ckb.version); + rc = -EIO; + goto out; + } + if (prepparm->vud.ckb.algo != 0x02) { + DEBUG_ERR( + "%s reply param keyblock algo mismatch 0x%02x != 0x02\n", + __func__, (int) prepparm->vud.ckb.algo); + rc = -EIO; + goto out; + } + + /* copy the translated protected key */ + switch (prepparm->vud.ckb.keylen) { + case 16+32: + /* AES 128 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_128; + break; + case 24+32: + /* AES 192 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_192; + break; + case 32+32: + /* AES 256 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keylen %d\n", + __func__, prepparm->vud.ckb.keylen); + rc = -EIO; + goto out; + } + memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); + if (protkeylen) + *protkeylen = prepparm->vud.ckb.keylen; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_cipher2protkey); + +/* + * query cryptographic facility from CCA adapter + */ +int cca_query_crypto_facility(u16 cardnr, u16 domain, + const char *keyword, + u8 *rarray, size_t *rarraylen, + u8 *varray, size_t *varraylen) +{ + int rc; + u16 len; + u8 *mem, *ptr; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct fqreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[8]; + struct lv1 { + u16 len; + u8 data[VARDATASIZE]; + } lv1; + u16 dummylen; + } __packed * preqparm; + size_t parmbsize = sizeof(struct fqreqparm); + struct fqrepparm { + u8 subfunc_code[2]; + u8 lvdata[0]; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with FQ request */ + preqparm = (struct fqreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "FQ", 2); + memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); + preqparm->lv1.len = sizeof(preqparm->lv1); + preqparm->dummylen = sizeof(preqparm->dummylen); + preqcblk->req_parml = parmbsize; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct fqrepparm *) prepcblk->rpl_parmb; + ptr = prepparm->lvdata; + + /* check and possibly copy reply rule array */ + len = *((u16 *) ptr); + if (len > sizeof(u16)) { + ptr += sizeof(u16); + len -= sizeof(u16); + if (rarray && rarraylen && *rarraylen > 0) { + *rarraylen = (len > *rarraylen ? *rarraylen : len); + memcpy(rarray, ptr, *rarraylen); + } + ptr += len; + } + /* check and possible copy reply var array */ + len = *((u16 *) ptr); + if (len > sizeof(u16)) { + ptr += sizeof(u16); + len -= sizeof(u16); + if (varray && varraylen && *varraylen > 0) { + *varraylen = (len > *varraylen ? *varraylen : len); + memcpy(varray, ptr, *varraylen); + } + ptr += len; + } + +out: + free_cprbmem(mem, parmbsize, 0); + return rc; +} +EXPORT_SYMBOL(cca_query_crypto_facility); + +static int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci) +{ + int rc = -ENOENT; + struct cca_info_list_entry *ptr; + + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { + if (ptr->cardnr == cardnr && ptr->domain == domain) { + memcpy(ci, &ptr->info, sizeof(*ci)); + rc = 0; + break; + } + } + spin_unlock_bh(&cca_info_list_lock); + + return rc; +} + +static void cca_info_cache_update(u16 cardnr, u16 domain, + const struct cca_info *ci) +{ + int found = 0; + struct cca_info_list_entry *ptr; + + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { + if (ptr->cardnr == cardnr && + ptr->domain == domain) { + memcpy(&ptr->info, ci, sizeof(*ci)); + found = 1; + break; + } + } + if (!found) { + ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); + if (!ptr) { + spin_unlock_bh(&cca_info_list_lock); + return; + } + ptr->cardnr = cardnr; + ptr->domain = domain; + memcpy(&ptr->info, ci, sizeof(*ci)); + list_add(&ptr->list, &cca_info_list); + } + spin_unlock_bh(&cca_info_list_lock); +} + +static void cca_info_cache_scrub(u16 cardnr, u16 domain) +{ + struct cca_info_list_entry *ptr; + + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { + if (ptr->cardnr == cardnr && + ptr->domain == domain) { + list_del(&ptr->list); + kfree(ptr); + break; + } + } + spin_unlock_bh(&cca_info_list_lock); +} + +static void __exit mkvp_cache_free(void) +{ + struct cca_info_list_entry *ptr, *pnext; + + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) { + list_del(&ptr->list); + kfree(ptr); + } + spin_unlock_bh(&cca_info_list_lock); +} + +/* + * Fetch cca_info values via query_crypto_facility from adapter. + */ +static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) +{ + int rc, found = 0; + size_t rlen, vlen; + u8 *rarray, *varray, *pg; + struct zcrypt_device_status_ext devstat; + + memset(ci, 0, sizeof(*ci)); + + /* get first info from zcrypt device driver about this apqn */ + rc = zcrypt_device_status_ext(cardnr, domain, &devstat); + if (rc) + return rc; + ci->hwtype = devstat.hwtype; + + /* prep page for rule array and var array use */ + pg = (u8 *) __get_free_page(GFP_KERNEL); + if (!pg) + return -ENOMEM; + rarray = pg; + varray = pg + PAGE_SIZE/2; + rlen = vlen = PAGE_SIZE/2; + + /* QF for this card/domain */ + rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", + rarray, &rlen, varray, &vlen); + if (rc == 0 && rlen >= 10*8 && vlen >= 204) { + memcpy(ci->serial, rarray, 8); + ci->new_mk_state = (char) rarray[7*8]; + ci->cur_mk_state = (char) rarray[8*8]; + ci->old_mk_state = (char) rarray[9*8]; + if (ci->old_mk_state == '2') + memcpy(&ci->old_mkvp, varray + 172, 8); + if (ci->cur_mk_state == '2') + memcpy(&ci->cur_mkvp, varray + 184, 8); + if (ci->new_mk_state == '3') + memcpy(&ci->new_mkvp, varray + 196, 8); + found = 1; + } + + free_page((unsigned long) pg); + + return found ? 0 : -ENOENT; +} + +/* + * Fetch cca information about a CCA queue. + */ +int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify) +{ + int rc; + + rc = cca_info_cache_fetch(card, dom, ci); + if (rc || verify) { + rc = fetch_cca_info(card, dom, ci); + if (rc == 0) + cca_info_cache_update(card, dom, ci); + } + + return rc; +} +EXPORT_SYMBOL(cca_get_info); + +/* + * Search for a matching crypto card based on the + * Master Key Verification Pattern given. + */ +static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, + int verify, int minhwtype) +{ + struct zcrypt_device_status_ext *device_status; + u16 card, dom; + struct cca_info ci; + int i, rc, oi = -1; + + /* mkvp must not be zero, minhwtype needs to be >= 0 */ + if (mkvp == 0 || minhwtype < 0) + return -EINVAL; + + /* fetch status of all crypto cards */ + device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + zcrypt_device_status_mask_ext(device_status); + + /* walk through all crypto cards */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + if (device_status[i].online && + device_status[i].functions & 0x04) { + /* enabled CCA card, check current mkvp from cache */ + if (cca_info_cache_fetch(card, dom, &ci) == 0 && + ci.hwtype >= minhwtype && + ci.cur_mk_state == '2' && + ci.cur_mkvp == mkvp) { + if (!verify) + break; + /* verify: refresh card info */ + if (fetch_cca_info(card, dom, &ci) == 0) { + cca_info_cache_update(card, dom, &ci); + if (ci.hwtype >= minhwtype && + ci.cur_mk_state == '2' && + ci.cur_mkvp == mkvp) + break; + } + } + } else { + /* Card is offline and/or not a CCA card. */ + /* del mkvp entry from cache if it exists */ + cca_info_cache_scrub(card, dom); + } + } + if (i >= MAX_ZDEV_ENTRIES_EXT) { + /* nothing found, so this time without cache */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + if (!(device_status[i].online && + device_status[i].functions & 0x04)) + continue; + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + /* fresh fetch mkvp from adapter */ + if (fetch_cca_info(card, dom, &ci) == 0) { + cca_info_cache_update(card, dom, &ci); + if (ci.hwtype >= minhwtype && + ci.cur_mk_state == '2' && + ci.cur_mkvp == mkvp) + break; + if (ci.hwtype >= minhwtype && + ci.old_mk_state == '2' && + ci.old_mkvp == mkvp && + oi < 0) + oi = i; + } + } + if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { + /* old mkvp matched, use this card then */ + card = AP_QID_CARD(device_status[oi].qid); + dom = AP_QID_QUEUE(device_status[oi].qid); + } + } + if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { + if (pcardnr) + *pcardnr = card; + if (pdomain) + *pdomain = dom; + rc = (i < MAX_ZDEV_ENTRIES_EXT ? 0 : 1); + } else + rc = -ENODEV; + + kfree(device_status); + return rc; +} + +/* + * Search for a matching crypto card based on the Master Key + * Verification Pattern provided inside a secure key token. + */ +int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) +{ + u64 mkvp; + int minhwtype = 0; + const struct keytoken_header *hdr = (struct keytoken_header *) key; + + if (hdr->type != TOKTYPE_CCA_INTERNAL) + return -EINVAL; + + switch (hdr->version) { + case TOKVER_CCA_AES: + mkvp = ((struct secaeskeytoken *)key)->mkvp; + break; + case TOKVER_CCA_VLSC: + mkvp = ((struct cipherkeytoken *)key)->mkvp0; + minhwtype = AP_DEVICE_TYPE_CEX6; + break; + default: + return -EINVAL; + } + + return findcard(mkvp, pcardnr, pdomain, verify, minhwtype); +} +EXPORT_SYMBOL(cca_findcard); + +int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, + int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify) +{ + struct zcrypt_device_status_ext *device_status; + int i, n, card, dom, curmatch, oldmatch, rc = 0; + struct cca_info ci; + + *apqns = NULL; + *nr_apqns = 0; + + /* fetch status of all crypto cards */ + device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + zcrypt_device_status_mask_ext(device_status); + + /* loop two times: first gather eligible apqns, then store them */ + while (1) { + n = 0; + /* walk through all the crypto cards */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + /* check online state */ + if (!device_status[i].online) + continue; + /* check for cca functions */ + if (!(device_status[i].functions & 0x04)) + continue; + /* check cardnr */ + if (cardnr != 0xFFFF && card != cardnr) + continue; + /* check domain */ + if (domain != 0xFFFF && dom != domain) + continue; + /* get cca info on this apqn */ + if (cca_get_info(card, dom, &ci, verify)) + continue; + /* current master key needs to be valid */ + if (ci.cur_mk_state != '2') + continue; + /* check min hardware type */ + if (minhwtype > 0 && minhwtype > ci.hwtype) + continue; + if (cur_mkvp || old_mkvp) { + /* check mkvps */ + curmatch = oldmatch = 0; + if (cur_mkvp && cur_mkvp == ci.cur_mkvp) + curmatch = 1; + if (old_mkvp && ci.old_mk_state == '2' && + old_mkvp == ci.old_mkvp) + oldmatch = 1; + if ((cur_mkvp || old_mkvp) && + (curmatch + oldmatch < 1)) + continue; + } + /* apqn passed all filtering criterons */ + if (*apqns && n < *nr_apqns) + (*apqns)[n] = (((u16)card) << 16) | ((u16) dom); + n++; + } + /* loop 2nd time: array has been filled */ + if (*apqns) + break; + /* loop 1st time: have # of eligible apqns in n */ + if (!n) { + rc = -ENODEV; /* no eligible apqns found */ + break; + } + *nr_apqns = n; + /* allocate array to store n apqns into */ + *apqns = kmalloc_array(n, sizeof(u32), GFP_KERNEL); + if (!*apqns) { + rc = -ENOMEM; + break; + } + verify = 0; + } + + kfree(device_status); + return rc; +} +EXPORT_SYMBOL(cca_findcard2); + +void __exit zcrypt_ccamisc_exit(void) +{ + mkvp_cache_free(); +} diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h new file mode 100644 index 000000000000..77b6cc7b8f82 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright IBM Corp. 2019 + * Author(s): Harald Freudenberger <freude@linux.ibm.com> + * Ingo Franzki <ifranzki@linux.ibm.com> + * + * Collection of CCA misc functions used by zcrypt and pkey + */ + +#ifndef _ZCRYPT_CCAMISC_H_ +#define _ZCRYPT_CCAMISC_H_ + +#include <asm/zcrypt.h> +#include <asm/pkey.h> + +/* Key token types */ +#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */ +#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */ + +/* For TOKTYPE_NON_CCA: */ +#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */ + +/* For TOKTYPE_CCA_INTERNAL: */ +#define TOKVER_CCA_AES 0x04 /* CCA AES key token */ +#define TOKVER_CCA_VLSC 0x05 /* var length sym cipher key token */ + +/* Max size of a cca variable length cipher key token */ +#define MAXCCAVLSCTOKENSIZE 725 + +/* header part of a CCA key token */ +struct keytoken_header { + u8 type; /* one of the TOKTYPE values */ + u8 res0[1]; + u16 len; /* vlsc token: total length in bytes */ + u8 version; /* one of the TOKVER values */ + u8 res1[3]; +} __packed; + +/* inside view of a CCA secure key token (only type 0x01 version 0x04) */ +struct secaeskeytoken { + u8 type; /* 0x01 for internal key token */ + u8 res0[3]; + u8 version; /* should be 0x04 */ + u8 res1[1]; + u8 flag; /* key flags */ + u8 res2[1]; + u64 mkvp; /* master key verification pattern */ + u8 key[32]; /* key value (encrypted) */ + u8 cv[8]; /* control vector */ + u16 bitsize; /* key bit size */ + u16 keysize; /* key byte size */ + u8 tvv[4]; /* token validation value */ +} __packed; + +/* inside view of a variable length symmetric cipher AES key token */ +struct cipherkeytoken { + u8 type; /* 0x01 for internal key token */ + u8 res0[1]; + u16 len; /* total key token length in bytes */ + u8 version; /* should be 0x05 */ + u8 res1[3]; + u8 kms; /* key material state, 0x03 means wrapped with MK */ + u8 kvpt; /* key verification pattern type, should be 0x01 */ + u64 mkvp0; /* master key verification pattern, lo part */ + u64 mkvp1; /* master key verification pattern, hi part (unused) */ + u8 eskwm; /* encrypted section key wrapping method */ + u8 hashalg; /* hash algorithmus used for wrapping key */ + u8 plfver; /* pay load format version */ + u8 res2[1]; + u8 adsver; /* associated data section version */ + u8 res3[1]; + u16 adslen; /* associated data section length */ + u8 kllen; /* optional key label length */ + u8 ieaslen; /* optional extended associated data length */ + u8 uadlen; /* optional user definable associated data length */ + u8 res4[1]; + u16 wpllen; /* wrapped payload length in bits: */ + /* plfver 0x00 0x01 */ + /* AES-128 512 640 */ + /* AES-192 576 640 */ + /* AES-256 640 640 */ + u8 res5[1]; + u8 algtype; /* 0x02 for AES cipher */ + u16 keytype; /* 0x0001 for 'cipher' */ + u8 kufc; /* key usage field count */ + u16 kuf1; /* key usage field 1 */ + u16 kuf2; /* key usage field 2 */ + u8 kmfc; /* key management field count */ + u16 kmf1; /* key management field 1 */ + u16 kmf2; /* key management field 2 */ + u16 kmf3; /* key management field 3 */ + u8 vdata[0]; /* variable part data follows */ +} __packed; + +/* Some defines for the CCA AES cipherkeytoken kmf1 field */ +#define KMF1_XPRT_SYM 0x8000 +#define KMF1_XPRT_UASY 0x4000 +#define KMF1_XPRT_AASY 0x2000 +#define KMF1_XPRT_RAW 0x1000 +#define KMF1_XPRT_CPAC 0x0800 +#define KMF1_XPRT_DES 0x0080 +#define KMF1_XPRT_AES 0x0040 +#define KMF1_XPRT_RSA 0x0008 + +/* + * Simple check if the token is a valid CCA secure AES data key + * token. If keybitsize is given, the bitsize of the key is + * also checked. Returns 0 on success or errno value on failure. + */ +int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize); + +/* + * Simple check if the token is a valid CCA secure AES cipher key + * token. If keybitsize is given, the bitsize of the key is + * also checked. If checkcpacfexport is enabled, the key is also + * checked for the export flag to allow CPACF export. + * Returns 0 on success or errno value on failure. + */ +int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize, + int checkcpacfexport); + +/* + * Generate (random) CCA AES DATA secure key. + */ +int cca_genseckey(u16 cardnr, u16 domain, u32 keybitsize, u8 *seckey); + +/* + * Generate CCA AES DATA secure key with given clear key value. + */ +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, + const u8 *clrkey, u8 *seckey); + +/* + * Derive proteced key from an CCA AES DATA secure key. + */ +int cca_sec2protkey(u16 cardnr, u16 domain, + const u8 seckey[SECKEYBLOBSIZE], + u8 *protkey, u32 *protkeylen, u32 *protkeytype); + +/* + * Generate (random) CCA AES CIPHER secure key. + */ +int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + u8 *keybuf, size_t *keybufsize); + +/* + * Derive proteced key from CCA AES cipher secure key. + */ +int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, + u8 *protkey, u32 *protkeylen, u32 *protkeytype); + +/* + * Build CCA AES CIPHER secure key with a given clear key value. + */ +int cca_clr2cipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + const u8 *clrkey, u8 *keybuf, size_t *keybufsize); + +/* + * Query cryptographic facility from CCA adapter + */ +int cca_query_crypto_facility(u16 cardnr, u16 domain, + const char *keyword, + u8 *rarray, size_t *rarraylen, + u8 *varray, size_t *varraylen); + +/* + * Search for a matching crypto card based on the Master Key + * Verification Pattern provided inside a secure key. + * Works with CCA AES data and cipher keys. + * Returns < 0 on failure, 0 if CURRENT MKVP matches and + * 1 if OLD MKVP matches. + */ +int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify); + +/* + * Build a list of cca apqns meeting the following constrains: + * - apqn is online and is in fact a CCA apqn + * - if cardnr is not FFFF only apqns with this cardnr + * - if domain is not FFFF only apqns with this domainnr + * - if minhwtype > 0 only apqns with hwtype >= minhwtype + * - if cur_mkvp != 0 only apqns where cur_mkvp == mkvp + * - if old_mkvp != 0 only apqns where old_mkvp == mkvp + * - if verify is enabled and a cur_mkvp and/or old_mkvp + * value is given, then refetch the cca_info and make sure the current + * cur_mkvp or old_mkvp values of the apqn are used. + * The array of apqn entries is allocated with kmalloc and returned in *apqns; + * the number of apqns stored into the list is returned in *nr_apqns. One apqn + * entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and + * may be casted to struct pkey_apqn. The return value is either 0 for success + * or a negative errno value. If no apqn meeting the criterias is found, + * -ENODEV is returned. + */ +int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, + int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify); + +/* struct to hold info for each CCA queue */ +struct cca_info { + int hwtype; /* one of the defined AP_DEVICE_TYPE_* */ + char new_mk_state; /* '1' empty, '2' partially full, '3' full */ + char cur_mk_state; /* '1' invalid, '2' valid */ + char old_mk_state; /* '1' invalid, '2' valid */ + u64 new_mkvp; /* truncated sha256 hash of new master key */ + u64 cur_mkvp; /* truncated sha256 hash of current master key */ + u64 old_mkvp; /* truncated sha256 hash of old master key */ + char serial[9]; /* serial number string (8 ascii numbers + 0x00) */ +}; + +/* + * Fetch cca information about an CCA queue. + */ +int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify); + +void zcrypt_ccamisc_exit(void); + +#endif /* _ZCRYPT_CCAMISC_H_ */ diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 582ffa7e0f18..f58d8dec19dc 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -18,6 +18,7 @@ #include "zcrypt_msgtype50.h" #include "zcrypt_error.h" #include "zcrypt_cex4.h" +#include "zcrypt_ccamisc.h" #define CEX4A_MIN_MOD_SIZE 1 /* 8 bits */ #define CEX4A_MAX_MOD_SIZE_2K 256 /* 2048 bits */ @@ -65,6 +66,85 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = { MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids); +/* + * CCA card addditional device attributes + */ +static ssize_t serialnr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cca_info ci; + struct ap_card *ac = to_ap_card(dev); + struct zcrypt_card *zc = ac->private; + + memset(&ci, 0, sizeof(ci)); + + if (ap_domain_index >= 0) + cca_get_info(ac->id, ap_domain_index, &ci, zc->online); + + return snprintf(buf, PAGE_SIZE, "%s\n", ci.serial); +} +static DEVICE_ATTR_RO(serialnr); + +static struct attribute *cca_card_attrs[] = { + &dev_attr_serialnr.attr, + NULL, +}; + +static const struct attribute_group cca_card_attr_group = { + .attrs = cca_card_attrs, +}; + +/* + * CCA queue addditional device attributes + */ +static ssize_t mkvps_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int n = 0; + struct cca_info ci; + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + static const char * const cao_state[] = { "invalid", "valid" }; + static const char * const new_state[] = { "empty", "partial", "full" }; + + memset(&ci, 0, sizeof(ci)); + + cca_get_info(AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + &ci, zq->online); + + if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3') + n = snprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", + new_state[ci.new_mk_state - '1'], ci.new_mkvp); + else + n = snprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); + + if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2') + n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: %s 0x%016llx\n", + cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp); + else + n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); + + if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2') + n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: %s 0x%016llx\n", + cao_state[ci.old_mk_state - '1'], ci.old_mkvp); + else + n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); + + return n; +} +static DEVICE_ATTR_RO(mkvps); + +static struct attribute *cca_queue_attrs[] = { + &dev_attr_mkvps.attr, + NULL, +}; + +static const struct attribute_group cca_queue_attr_group = { + .attrs = cca_queue_attrs, +}; + /** * Probe function for CEX4/CEX5/CEX6 card device. It always * accepts the AP device since the bus_match already checked @@ -194,8 +274,17 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) if (rc) { ac->private = NULL; zcrypt_card_free(zc); + goto out; } + if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + rc = sysfs_create_group(&ap_dev->device.kobj, + &cca_card_attr_group); + if (rc) + zcrypt_card_unregister(zc); + } + +out: return rc; } @@ -205,8 +294,11 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) */ static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) { - struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc = ac->private; + if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) + sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_group); if (zc) zcrypt_card_unregister(zc); } @@ -251,6 +343,7 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) } else { return -ENODEV; } + zq->queue = aq; zq->online = 1; atomic_set(&zq->load, 0); @@ -261,8 +354,17 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) if (rc) { aq->private = NULL; zcrypt_queue_free(zq); + goto out; + } + + if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + rc = sysfs_create_group(&ap_dev->device.kobj, + &cca_queue_attr_group); + if (rc) + zcrypt_queue_unregister(zq); } +out: return rc; } @@ -275,6 +377,8 @@ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) struct ap_queue *aq = to_ap_queue(&ap_dev->device); struct zcrypt_queue *zq = aq->private; + if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) + sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_group); if (zq) zcrypt_queue_unregister(zq); } |