mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zkey: Remove the use of AF_ALG for calculating key verification patterns
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 <fcallies@linux.ibm.com> Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
44d6020774
commit
7fffdcfe8c
@@ -102,6 +102,9 @@
|
|||||||
_x > _y ? _x : _y; \
|
_x > _y ? _x : _y; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
typedef unsigned __int128 u128 __aligned(16);
|
||||||
|
#endif
|
||||||
typedef unsigned long long u64;
|
typedef unsigned long long u64;
|
||||||
typedef signed long long s64;
|
typedef signed long long s64;
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ zkey-cryptsetup-skip-openssl:
|
|||||||
all: $(BUILD_TARGETS) $(SUB_DIRS)
|
all: $(BUILD_TARGETS) $(SUB_DIRS)
|
||||||
|
|
||||||
zkey.o: check-dep-zkey zkey.c pkey.h cca.h ep11.h misc.h
|
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
|
cca.o: cca.c cca.h pkey.h ep11.h utils.h
|
||||||
ep11.o: ep11.c ep11.h pkey.h cca.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
|
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
|
ep11.h misc.h utils.h
|
||||||
kms.o: kms.c kms.h kms-plugin.h utils.h pkey.h
|
kms.o: kms.c kms.h kms-plugin.h utils.h pkey.h
|
||||||
pvsecrets.o: pvsecrets.h
|
pvsecrets.o: pvsecrets.h
|
||||||
|
cpacf.o: cpacf.c cpacf.h pkey.h
|
||||||
|
|
||||||
zkey: LDLIBS = -ldl -lcrypto
|
zkey: LDLIBS = -ldl -lcrypto
|
||||||
zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o kms.o \
|
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 $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c -lcrypto
|
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 $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
install-common:
|
install-common:
|
||||||
|
|||||||
603
zkey/cpacf.c
Normal file
603
zkey/cpacf.c
Normal file
@@ -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 <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
324
zkey/cpacf.h
Normal file
324
zkey/cpacf.h
Normal file
@@ -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
|
||||||
@@ -17,7 +17,7 @@ plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h
|
|||||||
properties.o: ../properties.c ../properties.h
|
properties.o: ../properties.c ../properties.h
|
||||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
$(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 $@
|
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
||||||
|
|
||||||
cca.o: ../cca.c ../cca.h ../pkey.h ../ep11.h ../utils.h
|
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
|
utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h
|
||||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
$(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: ALL_CFLAGS += -fPIC
|
||||||
zkey-ekmfweb.so: LDLIBS = -L$(rootdir)/libekmfweb -lekmfweb -ldl -lcrypto
|
zkey-ekmfweb.so: LDLIBS = -L$(rootdir)/libekmfweb -lekmfweb -ldl -lcrypto
|
||||||
zkey-ekmfweb.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-ekmfweb.map \
|
zkey-ekmfweb.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-ekmfweb.map \
|
||||||
-Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-ekmfweb.so.$(VERM)
|
-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 \
|
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 $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
install-libekmfweb.dep:
|
install-libekmfweb.dep:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h
|
|||||||
properties.o: ../properties.c ../properties.h
|
properties.o: ../properties.c ../properties.h
|
||||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
$(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 $@
|
$(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
|
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
|
utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h ../kms-plugin.h
|
||||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
$(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: ALL_CFLAGS += -fPIC
|
||||||
zkey-kmip.so: LDLIBS = -L$(rootdir)/libkmipclient -lkmipclient -ldl -lcrypto
|
zkey-kmip.so: LDLIBS = -L$(rootdir)/libkmipclient -lkmipclient -ldl -lcrypto
|
||||||
zkey-kmip.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-kmip.map \
|
zkey-kmip.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-kmip.map \
|
||||||
-Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-kmip.so.$(VERM)
|
-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 \
|
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 $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
install-libkmipclient.dep:
|
install-libkmipclient.dep:
|
||||||
|
|||||||
360
zkey/pkey.c
360
zkey/pkey.c
@@ -11,16 +11,16 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/if_alg.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
#include "lib/util_panic.h"
|
#include "lib/util_panic.h"
|
||||||
@@ -28,13 +28,7 @@
|
|||||||
#include "pkey.h"
|
#include "pkey.h"
|
||||||
#include "pvsecrets.h"
|
#include "pvsecrets.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "cpacf.h"
|
||||||
#ifndef AF_ALG
|
|
||||||
#define AF_ALG 38
|
|
||||||
#endif
|
|
||||||
#ifndef SOL_ALG
|
|
||||||
#define SOL_ALG 279
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define pr_verbose(verbose, fmt...) do { \
|
#define pr_verbose(verbose, fmt...) do { \
|
||||||
if (verbose) \
|
if (verbose) \
|
||||||
@@ -48,6 +42,8 @@
|
|||||||
|
|
||||||
#define INITIAL_APQN_ENTRIES 16
|
#define INITIAL_APQN_ENTRIES 16
|
||||||
|
|
||||||
|
#define MAX_WKVP_RETRY_COUNT 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the pkey device and returns its file descriptor.
|
* 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
|
* 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] pkey_fd the pkey file descriptor
|
||||||
* @param[in] key the secure key token
|
* @param[in] key the secure key token
|
||||||
@@ -1595,31 +1591,19 @@ int generate_aes_key_verification_pattern(int pkey_fd,
|
|||||||
const char *cipher,
|
const char *cipher,
|
||||||
bool verbose)
|
bool verbose)
|
||||||
{
|
{
|
||||||
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
|
u8 protkey[MAX(MAX_AES_PROTKEYSIZE * 2, MAX_XTSFULL_PROTKEYSIZE)];
|
||||||
char null_msg[ENC_ZERO_LEN];
|
size_t protkey_size = sizeof(protkey);
|
||||||
char enc_zero[ENC_ZERO_LEN];
|
u8 null_msg[ENC_ZERO_LEN] = { 0 };
|
||||||
struct af_alg_iv *alg_iv;
|
u8 enc_zero[ENC_ZERO_LEN];
|
||||||
struct cmsghdr *header;
|
bool securekey, xts;
|
||||||
uint32_t *type;
|
int pkeytype = 0;
|
||||||
ssize_t len;
|
int count = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
struct sockaddr_alg sa = {
|
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||||
.salg_family = AF_ALG,
|
util_assert(key != NULL, "Internal error: key is NULL");
|
||||||
.salg_type = "skcipher",
|
util_assert(vp != NULL, "Internal error: vp is NULL");
|
||||||
};
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (vp_len < VERIFICATION_PATTERN_LEN) {
|
if (vp_len < VERIFICATION_PATTERN_LEN) {
|
||||||
rc = -EMSGSIZE;
|
rc = -EMSGSIZE;
|
||||||
@@ -1627,102 +1611,68 @@ int generate_aes_key_verification_pattern(int pkey_fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cipher != NULL) {
|
if (cipher != NULL) {
|
||||||
util_strlcpy((char *)sa.salg_name, cipher,
|
if (strcmp(cipher, "cbc(aes)") == 0) {
|
||||||
sizeof(sa.salg_name));
|
rc = cpacf_aes_cbc_enc(key, key_size,
|
||||||
} else {
|
null_msg, enc_zero,
|
||||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)",
|
sizeof(null_msg), 0);
|
||||||
is_xts_key(key, key_size) ? "xts" : "cbc");
|
} else if (strcmp(cipher, "xts(aes)") == 0) {
|
||||||
}
|
rc = cpacf_aes_xts_enc(key, key_size,
|
||||||
|
null_msg, enc_zero,
|
||||||
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
sizeof(null_msg), 0);
|
||||||
if (tfmfd < 0) {
|
} else {
|
||||||
rc = -errno;
|
pr_verbose(verbose, "Invalid clear key cipher '%s'",
|
||||||
pr_verbose(verbose, "Failed to open an AF_ALG socket");
|
cipher);
|
||||||
goto out;
|
rc = -EINVAL;
|
||||||
}
|
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;
|
} else {
|
||||||
}
|
securekey = is_secure_key(key, key_size);
|
||||||
rc = 0;
|
xts = securekey ? is_xts_key(key, key_size) : false;
|
||||||
|
|
||||||
opfd = accept(tfmfd, NULL, NULL);
|
do {
|
||||||
if (opfd < 0) {
|
rc = pkey_kblob2protk(pkey_fd, (u8 *)key, key_size,
|
||||||
rc = -errno;
|
protkey, &protkey_size, &pkeytype,
|
||||||
pr_verbose(verbose, "Failed to accept on the AF_ALG socket");
|
verbose);
|
||||||
goto out;
|
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));
|
if (rc != 0)
|
||||||
memset(buffer, 0, sizeof(buffer));
|
|
||||||
|
|
||||||
header = CMSG_FIRSTHDR(&msg);
|
|
||||||
if (header == NULL) {
|
|
||||||
pr_verbose(verbose, "Failed to obtain control message header");
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out;
|
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);
|
memset(vp, 0, vp_len);
|
||||||
for (i = 0; i < sizeof(enc_zero); i++)
|
for (i = 0; i < sizeof(enc_zero); i++)
|
||||||
@@ -1731,11 +1681,6 @@ retry_setkey:
|
|||||||
pr_verbose(verbose, "Key verification pattern: %s", vp);
|
pr_verbose(verbose, "Key verification pattern: %s", vp);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (opfd != -1)
|
|
||||||
close(opfd);
|
|
||||||
if (tfmfd != -1)
|
|
||||||
close(tfmfd);
|
|
||||||
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
pr_verbose(verbose, "Failed to generate the key verification "
|
pr_verbose(verbose, "Failed to generate the key verification "
|
||||||
"pattern: %s", strerror(-rc));
|
"pattern: %s", strerror(-rc));
|
||||||
@@ -1745,7 +1690,7 @@ out:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a key verification pattern of a secure HMAC key by MACing the all
|
* 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] pkey_fd the pkey file descriptor
|
||||||
* @param[in] key the secure key token
|
* @param[in] key the secure key token
|
||||||
@@ -1763,16 +1708,19 @@ int generate_hmac_key_verification_pattern(int pkey_fd,
|
|||||||
const char *cipher,
|
const char *cipher,
|
||||||
bool verbose)
|
bool verbose)
|
||||||
{
|
{
|
||||||
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
|
u8 protkey[MAX_HMAC_PROTKEYSIZE];
|
||||||
char null_msg[MAC_ZERO_LEN];
|
size_t protkey_size = sizeof(protkey);
|
||||||
char mac_zero[MAC_ZERO_LEN];
|
u8 null_msg[MAC_ZERO_LEN] = { 0 };
|
||||||
size_t i, bitsize;
|
u8 mac_zero[MAC_ZERO_LEN];
|
||||||
int len;
|
u8 clear_key[128] = { 0 };
|
||||||
|
size_t i, clear_key_size;
|
||||||
|
int pkeytype = 0;
|
||||||
|
int count = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
struct sockaddr_alg sa = {
|
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||||
.salg_family = AF_ALG,
|
util_assert(key != NULL, "Internal error: key is NULL");
|
||||||
.salg_type = "hash",
|
util_assert(vp != NULL, "Internal error: vp is NULL");
|
||||||
};
|
|
||||||
|
|
||||||
if (vp_len < VERIFICATION_PATTERN_LEN) {
|
if (vp_len < VERIFICATION_PATTERN_LEN) {
|
||||||
rc = -EMSGSIZE;
|
rc = -EMSGSIZE;
|
||||||
@@ -1780,79 +1728,66 @@ int generate_hmac_key_verification_pattern(int pkey_fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cipher != NULL) {
|
if (cipher != NULL) {
|
||||||
util_strlcpy((char *)sa.salg_name, cipher,
|
if (strcmp(cipher, "hmac(sha256)") == 0) {
|
||||||
sizeof(sa.salg_name));
|
if (key_size > 64) {
|
||||||
} else {
|
if (SHA256(key, key_size, clear_key) == NULL) {
|
||||||
rc = get_key_bit_size(key, key_size, &bitsize);
|
pr_verbose(verbose,
|
||||||
if (rc != 0) {
|
"Failed to hash the key");
|
||||||
pr_verbose(verbose, "Failed to get the key size");
|
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;
|
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 (rc != 0)
|
||||||
if (tfmfd < 0) {
|
|
||||||
rc = -errno;
|
|
||||||
pr_verbose(verbose, "Failed to open an AF_ALG socket");
|
|
||||||
goto out;
|
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);
|
memset(vp, 0, vp_len);
|
||||||
for (i = 0; i < SHA_256_HASH_SIZE; i++)
|
for (i = 0; i < SHA_256_HASH_SIZE; i++)
|
||||||
@@ -1861,21 +1796,18 @@ retry_setkey:
|
|||||||
pr_verbose(verbose, "Key verification pattern: %s", vp);
|
pr_verbose(verbose, "Key verification pattern: %s", vp);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (opfd != -1)
|
|
||||||
close(opfd);
|
|
||||||
if (tfmfd != -1)
|
|
||||||
close(tfmfd);
|
|
||||||
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
pr_verbose(verbose, "Failed to generate the key verification "
|
pr_verbose(verbose, "Failed to generate the key verification "
|
||||||
"pattern: %s", strerror(-rc));
|
"pattern: %s", strerror(-rc));
|
||||||
|
|
||||||
|
OPENSSL_cleanse(clear_key, sizeof(clear_key));
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a key verification pattern of a secure key by encrypting the all
|
* 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] pkey_fd the pkey file descriptor
|
||||||
* @param[in] key the secure key token
|
* @param[in] key the secure key token
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ struct pkey_clrkey {
|
|||||||
#define PKEY_KEYTYPE_AES_128 1
|
#define PKEY_KEYTYPE_AES_128 1
|
||||||
#define PKEY_KEYTYPE_AES_192 2
|
#define PKEY_KEYTYPE_AES_192 2
|
||||||
#define PKEY_KEYTYPE_AES_256 3
|
#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 {
|
struct pkey_genseck {
|
||||||
u16 cardnr; /* in: card to use or FFFF for any */
|
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 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_AESDATA "CCA-AESDATA"
|
||||||
#define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER"
|
#define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER"
|
||||||
#define KEY_TYPE_EP11_AES "EP11-AES"
|
#define KEY_TYPE_EP11_AES "EP11-AES"
|
||||||
|
|||||||
Reference in New Issue
Block a user