From: Harald Freudenberger Date: Fri, 25 Oct 2024 10:34:29 +0000 (+0200) Subject: s390/pkey: Rework pkey verify for protected keys X-Git-Tag: v6.13-rc1~206^2~79 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b2402a67246f83cdd1f807c8a54b341936b8ce0b;p=thirdparty%2Fkernel%2Flinux.git s390/pkey: Rework pkey verify for protected keys Rework the verification of protected keys by simple check for the correct AES wrapping key verification pattern. A protected key always carries the AES wrapping key verification pattern within the blob. The old code really used the protected key for an en/decrypt operation and by doing so, verified the AES WK VP. But a much simpler and more generic way is to extract the AES WK VP value from the key and compare it with AES WK VP from a freshly created dummy protected key. This also eliminates the limitation to only be able to verify AES protected keys. With this change any kind of known protected key can be verified. Suggested-by: Holger Dengler Signed-off-by: Harald Freudenberger Reviewed-by: Holger Dengler Signed-off-by: Heiko Carstens --- diff --git a/drivers/s390/crypto/pkey_pckmo.c b/drivers/s390/crypto/pkey_pckmo.c index 20fabfff6ef8d..b66fbf9846dcb 100644 --- a/drivers/s390/crypto/pkey_pckmo.c +++ b/drivers/s390/crypto/pkey_pckmo.c @@ -174,60 +174,42 @@ out: /* * Verify a raw protected key blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen, u32 protkeytype) { - struct { - u8 iv[AES_BLOCK_SIZE]; - u8 key[MAXPROTKEYSIZE]; - } param; - u8 null_msg[AES_BLOCK_SIZE]; - u8 dest_buf[AES_BLOCK_SIZE]; - unsigned int k, pkeylen; - unsigned long fc; - int rc = -EINVAL; + u8 clrkey[16] = { 0 }, tmpkeybuf[16 + AES_WK_VP_SIZE]; + u32 tmpkeybuflen, tmpkeytype; + int keysize, rc = -EINVAL; + u8 *wkvp; - switch (protkeytype) { - case PKEY_KEYTYPE_AES_128: - pkeylen = 16 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_128; - break; - case PKEY_KEYTYPE_AES_192: - pkeylen = 24 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_192; - break; - case PKEY_KEYTYPE_AES_256: - pkeylen = 32 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_256; - break; - default: + /* check protkey type and size */ + keysize = pkey_keytype_to_size(protkeytype); + if (!keysize) { PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__, protkeytype); goto out; } - if (protkeylen != pkeylen) { - PKEY_DBF_ERR("%s invalid protected key size %u for keytype %u\n", - __func__, protkeylen, protkeytype); + if (protkeylen < keysize + AES_WK_VP_SIZE) goto out; - } - - memset(null_msg, 0, sizeof(null_msg)); - memset(param.iv, 0, sizeof(param.iv)); - memcpy(param.key, protkey, protkeylen); + /* generate a dummy AES 128 protected key */ + tmpkeybuflen = sizeof(tmpkeybuf); + rc = pckmo_clr2protkey(PKEY_KEYTYPE_AES_128, + clrkey, sizeof(clrkey), + tmpkeybuf, &tmpkeybuflen, &tmpkeytype); + if (rc) + goto out; + memzero_explicit(tmpkeybuf, 16); + wkvp = tmpkeybuf + 16; - k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, - sizeof(null_msg)); - if (k != sizeof(null_msg)) { - PKEY_DBF_ERR("%s protected key is not valid\n", __func__); + /* compare WK VP from the temp key with that of the given prot key */ + if (memcmp(wkvp, protkey + keysize, AES_WK_VP_SIZE)) { + PKEY_DBF_ERR("%s protected key WK VP mismatch\n", __func__); rc = -EKEYREJECTED; goto out; } - rc = 0; - out: pr_debug("rc=%d\n", rc); return rc; @@ -369,7 +351,6 @@ out: /* * Verify a protected key token blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_key(const u8 *key, u32 keylen) { @@ -383,11 +364,26 @@ static int pckmo_verify_key(const u8 *key, u32 keylen) switch (hdr->version) { case TOKVER_PROTECTED_KEY: { - struct protaeskeytoken *t; + struct protkeytoken *t = (struct protkeytoken *)key; + u32 keysize; - if (keylen != sizeof(struct protaeskeytoken)) + if (keylen < sizeof(*t)) + goto out; + keysize = pkey_keytype_to_size(t->keytype); + if (!keysize || t->len != keysize + AES_WK_VP_SIZE) goto out; - t = (struct protaeskeytoken *)key; + switch (t->keytype) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_192: + case PKEY_KEYTYPE_AES_256: + if (keylen != sizeof(struct protaeskeytoken)) + goto out; + break; + default: + if (keylen != sizeof(*t) + keysize + AES_WK_VP_SIZE) + goto out; + break; + } rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); break; }