From 7fffdcfe8cae3f6fd003cd2f5f70bd11fc6bc2bf Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Mon, 8 Jun 2026 13:15:30 +0200 Subject: [PATCH] zkey: Remove the use of AF_ALG for calculating key verification patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using AF_ALG to calculate key verification patterns, transform the key blob into a protected key and calculate the key verification patterns with CAPCF calls. The 'zkey-cryptsetup convert' command also calculates key verification patterns from clear keys. Support this, too. Reviewed-by: Finn Callies Signed-off-by: Ingo Franzki Signed-off-by: Jan Höppner --- include/lib/zt_common.h | 3 + zkey/Makefile | 7 +- zkey/cpacf.c | 603 ++++++++++++++++++++++++++++++++++++++++ zkey/cpacf.h | 324 +++++++++++++++++++++ zkey/ekmfweb/Makefile | 7 +- zkey/kmip/Makefile | 7 +- zkey/pkey.c | 360 ++++++++++-------------- zkey/pkey.h | 8 + 8 files changed, 1098 insertions(+), 221 deletions(-) create mode 100644 zkey/cpacf.c create mode 100644 zkey/cpacf.h diff --git a/include/lib/zt_common.h b/include/lib/zt_common.h index f8257e5d..c5363fe2 100644 --- a/include/lib/zt_common.h +++ b/include/lib/zt_common.h @@ -102,6 +102,9 @@ _x > _y ? _x : _y; \ }) +#ifdef __SIZEOF_INT128__ +typedef unsigned __int128 u128 __aligned(16); +#endif typedef unsigned long long u64; typedef signed long long s64; typedef unsigned int u32; diff --git a/zkey/Makefile b/zkey/Makefile index eae1c37d..4a58b9af 100644 --- a/zkey/Makefile +++ b/zkey/Makefile @@ -98,7 +98,7 @@ zkey-cryptsetup-skip-openssl: all: $(BUILD_TARGETS) $(SUB_DIRS) zkey.o: check-dep-zkey zkey.c pkey.h cca.h ep11.h misc.h -pkey.o: pkey.c pkey.h cca.h ep11.h utils.h +pkey.o: pkey.c pkey.h cca.h ep11.h utils.h cpacf.h cca.o: cca.c cca.h pkey.h ep11.h utils.h ep11.o: ep11.c ep11.h pkey.h cca.h utils.h utils.o: utils.h pkey.h cca.h ep11.h @@ -109,14 +109,15 @@ zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h cca.h \ ep11.h misc.h utils.h kms.o: kms.c kms.h kms-plugin.h utils.h pkey.h pvsecrets.o: pvsecrets.h +cpacf.o: cpacf.c cpacf.h pkey.h zkey: LDLIBS = -ldl -lcrypto zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o kms.o \ - pvsecrets.o $(libs) + pvsecrets.o cpacf.o $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c -lcrypto -zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o ep11.o utils.o $(libs) +zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o ep11.o utils.o cpacf.o $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ install-common: diff --git a/zkey/cpacf.c b/zkey/cpacf.c new file mode 100644 index 00000000..d1a52825 --- /dev/null +++ b/zkey/cpacf.c @@ -0,0 +1,603 @@ +/* + * zkey - Generate, re-encipher, and validate secure keys + * + * Copyright IBM Corp. 2018, 2024 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "lib/util_libc.h" + +#include "cpacf.h" +#include "pkey.h" + +#define MASK64(n) (1ULL << (63 - (n) % 64)) +#define OFF64(n) ((n) / 64) + +/* + * Checks if the specified MSA level is available. + * + * @param[in] msa the MSA level to query + * + * @returns true if available, false otherwise + */ +static bool cpacf_msa(int msa) +{ + bool ret; + + unsigned long hwcap, facility_list_nmemb; + u64 *facility_list = NULL, tmp; + + hwcap = getauxval(AT_HWCAP); + if ((hwcap & HWCAP_S390_STFLE) == 0) + return false; + + facility_list_nmemb = stfle(&tmp, 1); + if (facility_list_nmemb > UINT8_MAX) + return false; + + facility_list = util_zalloc(facility_list_nmemb * sizeof(u64)); + stfle(facility_list, facility_list_nmemb); + + ret = (facility_list_nmemb >= (unsigned long)OFF64(msa) + 1 && + (facility_list[OFF64(msa)] & MASK64(msa)) != 0); + + free(facility_list); + return ret; +} + +/* + * Checks if the KMC instruction and the specified KMC function code is + * supported. + * + * @param[in] fc the function code to query + * + * @returns true if supported, false otherwise + */ +static bool cpacf_query_kmc(int fc) +{ + u64 status_word[2] = { 0 }; + + if (!cpacf_msa(MSA)) + return false; + + cpacf_kmc(CPACF_KM_QUERY, &status_word, NULL, NULL, 0, NULL); + + return (status_word[OFF64(fc)] & MASK64(fc)) != 0; +} + +/* + * Checks if the KM instruction and the specified KM function code is + * supported. + * + * @param[in] fc the function code to query + * + * @returns true if supported, false otherwise + */ +static bool cpacf_query_km(int fc) +{ + u64 status_word[2] = { 0 }; + + if (!cpacf_msa(MSA)) + return false; + + cpacf_km(CPACF_KMC_QUERY, &status_word, NULL, NULL, 0, NULL); + + return (status_word[OFF64(fc)] & MASK64(fc)) != 0; +} + +/* + * Checks if the KMAC instruction and the specified KMAC function code is + * supported. + * + * @param[in] fc the function code to query + * + * @returns true if supported, false otherwise + */ +static bool cpacf_query_kmac(int fc) +{ + u64 status_word[2] = { 0 }; + + if (!cpacf_msa(MSA)) + return false; + + cpacf_kmac(CPACF_KMAC_QUERY, &status_word, NULL, 0); + + return (status_word[OFF64(fc)] & MASK64(fc)) != 0; +} + +/* + * Checks if the PCC instruction and the specified PCC function code is + * supported. + * + * @param[in] fc the function code to query + * + * @returns true if supported, false otherwise + */ +static bool cpacf_query_pcc(int fc) +{ + u64 status_word[2] = { 0 }; + + if (!cpacf_msa(MSA4)) + return false; + + cpacf_pcc(CPACF_PCC_QUERY, &status_word); + + return (status_word[OFF64(fc)] & MASK64(fc)) != 0; +} + +/* + * Performs a one-shot AES-ECB encryption using a clear or protected key. + * + * @param[in] key the clear or protected key + * @param[in] key_size the size of the clear or protected key + * @param[in] in the clear data to encrypt + * @param[in] out the output buffer to write the encrypted data to + * @param[in] size the size of the data to encrypt, and also the size + * of the output buffer. + * @param[in] pkey_type the type of the protected key (PKEY_KEYTYPE_nnn) + * or 0 if it is a clear key. + * + * @returns 0 on success, a negative errno in case of an error + */ +int cpacf_aes_cbc_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type) +{ + union { + struct cpacf_kmc_aes_128_param aes_128; + struct cpacf_kmc_aes_192_param aes_192; + struct cpacf_kmc_aes_256_param aes_256; + struct cpacf_kmc_enc_aes_128_param aes_128_enc; + struct cpacf_kmc_enc_aes_192_param aes_192_enc; + struct cpacf_kmc_enc_aes_256_param aes_256_enc; + } kmc_param = { 0 }; + int fc, cc, rc = 0; + + switch (pkey_type) { + case 0: + /* clear key */ + switch (key_size) { + case 16: + fc = CPACF_KMC_AES_128; + memcpy(kmc_param.aes_128.key, key, + sizeof(kmc_param.aes_128.key)); + break; + case 24: + fc = CPACF_KMC_AES_192; + memcpy(kmc_param.aes_192.key, key, + sizeof(kmc_param.aes_192.key)); + break; + case 32: + fc = CPACF_KMC_AES_256; + memcpy(kmc_param.aes_256.key, key, + sizeof(kmc_param.aes_256.key)); + break; + default: + rc = -EINVAL; + goto out; + } + break; + case PKEY_KEYTYPE_AES_128: + fc = CPACF_KMC_ENCRYPTED_AES_128; + + if (key_size != sizeof(kmc_param.aes_128_enc.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(kmc_param.aes_128_enc.protkey, key, + sizeof(kmc_param.aes_128_enc.protkey)); + break; + case PKEY_KEYTYPE_AES_192: + fc = CPACF_KMC_ENCRYPTED_AES_192; + + if (key_size != sizeof(kmc_param.aes_192_enc.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(kmc_param.aes_192_enc.protkey, key, + sizeof(kmc_param.aes_192_enc.protkey)); + break; + case PKEY_KEYTYPE_AES_256: + fc = CPACF_KMC_ENCRYPTED_AES_256; + + if (key_size != sizeof(kmc_param.aes_256_enc.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(kmc_param.aes_256_enc.protkey, key, + sizeof(kmc_param.aes_256_enc.protkey)); + break; + default: + rc = -EINVAL; + goto out; + } + + if (!cpacf_query_kmc(fc)) { + rc = -ENODEV; + goto out; + } + + cc = cpacf_kmc(fc, &kmc_param, out, in, size, NULL); + if (cc == 1) /* WKVP mismatch */ + rc = -EAGAIN; + else if (cc != 0) + rc = -EIO; + +out: + OPENSSL_cleanse(&kmc_param, sizeof(kmc_param)); + return rc; +} + +/* + * Performs a one-shot AES-XTS encryption using a clear or protected key. + * + * @param[in] key the clear or protected key + * @param[in] key_size the size of the clear or protected key + * @param[in] in the clear data to encrypt + * @param[in] out the output buffer to write the encrypted data to + * @param[in] size the size of the data to encrypt, and also the size + * of the output buffer. + * @param[in] pkey_type the type of the protected key (PKEY_KEYTYPE_nnn) + * or 0 if it is a clear key. + * + * @returns 0 on success, a negative errno in case of an error + */ +int cpacf_aes_xts_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type) +{ + union { + struct cpacf_pcc_xts_aes_128_param aes_xts_128; + struct cpacf_pcc_xts_aes_256_param aes_xts_256; + struct cpacf_pcc_enc_xts_aes_128_param aes_xts_enc_128; + struct cpacf_pcc_enc_xts_aes_256_param aes_xts_enc_256; + } pcc_param = { 0 }; + union { + struct cpacf_km_xts_aes_128_param aes_xts_128; + struct cpacf_km_xts_aes_256_param aes_xts_256; + struct cpacf_km_enc_xts_aes_128_param aes_xts_enc_128; + struct cpacf_km_enc_xts_aes_256_param aes_xts_enc_256; + } km_param = { 0 }; + int pcc_fc, km_fc, cc, rc = 0; + + switch (pkey_type) { + case 0: + /* clear key */ + switch (key_size) { + case 32: + pcc_fc = CPACF_PCC_XTS_AES_128; + memcpy(pcc_param.aes_xts_128.key, + key + sizeof(pcc_param.aes_xts_128.key), + sizeof(pcc_param.aes_xts_128.key)); + break; + case 64: + pcc_fc = CPACF_PCC_XTS_AES_256; + memcpy(pcc_param.aes_xts_256.key, + key + sizeof(pcc_param.aes_xts_256.key), + sizeof(pcc_param.aes_xts_256.key)); + break; + default: + rc = -EINVAL; + goto out; + } + break; + case PKEY_KEYTYPE_AES_128: + pcc_fc = CPACF_PCC_XTS_ENCRYPTED_AES_128; + + if (key_size != 2 * sizeof(pcc_param.aes_xts_enc_128.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(pcc_param.aes_xts_enc_128.protkey, + key + sizeof(pcc_param.aes_xts_enc_128.protkey), + sizeof(pcc_param.aes_xts_enc_128.protkey)); + break; + case PKEY_KEYTYPE_AES_256: + pcc_fc = CPACF_PCC_XTS_ENCRYPTED_AES_256; + + if (key_size != 2 * sizeof(pcc_param.aes_xts_enc_256.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(pcc_param.aes_xts_enc_256.protkey, + key + sizeof(pcc_param.aes_xts_enc_256.protkey), + sizeof(pcc_param.aes_xts_enc_256.protkey)); + break; + default: + rc = -EINVAL; + goto out; + } + + if (!cpacf_query_pcc(pcc_fc)) { + rc = -ENODEV; + goto out; + } + + cc = cpacf_pcc(pcc_fc, &pcc_param); + if (cc == 1) /* WKVP mismatch */ + rc = -EAGAIN; + else if (cc != 0) + rc = -EIO; + if (rc != 0) + goto out; + + switch (pkey_type) { + case 0: + /* clear key */ + switch (key_size) { + case 32: + km_fc = CPACF_KM_XTS_AES_128; + memcpy(km_param.aes_xts_128.key, key, + sizeof(km_param.aes_xts_128.key)); + memcpy(km_param.aes_xts_128.xtsparam, + pcc_param.aes_xts_128.xtsparams, + sizeof(km_param.aes_xts_128.xtsparam)); + break; + case 64: + km_fc = CPACF_KM_XTS_AES_256; + memcpy(km_param.aes_xts_256.key, key, + sizeof(km_param.aes_xts_256.key)); + memcpy(km_param.aes_xts_256.xtsparam, + pcc_param.aes_xts_256.xtsparams, + sizeof(km_param.aes_xts_256.xtsparam)); + break; + default: + rc = -EINVAL; + goto out; + } + break; + case PKEY_KEYTYPE_AES_128: + km_fc = CPACF_KM_XTS_ENCRYPTED_AES_128; + memcpy(km_param.aes_xts_enc_128.protkey, key, + sizeof(km_param.aes_xts_enc_128.protkey)); + memcpy(km_param.aes_xts_enc_128.xtsparam, + pcc_param.aes_xts_enc_128.xtsparams, + sizeof(km_param.aes_xts_enc_128.xtsparam)); + break; + case PKEY_KEYTYPE_AES_256: + km_fc = CPACF_KM_XTS_ENCRYPTED_AES_256; + memcpy(km_param.aes_xts_enc_256.protkey, key, + sizeof(km_param.aes_xts_enc_256.protkey)); + memcpy(km_param.aes_xts_enc_256.xtsparam, + pcc_param.aes_xts_enc_256.xtsparams, + sizeof(km_param.aes_xts_enc_256.xtsparam)); + break; + default: + rc = -EINVAL; + goto out; + } + + if (!cpacf_query_km(km_fc)) { + rc = -ENODEV; + goto out; + } + + cc = cpacf_km(km_fc, &km_param, out, in, size, NULL); + if (cc == 1) /* WKVP mismatch */ + rc = -EAGAIN; + else if (cc != 0) + rc = -EIO; + +out: + OPENSSL_cleanse(&pcc_param, sizeof(pcc_param)); + OPENSSL_cleanse(&km_param, sizeof(km_param)); + return rc; +} + +/* + * Performs a one-shot AES-XTS encryption using a Full-XTS protected key + * + * @param[in] key the protected key + * @param[in] key_size the size of the protected key + * @param[in] in the clear data to encrypt + * @param[in] out the output buffer to write the encrypted data to + * @param[in] size the size of the data to encrypt, and also the size + * of the output buffer. + * @param[in] pkey_type the type of the protected key (PKEY_KEYTYPE_nnn). + * + * @returns 0 on success, a negative errno in case of an error + */ +int cpacf_aes_xts_full_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type) +{ + union { + struct cpacf_km_xts_full_aes_128_param aes_128; + struct cpacf_km_xts_full_aes_256_param aes_256; + } km_param = { 0 }; + int fc, cc, rc = 0; + + switch (pkey_type) { + case PKEY_KEYTYPE_AES_XTS_128: + fc = CPACF_KM_FXTS_ENCRYPTED_AES_128; + + if (key_size != sizeof(km_param.aes_128.protkey) + + sizeof(km_param.aes_128.wkvp)) { + rc = -EINVAL; + goto out; + } + + memcpy(km_param.aes_128.protkey, key, + sizeof(km_param.aes_128.protkey)); + km_param.aes_128.nap[0] = 0x01; + memcpy(km_param.aes_128.wkvp, + key + sizeof(km_param.aes_128.protkey), + sizeof(km_param.aes_128.wkvp)); + break; + case PKEY_KEYTYPE_AES_XTS_256: + fc = CPACF_KM_FXTS_ENCRYPTED_AES_256; + + if (key_size != sizeof(km_param.aes_256.protkey) + + sizeof(km_param.aes_256.wkvp)) { + rc = -EINVAL; + goto out; + } + + memcpy(km_param.aes_256.protkey, key, + sizeof(km_param.aes_256.protkey)); + km_param.aes_256.nap[0] = 0x01; + memcpy(km_param.aes_256.wkvp, + key + sizeof(km_param.aes_256.protkey), + sizeof(km_param.aes_256.wkvp)); + break; + default: + rc = -EINVAL; + goto out; + } + + if (!cpacf_query_km(fc)) { + rc = -ENODEV; + goto out; + } + + cc = cpacf_km(fc, &km_param, out, in, size, NULL); + if (cc == 1) /* WKVP mismatch */ + rc = -EAGAIN; + else if (cc != 0) + rc = -EIO; + +out: + OPENSSL_cleanse(&km_param, sizeof(km_param)); + return rc; +} + +/* + * Performs a one-shot SHA-HMAC operation using a clear or protected key. + * + * @param[in] key the clear or protected key + * @param[in] key_size the size of the clear or protected key + * @param[in] in the clear data to mac + * @param[in] in_size the size of the data to mac + * @param[in] mac the output buffer to write the mac to + * @param[in] mac_size the size of the mac buffer + * @param[in] pkey_type the type of the protected key (PKEY_KEYTYPE_nnn) + * or 0 if it is a clear key. + * + * @returns 0 on success, a negative errno in case of an error + */ +int cpacf_hmac_sha(const u8 *key, size_t key_size, + const u8 *in, size_t in_size, + u8 *mac, size_t mac_size, + int pkey_type) +{ + union { + struct cpacf_kmac_hmac_224_256_param hmac_256; + struct cpacf_kmac_hmac_384_512_param hmac_512; + struct cpacf_kmac_enc_hmac_224_256_param hmac_256_enc; + struct cpacf_kmac_enc_hmac_384_512_param hmac_512_enc; + } kmac_param = { 0 }; + int fc, cc, rc = 0; + + switch (pkey_type) { + case 0: + /* clear key */ + switch (key_size) { + case 64: + fc = CPACF_KMAC_HMAC_SHA_256; + memcpy(kmac_param.hmac_256.key, key, + sizeof(kmac_param.hmac_256.key)); + kmac_param.hmac_256.imbl = in_size * 8; + break; + case 128: + fc = CPACF_KMAC_HMAC_SHA_512; + memcpy(kmac_param.hmac_512.key, key, + sizeof(kmac_param.hmac_512.key)); + kmac_param.hmac_512.imbl = in_size * 8; + break; + default: + rc = -EINVAL; + goto out; + } + break; + case PKEY_KEYTYPE_HMAC_512: + fc = CPACF_KMAC_HMAC_ENCRYPTED_SHA_256; + + if (key_size != sizeof(kmac_param.hmac_256_enc.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(kmac_param.hmac_256_enc.protkey, key, + sizeof(kmac_param.hmac_256_enc.protkey)); + kmac_param.hmac_256_enc.imbl = in_size * 8; + break; + case PKEY_KEYTYPE_HMAC_1024: + fc = CPACF_KMAC_HMAC_ENCRYPTED_SHA_512; + + if (key_size != sizeof(kmac_param.hmac_512_enc.protkey)) { + rc = -EINVAL; + goto out; + } + + memcpy(kmac_param.hmac_512_enc.protkey, key, + sizeof(kmac_param.hmac_512_enc.protkey)); + kmac_param.hmac_512_enc.imbl = in_size * 8; + break; + default: + rc = -EINVAL; + goto out; + } + + if (!cpacf_query_kmac(fc)) { + rc = -ENODEV; + goto out; + } + + cc = cpacf_kmac(fc, &kmac_param, in, in_size); + if (cc == 1) /* WKVP mismatch */ + rc = -EAGAIN; + else if (cc != 0) + rc = -EIO; + if (rc != 0) + goto out; + + switch (pkey_type) { + case 0: + /* clear key */ + switch (key_size) { + case 64: + memcpy(mac, kmac_param.hmac_256.h, + MIN(mac_size, sizeof(kmac_param.hmac_256.h))); + break; + case 128: + memcpy(mac, kmac_param.hmac_512.h, + MIN(mac_size, sizeof(kmac_param.hmac_512.h))); + break; + default: + rc = -EINVAL; + goto out; + } + break; + case PKEY_KEYTYPE_HMAC_512: + memcpy(mac, kmac_param.hmac_256_enc.h, + MIN(mac_size, sizeof(kmac_param.hmac_256_enc.h))); + break; + case PKEY_KEYTYPE_HMAC_1024: + memcpy(mac, kmac_param.hmac_512_enc.h, + MIN(mac_size, sizeof(kmac_param.hmac_512_enc.h))); + break; + default: + rc = -EINVAL; + goto out; + } + +out: + OPENSSL_cleanse(&kmac_param, sizeof(kmac_param)); + return rc; +} diff --git a/zkey/cpacf.h b/zkey/cpacf.h new file mode 100644 index 00000000..35642693 --- /dev/null +++ b/zkey/cpacf.h @@ -0,0 +1,324 @@ +/* + * zkey - Generate, re-encipher, and validate secure keys + * + * This header file defines the interface to the pkey kernel module. + * It defines a set of IOCTL commands with its associated structures. + * + * Copyright IBM Corp. 2017, 2024 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef CPACF_H +#define CPACF_H + +#include "lib/zt_common.h" + +int cpacf_aes_cbc_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type); +int cpacf_aes_xts_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type); +int cpacf_aes_xts_full_enc(const u8 *key, size_t key_size, + const u8 *in, u8 *out, size_t size, + int pkey_type); +int cpacf_hmac_sha(const u8 *key, size_t key_size, + const u8 *in, size_t in_size, + u8 *mac, size_t mac_size, + int pkey_type); + +#define MSA 17 /* message-security-assist */ +#define MSA4 77 /* message-security-assist extension 4 */ + +/* STFLE (store facility list extended) */ + +static inline unsigned long stfle(u64 flist[], u8 nmemb) +{ + register unsigned long r0 __asm__("0") = (unsigned long)nmemb - 1; + + __asm__ volatile( + ".insn s,%[opc]<<16,0(%[flist])" + : "+d" (r0) + : [flist] "a" (flist), [opc] "i" (0xb2b0) + : "memory", "cc" + ); + + return r0 + 1; +} + +/* KM */ + +/* Function codes */ +#define CPACF_KM_QUERY 0 +#define CPACF_KM_XTS_AES_128 50 +#define CPACF_KM_XTS_AES_256 52 +#define CPACF_KM_XTS_ENCRYPTED_AES_128 58 +#define CPACF_KM_XTS_ENCRYPTED_AES_256 60 +#define CPACF_KM_FXTS_ENCRYPTED_AES_128 90 +#define CPACF_KM_FXTS_ENCRYPTED_AES_256 92 + +struct cpacf_km_xts_aes_128_param { + u8 key[16]; + u8 xtsparam[16]; +}; + +struct cpacf_km_xts_aes_256_param { + u8 key[32]; + u8 xtsparam[16]; +}; + +struct cpacf_km_enc_xts_aes_128_param { + u8 protkey[48]; /* WKa(K)|WKaVP */ + u8 xtsparam[16]; +}; + +struct cpacf_km_enc_xts_aes_256_param { + u8 protkey[64]; /* WKa(K)|WKaVP */ + u8 xtsparam[16]; +}; + +struct cpacf_km_xts_full_aes_128_param { + u8 protkey[32]; /* WKa(K) */ + u8 tweak[16]; + u8 nap[16]; + u8 wkvp[32]; /* WKaVP */ +}; + +struct cpacf_km_xts_full_aes_256_param { + u8 protkey[64]; /* WKa(K) */ + u8 tweak[16]; + u8 nap[16]; + u8 wkvp[32]; /* WKaVP */ +}; + +static inline int cpacf_km(unsigned long fc, void *param, u8 *out, + const u8 *in, unsigned long inlen, + unsigned long *bytes_processed) +{ + register unsigned long r0 __asm__("0") = (unsigned long)fc; + register unsigned long r1 __asm__("1") = (unsigned long)param; + register unsigned long r2 __asm__("2") = (unsigned long)in; + register unsigned long r3 __asm__("3") = (unsigned long)inlen; + register unsigned long r4 __asm__("4") = (unsigned long)out; + u8 cc; + + __asm__ volatile( + "0: .insn rre,%[opc] << 16,%[out],%[in]\n" + " brc 1,0b\n" /* handle partial completion */ + " ipm %[cc]\n" + " srl %[cc],28\n" + : [in] "+a" (r2), [inlen] "+d" (r3), [out] "+a" (r4), + [cc] "=d" (cc) + : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92e) + : "cc", "memory" + ); + + if (bytes_processed != NULL) + *bytes_processed = fc ? inlen - r3 : r3; + + return cc; +} + +/* KMC */ + +/* Function codes */ +#define CPACF_KMC_QUERY 0 +#define CPACF_KMC_AES_128 18 +#define CPACF_KMC_AES_192 19 +#define CPACF_KMC_AES_256 20 +#define CPACF_KMC_ENCRYPTED_AES_128 26 +#define CPACF_KMC_ENCRYPTED_AES_192 27 +#define CPACF_KMC_ENCRYPTED_AES_256 28 + +struct cpacf_kmc_aes_128_param { + u8 cv[16]; + u8 key[16]; +}; + +struct cpacf_kmc_aes_192_param { + u8 cv[16]; + u8 key[24]; +}; + +struct cpacf_kmc_aes_256_param { + u8 cv[16]; + u8 key[32]; +}; + +struct cpacf_kmc_enc_aes_128_param { + u8 cv[16]; + u8 protkey[48]; /* WKa(K)|WKaVP */ +}; + +struct cpacf_kmc_enc_aes_192_param { + u8 cv[16]; + u8 protkey[56]; /* WKa(K)|WKaVP */ +}; + +struct cpacf_kmc_enc_aes_256_param { + u8 cv[16]; + u8 protkey[64]; /* WKa(K)|WKaVP */ +}; + +static inline int cpacf_kmc(unsigned long fc, void *param, u8 *out, + const u8 *in, long inlen, + unsigned long *bytes_processed) +{ + register unsigned long r0 __asm__("0") = (unsigned long)fc; + register unsigned long r1 __asm__("1") = (unsigned long)param; + register unsigned long r2 __asm__("2") = (unsigned long)in; + register unsigned long r3 __asm__("3") = (unsigned long)inlen; + register unsigned long r4 __asm__("4") = (unsigned long)out; + u8 cc; + + __asm__ volatile( + "0: .insn rre,%[opc] << 16,%[out],%[in]\n" + " brc 1,0b\n" /* handle partial completion */ + " ipm %[cc]\n" + " srl %[cc],28\n" + : [in] "+a" (r2), [inlen] "+d" (r3), [out] "+a" (r4), + [cc] "=d" (cc) + : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92f) + : "cc", "memory" + ); + + if (bytes_processed != NULL) + *bytes_processed = fc ? inlen - r3 : r3; + + return cc; +} + +/* KMAC */ + +/* Function codes */ +#define CPACF_KMAC_QUERY 0 +#define CPACF_KMAC_HMAC_SHA_256 113 +#define CPACF_KMAC_HMAC_SHA_512 115 +#define CPACF_KMAC_HMAC_ENCRYPTED_SHA_256 121 +#define CPACF_KMAC_HMAC_ENCRYPTED_SHA_512 123 + +/* Flags */ +#define CPACF_KMAC_IKP 0x8000 +#define CPACF_KMAC_IIMP 0x4000 +#define CPACF_KMAC_CCUP 0x2000 + +struct cpacf_kmac_hmac_224_256_param { + u32 h[8]; + u64 imbl; + unsigned char key[64]; +}; + +struct cpacf_kmac_hmac_384_512_param { + u64 h[8]; +#ifdef __SIZEOF_INT128__ + u128 imbl; +#else + u64 imblhi; + u64 imbl; +#endif + unsigned char key[128]; +}; + +struct cpacf_kmac_enc_hmac_224_256_param { + u32 h[8]; + u64 imbl; + unsigned char protkey[96]; /* WKa(K)|WKaVP */ +}; + +struct cpacf_kmac_enc_hmac_384_512_param { + u64 h[8]; +#ifdef __SIZEOF_INT128__ + u128 imbl; +#else + u64 imblhi; + u64 imbl; +#endif + unsigned char protkey[160]; /* WKa(K)|WKaVP */ +}; + +static inline int cpacf_kmac(unsigned long fc, void *param, const u8 *in, + unsigned long inlen) +{ + register unsigned long r0 __asm__("0") = (unsigned long)fc; + register unsigned long r1 __asm__("1") = (unsigned long)param; + register unsigned long r2 __asm__("2") = (unsigned long)in; + register unsigned long r3 __asm__("3") = (unsigned long)inlen; + u8 cc; + + __asm__ volatile( + "0: .insn rre,%[opc] << 16,0,%[in]\n" + " brc 1,0b\n" /* handle partial completion */ + " ipm %[cc]\n" + " srl %[cc],28\n" + : [in] "+a" (r2), [inlen] "+d" (r3), [cc] "=d" (cc) + : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb91e) + : "cc", "memory" + ); + + return cc; +} + +/* PCC */ + +/* Function codes */ +#define CPACF_PCC_QUERY 0 +#define CPACF_PCC_XTS_AES_128 50 +#define CPACF_PCC_XTS_AES_256 52 +#define CPACF_PCC_XTS_ENCRYPTED_AES_128 58 +#define CPACF_PCC_XTS_ENCRYPTED_AES_256 60 + +struct cpacf_pcc_xts_aes_128_param { + u8 key[16]; + u8 i[16]; + u8 j[16]; + u8 t[16]; + u8 xtsparams[16]; +}; + +struct cpacf_pcc_xts_aes_256_param { + u8 key[32]; + u8 i[16]; + u8 j[16]; + u8 t[16]; + u8 xtsparams[16]; +}; + +struct cpacf_pcc_enc_xts_aes_128_param { + u8 protkey[48]; /* WKa(K)|WKaVP */ + u8 i[16]; + u8 j[16]; + u8 t[16]; + u8 xtsparams[16]; +}; + +struct cpacf_pcc_enc_xts_aes_256_param { + u8 protkey[64]; /* WKa(K)|WKaVP */ + u8 i[16]; + u8 j[16]; + u8 t[16]; + u8 xtsparams[16]; +}; + +/* PCC (perform cryptographic computation) */ +static inline int cpacf_pcc(unsigned long fc, void *param) +{ + register unsigned long r0 __asm__("0") = (unsigned long)fc; + register unsigned long r1 __asm__("1") = (unsigned long)param; + u8 cc; + + __asm__ volatile( + "0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */ + " brc 1,0b\n" /* handle partial completion */ + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=d" (cc) + : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92c) + : "cc", "memory" + ); + + return cc; +} + +#endif diff --git a/zkey/ekmfweb/Makefile b/zkey/ekmfweb/Makefile index 450cff72..008d7453 100644 --- a/zkey/ekmfweb/Makefile +++ b/zkey/ekmfweb/Makefile @@ -17,7 +17,7 @@ plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h properties.o: ../properties.c ../properties.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ -pkey.o: ../pkey.c ../pkey.h ../cca.h ../ep11.h ../utils.h +pkey.o: ../pkey.c ../pkey.h ../cca.h ../ep11.h ../utils.h ../cpacf.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ cca.o: ../cca.c ../cca.h ../pkey.h ../ep11.h ../utils.h @@ -29,12 +29,15 @@ ep11.o: ../ep11.c ../ep11.h ../pkey.h ../cca.h ../utils.h utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ +cpacf.o: ../cpacf.c ../cpacf.h ../pkey.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + zkey-ekmfweb.so: ALL_CFLAGS += -fPIC zkey-ekmfweb.so: LDLIBS = -L$(rootdir)/libekmfweb -lekmfweb -ldl -lcrypto zkey-ekmfweb.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-ekmfweb.map \ -Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-ekmfweb.so.$(VERM) zkey-ekmfweb.so: zkey-ekmfweb.o plugin-utils.o properties.o pkey.o cca.o \ - ep11.o utils.o $(libs) + ep11.o utils.o cpacf.o $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ install-libekmfweb.dep: diff --git a/zkey/kmip/Makefile b/zkey/kmip/Makefile index 5c21b586..171ec1d6 100644 --- a/zkey/kmip/Makefile +++ b/zkey/kmip/Makefile @@ -18,7 +18,7 @@ plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h properties.o: ../properties.c ../properties.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ -pkey.o: ../pkey.c ../pkey.h ../cca.h ../ep11.h ../utils.h ../kms-plugin.h +pkey.o: ../pkey.c ../pkey.h ../cca.h ../ep11.h ../utils.h ../cpacf.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ cca.o: ../cca.c ../cca.h ../pkey.h ../ep11.h ../utils.h ../properties.h ../kms-plugin.h @@ -30,12 +30,15 @@ ep11.o: ../ep11.c ../ep11.h ../pkey.h ../cca.h ../utils.h ../kms-plugin.h utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h ../kms-plugin.h $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ +cpacf.o: ../cpacf.c ../cpacf.h ../pkey.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + zkey-kmip.so: ALL_CFLAGS += -fPIC zkey-kmip.so: LDLIBS = -L$(rootdir)/libkmipclient -lkmipclient -ldl -lcrypto zkey-kmip.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-kmip.map \ -Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-kmip.so.$(VERM) zkey-kmip.so: zkey-kmip.o plugin-utils.o properties.o pkey.o cca.o ep11.o \ - utils.o profiles.o $(libs) + utils.o profiles.o cpacf.o $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ install-libkmipclient.dep: diff --git a/zkey/pkey.c b/zkey/pkey.c index 26a4bcbe..2b2e41c4 100644 --- a/zkey/pkey.c +++ b/zkey/pkey.c @@ -11,16 +11,16 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include +#include +#include + #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" @@ -28,13 +28,7 @@ #include "pkey.h" #include "pvsecrets.h" #include "utils.h" - -#ifndef AF_ALG -#define AF_ALG 38 -#endif -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif +#include "cpacf.h" #define pr_verbose(verbose, fmt...) do { \ if (verbose) \ @@ -48,6 +42,8 @@ #define INITIAL_APQN_ENTRIES 16 +#define MAX_WKVP_RETRY_COUNT 1000 + /** * Opens the pkey device and returns its file descriptor. * @@ -1576,7 +1572,7 @@ out: /** * Generate a key verification pattern of a secure AES key by encrypting the all - * zero message with the secure key using the AF_ALG interface + * zero message with the secure key * * @param[in] pkey_fd the pkey file descriptor * @param[in] key the secure key token @@ -1595,31 +1591,19 @@ int generate_aes_key_verification_pattern(int pkey_fd, const char *cipher, bool verbose) { - int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0; - char null_msg[ENC_ZERO_LEN]; - char enc_zero[ENC_ZERO_LEN]; - struct af_alg_iv *alg_iv; - struct cmsghdr *header; - uint32_t *type; - ssize_t len; + u8 protkey[MAX(MAX_AES_PROTKEYSIZE * 2, MAX_XTSFULL_PROTKEYSIZE)]; + size_t protkey_size = sizeof(protkey); + u8 null_msg[ENC_ZERO_LEN] = { 0 }; + u8 enc_zero[ENC_ZERO_LEN]; + bool securekey, xts; + int pkeytype = 0; + int count = 0; size_t i; + int rc; - struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "skcipher", - }; - struct iovec iov = { - .iov_base = (void *)null_msg, - .iov_len = sizeof(null_msg), - }; - int iv_msg_size = CMSG_SPACE(sizeof(*alg_iv) + PAES_BLOCK_SIZE); - char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size]; - struct msghdr msg = { - .msg_control = buffer, - .msg_controllen = sizeof(buffer), - .msg_iov = &iov, - .msg_iovlen = 1, - }; + util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); + util_assert(key != NULL, "Internal error: key is NULL"); + util_assert(vp != NULL, "Internal error: vp is NULL"); if (vp_len < VERIFICATION_PATTERN_LEN) { rc = -EMSGSIZE; @@ -1627,102 +1611,68 @@ int generate_aes_key_verification_pattern(int pkey_fd, } if (cipher != NULL) { - util_strlcpy((char *)sa.salg_name, cipher, - sizeof(sa.salg_name)); - } else { - snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)", - is_xts_key(key, key_size) ? "xts" : "cbc"); - } - - tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); - if (tfmfd < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to open an AF_ALG socket"); - goto out; - } - - if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to bind the AF_ALG socket, " - "salg_name='%s' ", sa.salg_name); - goto out; - } - -retry_setkey: - if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, - key_size) < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to set the key: %s", - strerror(-rc)); - - /* - * After a master key change, it can happen that the setkey - * operation returns EINVAL or EAGAIN, although the key is - * valid. This is a temporary situation and the operation will - * succeed, once the firmware has completed some internal - * processing related with the master key change. - * Delay 1 second and retry up to 10 times. - */ - if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) { - pr_verbose(verbose, "Retrying after 1 second..."); - retry_count++; - sleep(1); - goto retry_setkey; + if (strcmp(cipher, "cbc(aes)") == 0) { + rc = cpacf_aes_cbc_enc(key, key_size, + null_msg, enc_zero, + sizeof(null_msg), 0); + } else if (strcmp(cipher, "xts(aes)") == 0) { + rc = cpacf_aes_xts_enc(key, key_size, + null_msg, enc_zero, + sizeof(null_msg), 0); + } else { + pr_verbose(verbose, "Invalid clear key cipher '%s'", + cipher); + rc = -EINVAL; + goto out; } - goto out; - } - rc = 0; + } else { + securekey = is_secure_key(key, key_size); + xts = securekey ? is_xts_key(key, key_size) : false; - opfd = accept(tfmfd, NULL, NULL); - if (opfd < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to accept on the AF_ALG socket"); - goto out; + do { + rc = pkey_kblob2protk(pkey_fd, (u8 *)key, key_size, + protkey, &protkey_size, &pkeytype, + verbose); + if (rc != 0) + goto out; + + switch (pkeytype) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_192: + case PKEY_KEYTYPE_AES_256: + if (xts) + rc = cpacf_aes_xts_enc(protkey, + protkey_size, + null_msg, + enc_zero, + sizeof(null_msg), + pkeytype); + else + rc = cpacf_aes_cbc_enc(protkey, + protkey_size, + null_msg, + enc_zero, + sizeof(null_msg), + pkeytype); + break; + case PKEY_KEYTYPE_AES_XTS_128: + case PKEY_KEYTYPE_AES_XTS_256: + rc = cpacf_aes_xts_full_enc(protkey, + protkey_size, + null_msg, enc_zero, + sizeof(null_msg), + pkeytype); + break; + default: + rc = -EINVAL; + goto out; + } + + } while (rc == -EAGAIN && count++ < MAX_WKVP_RETRY_COUNT); } - memset(null_msg, 0, sizeof(null_msg)); - memset(buffer, 0, sizeof(buffer)); - - header = CMSG_FIRSTHDR(&msg); - if (header == NULL) { - pr_verbose(verbose, "Failed to obtain control message header"); - rc = -EINVAL; + if (rc != 0) goto out; - } - - header->cmsg_level = SOL_ALG; - header->cmsg_type = ALG_SET_OP; - header->cmsg_len = CMSG_LEN(sizeof(*type)); - type = (void *)CMSG_DATA(header); - *type = ALG_OP_ENCRYPT; - - header = CMSG_NXTHDR(&msg, header); - if (header == NULL) { - pr_verbose(verbose, "Failed to obtain control message " - "header"); - rc = -EINVAL; - goto out; - } - header->cmsg_level = SOL_ALG; - header->cmsg_type = ALG_SET_IV; - header->cmsg_len = iv_msg_size; - alg_iv = (void *)CMSG_DATA(header); - alg_iv->ivlen = PAES_BLOCK_SIZE; - memcpy(alg_iv->iv, null_msg, PAES_BLOCK_SIZE); - - len = sendmsg(opfd, &msg, 0); - if (len != ENC_ZERO_LEN) { - pr_verbose(verbose, "Failed to send to the AF_ALG socket"); - rc = -errno; - goto out; - } - - len = read(opfd, enc_zero, sizeof(enc_zero)); - if (len != ENC_ZERO_LEN) { - pr_verbose(verbose, "Failed to receive from the AF_ALG socket"); - rc = -errno; - goto out; - } memset(vp, 0, vp_len); for (i = 0; i < sizeof(enc_zero); i++) @@ -1731,11 +1681,6 @@ retry_setkey: pr_verbose(verbose, "Key verification pattern: %s", vp); out: - if (opfd != -1) - close(opfd); - if (tfmfd != -1) - close(tfmfd); - if (rc != 0) pr_verbose(verbose, "Failed to generate the key verification " "pattern: %s", strerror(-rc)); @@ -1745,7 +1690,7 @@ out: /** * Generate a key verification pattern of a secure HMAC key by MACing the all - * zero message with the secure key using the AF_ALG interface + * zero message with the secure key * * @param[in] pkey_fd the pkey file descriptor * @param[in] key the secure key token @@ -1763,16 +1708,19 @@ int generate_hmac_key_verification_pattern(int pkey_fd, const char *cipher, bool verbose) { - int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0; - char null_msg[MAC_ZERO_LEN]; - char mac_zero[MAC_ZERO_LEN]; - size_t i, bitsize; - int len; + u8 protkey[MAX_HMAC_PROTKEYSIZE]; + size_t protkey_size = sizeof(protkey); + u8 null_msg[MAC_ZERO_LEN] = { 0 }; + u8 mac_zero[MAC_ZERO_LEN]; + u8 clear_key[128] = { 0 }; + size_t i, clear_key_size; + int pkeytype = 0; + int count = 0; + int rc; - struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "hash", - }; + util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); + util_assert(key != NULL, "Internal error: key is NULL"); + util_assert(vp != NULL, "Internal error: vp is NULL"); if (vp_len < VERIFICATION_PATTERN_LEN) { rc = -EMSGSIZE; @@ -1780,79 +1728,66 @@ int generate_hmac_key_verification_pattern(int pkey_fd, } if (cipher != NULL) { - util_strlcpy((char *)sa.salg_name, cipher, - sizeof(sa.salg_name)); - } else { - rc = get_key_bit_size(key, key_size, &bitsize); - if (rc != 0) { - pr_verbose(verbose, "Failed to get the key size"); + if (strcmp(cipher, "hmac(sha256)") == 0) { + if (key_size > 64) { + if (SHA256(key, key_size, clear_key) == NULL) { + pr_verbose(verbose, + "Failed to hash the key"); + rc = -EIO; + goto out; + } + } else { + memcpy(clear_key, key, key_size); + } + clear_key_size = 64; + } else if (strcmp(cipher, "hmac(sha512)") == 0) { + if (key_size > 128) { + if (SHA512(key, key_size, clear_key) == NULL) { + pr_verbose(verbose, + "Failed to hash the key"); + rc = -EIO; + goto out; + } + } else { + memcpy(clear_key, key, key_size); + } + clear_key_size = 128; + } else { + pr_verbose(verbose, "Invalid clear key cipher '%s'", + cipher); + rc = -EINVAL; goto out; } - snprintf((char *)sa.salg_name, sizeof(sa.salg_name), - "phmac(sha%lu)", bitsize / 2); + + rc = cpacf_hmac_sha(clear_key, clear_key_size, + null_msg, sizeof(null_msg), + mac_zero, sizeof(mac_zero), 0); + } else { + do { + rc = pkey_kblob2protk(pkey_fd, (u8 *)key, key_size, + protkey, &protkey_size, &pkeytype, + verbose); + if (rc != 0) + goto out; + + switch (pkeytype) { + case PKEY_KEYTYPE_HMAC_512: + case PKEY_KEYTYPE_HMAC_1024: + rc = cpacf_hmac_sha(protkey, protkey_size, + null_msg, sizeof(null_msg), + mac_zero, sizeof(mac_zero), + pkeytype); + break; + default: + rc = -EINVAL; + goto out; + } + + } while (rc == -EAGAIN && count++ < MAX_WKVP_RETRY_COUNT); } - tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); - if (tfmfd < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to open an AF_ALG socket"); + if (rc != 0) goto out; - } - - if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to bind the AF_ALG socket, " - "salg_name='%s' ", sa.salg_name); - goto out; - } - -retry_setkey: - if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, - key_size) < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to set the key: %s", - strerror(-rc)); - - /* - * After a master key change, it can happen that the setkey - * operation returns EINVAL or EAGAIN, although the key is - * valid. This is a temporary situation and the operation will - * succeed, once the firmware has completed some internal - * processing related with the master key change. - * Delay 1 second and retry up to 10 times. - */ - if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) { - pr_verbose(verbose, "Retrying after 1 second..."); - retry_count++; - sleep(1); - goto retry_setkey; - } - goto out; - } - rc = 0; - - opfd = accept(tfmfd, NULL, NULL); - if (opfd < 0) { - rc = -errno; - pr_verbose(verbose, "Failed to accept on the AF_ALG socket"); - goto out; - } - - memset(null_msg, 0, sizeof(null_msg)); - - len = send(opfd, &null_msg, sizeof(null_msg), 0); - if (len != MAC_ZERO_LEN) { - rc = -errno; - pr_verbose(verbose, "Failed to send to the AF_ALG socket"); - goto out; - } - - len = read(opfd, mac_zero, sizeof(mac_zero)); - if (len < SHA_256_HASH_SIZE) { - rc = -errno; - pr_verbose(verbose, "Failed to receive from the AF_ALG socket"); - goto out; - } memset(vp, 0, vp_len); for (i = 0; i < SHA_256_HASH_SIZE; i++) @@ -1861,21 +1796,18 @@ retry_setkey: pr_verbose(verbose, "Key verification pattern: %s", vp); out: - if (opfd != -1) - close(opfd); - if (tfmfd != -1) - close(tfmfd); - if (rc != 0) pr_verbose(verbose, "Failed to generate the key verification " "pattern: %s", strerror(-rc)); + OPENSSL_cleanse(clear_key, sizeof(clear_key)); return rc; + } /** * Generate a key verification pattern of a secure key by encrypting the all - * zero message with the secure key using the AF_ALG interface + * zero message with the secure key * * @param[in] pkey_fd the pkey file descriptor * @param[in] key the secure key token diff --git a/zkey/pkey.h b/zkey/pkey.h index 2e70bce3..46cdccbe 100644 --- a/zkey/pkey.h +++ b/zkey/pkey.h @@ -170,6 +170,10 @@ struct pkey_clrkey { #define PKEY_KEYTYPE_AES_128 1 #define PKEY_KEYTYPE_AES_192 2 #define PKEY_KEYTYPE_AES_256 3 +#define PKEY_KEYTYPE_AES_XTS_128 10 +#define PKEY_KEYTYPE_AES_XTS_256 11 +#define PKEY_KEYTYPE_HMAC_512 12 +#define PKEY_KEYTYPE_HMAC_1024 13 struct pkey_genseck { u16 cardnr; /* in: card to use or FFFF for any */ @@ -310,6 +314,10 @@ struct pkey_kblob2pkey3 { #define PKEY_KBLOB2PROTK3 _IOWR(PKEY_IOCTL_MAGIC, 0x1D, struct pkey_kblob2pkey3) +#define MAX_AES_PROTKEYSIZE 64 +#define MAX_XTSFULL_PROTKEYSIZE 96 +#define MAX_HMAC_PROTKEYSIZE 160 + #define KEY_TYPE_CCA_AESDATA "CCA-AESDATA" #define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER" #define KEY_TYPE_EP11_AES "EP11-AES"