Skip to content

Commit

Permalink
s390/zcrypt: Support for CCA APKA master keys
Browse files Browse the repository at this point in the history
Support for CCA APKA (used for CCA ECC keys) master keys.
The existing mkvps sysfs attribute for each queue for cards
in CCA mode is extended to show the APKA master key register
states and verification pattern:

Improve the mkvps sysfs attribute to display the APKA
master key verification patterns for old, current and new
master key registers. The APKA master key is used to
encrypt CCA ECC secure keys. The syntax is analog to the
existing AES mk verification patterns:

    APKA NEW: <new_apka_mk_state> <new_apka_mk_mkvp>
    APKA CUR: <cur_apka_mk_state> <cur_apka_mk_mkvp>
    APKA OLD: <old_apka_mk_state> <old_apka_mk_mkvp>
  with
    <new_apka_mk_state>: 'empty' or 'partial' or 'full'
    <cur_apka_mk_state>: 'valid' or 'invalid'
    <old_apka_mk_state>: 'valid' or 'invalid'
    <new_apka_mk_mkvp>, <cur_apka_mk_mkvp>, <old_apka_mk_mkvp>
      8 byte hex string with leading 0x

MKVP means Master Key Verification Pattern and is a folded hash over
the key value. Only the states 'full' and 'valid' result in displaying
a useful mkvp, otherwise a mkvp of all bytes zero is shown. If for any
reason the FQ fails and the (cached) information is not available, the
state '-' will be shown with the mkvp value also '-'. The values shown
here are the very same as the cca panel tools displays.

The internal function cca_findcard2() also supports to match
against the APKA master key verification patterns and the pkey
kernel module which uses this function needed compatible rewrite
of these invocations.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
  • Loading branch information
Harald Freudenberger authored and Vasily Gorbik committed Sep 24, 2020
1 parent 5596c4c commit 32ca04b
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 57 deletions.
18 changes: 11 additions & 7 deletions drivers/s390/crypto/pkey_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,13 +661,14 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
*ksize = (enum pkey_key_size) t->bitsize;

rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
ZCRYPT_CEX3C, t->mkvp, 0, 1);
ZCRYPT_CEX3C, AES_MK_SET, t->mkvp, 0, 1);
if (rc == 0 && flags)
*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
if (rc == -ENODEV) {
rc = cca_findcard2(&_apqns, &_nr_apqns,
*cardnr, *domain,
ZCRYPT_CEX3C, 0, t->mkvp, 1);
ZCRYPT_CEX3C, AES_MK_SET,
0, t->mkvp, 1);
if (rc == 0 && flags)
*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
}
Expand Down Expand Up @@ -697,13 +698,14 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
}

rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
ZCRYPT_CEX6, t->mkvp0, 0, 1);
ZCRYPT_CEX6, AES_MK_SET, t->mkvp0, 0, 1);
if (rc == 0 && flags)
*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
if (rc == -ENODEV) {
rc = cca_findcard2(&_apqns, &_nr_apqns,
*cardnr, *domain,
ZCRYPT_CEX6, 0, t->mkvp0, 1);
ZCRYPT_CEX6, AES_MK_SET,
0, t->mkvp0, 1);
if (rc == 0 && flags)
*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
}
Expand Down Expand Up @@ -863,7 +865,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
return -EINVAL;
}
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
minhwtype, cur_mkvp, old_mkvp, 1);
minhwtype, AES_MK_SET,
cur_mkvp, old_mkvp, 1);
if (rc)
goto out;
} else
Expand Down Expand Up @@ -900,7 +903,8 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype,
if (ktype == PKEY_TYPE_CCA_CIPHER)
minhwtype = ZCRYPT_CEX6;
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
minhwtype, cur_mkvp, old_mkvp, 1);
minhwtype, AES_MK_SET,
cur_mkvp, old_mkvp, 1);
if (rc)
goto out;
} else if (ktype == PKEY_TYPE_EP11) {
Expand Down Expand Up @@ -1589,7 +1593,7 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits,

/* build a list of apqns able to generate an cipher key */
rc = cca_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
ZCRYPT_CEX6, 0, 0, 0);
ZCRYPT_CEX6, 0, 0, 0, 0);
if (rc)
return rc;

Expand Down
85 changes: 56 additions & 29 deletions drivers/s390/crypto/zcrypt_ccamisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,21 +1506,38 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
rarray, &rlen, varray, &vlen);
if (rc == 0 && rlen >= 10*8 && vlen >= 204) {
memcpy(ci->serial, rarray, 8);
ci->new_mk_state = (char) rarray[7*8];
ci->cur_mk_state = (char) rarray[8*8];
ci->old_mk_state = (char) rarray[9*8];
if (ci->old_mk_state == '2')
memcpy(&ci->old_mkvp, varray + 172, 8);
if (ci->cur_mk_state == '2')
memcpy(&ci->cur_mkvp, varray + 184, 8);
if (ci->new_mk_state == '3')
memcpy(&ci->new_mkvp, varray + 196, 8);
found = 1;
ci->new_aes_mk_state = (char) rarray[7*8];
ci->cur_aes_mk_state = (char) rarray[8*8];
ci->old_aes_mk_state = (char) rarray[9*8];
if (ci->old_aes_mk_state == '2')
memcpy(&ci->old_aes_mkvp, varray + 172, 8);
if (ci->cur_aes_mk_state == '2')
memcpy(&ci->cur_aes_mkvp, varray + 184, 8);
if (ci->new_aes_mk_state == '3')
memcpy(&ci->new_aes_mkvp, varray + 196, 8);
found++;
}
if (!found)
goto out;
rlen = vlen = PAGE_SIZE/2;
rc = cca_query_crypto_facility(cardnr, domain, "STATICSB",
rarray, &rlen, varray, &vlen);
if (rc == 0 && rlen >= 10*8 && vlen >= 240) {
ci->new_apka_mk_state = (char) rarray[7*8];
ci->cur_apka_mk_state = (char) rarray[8*8];
ci->old_apka_mk_state = (char) rarray[9*8];
if (ci->old_apka_mk_state == '2')
memcpy(&ci->old_apka_mkvp, varray + 208, 8);
if (ci->cur_apka_mk_state == '2')
memcpy(&ci->cur_apka_mkvp, varray + 220, 8);
if (ci->new_apka_mk_state == '3')
memcpy(&ci->new_apka_mkvp, varray + 232, 8);
found++;
}

out:
free_page((unsigned long) pg);

return found ? 0 : -ENOENT;
return found == 2 ? 0 : -ENOENT;
}

/*
Expand Down Expand Up @@ -1574,16 +1591,16 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain,
/* enabled CCA card, check current mkvp from cache */
if (cca_info_cache_fetch(card, dom, &ci) == 0 &&
ci.hwtype >= minhwtype &&
ci.cur_mk_state == '2' &&
ci.cur_mkvp == mkvp) {
ci.cur_aes_mk_state == '2' &&
ci.cur_aes_mkvp == mkvp) {
if (!verify)
break;
/* verify: refresh card info */
if (fetch_cca_info(card, dom, &ci) == 0) {
cca_info_cache_update(card, dom, &ci);
if (ci.hwtype >= minhwtype &&
ci.cur_mk_state == '2' &&
ci.cur_mkvp == mkvp)
ci.cur_aes_mk_state == '2' &&
ci.cur_aes_mkvp == mkvp)
break;
}
}
Expand All @@ -1605,12 +1622,12 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain,
if (fetch_cca_info(card, dom, &ci) == 0) {
cca_info_cache_update(card, dom, &ci);
if (ci.hwtype >= minhwtype &&
ci.cur_mk_state == '2' &&
ci.cur_mkvp == mkvp)
ci.cur_aes_mk_state == '2' &&
ci.cur_aes_mkvp == mkvp)
break;
if (ci.hwtype >= minhwtype &&
ci.old_mk_state == '2' &&
ci.old_mkvp == mkvp &&
ci.old_aes_mk_state == '2' &&
ci.old_aes_mkvp == mkvp &&
oi < 0)
oi = i;
}
Expand Down Expand Up @@ -1664,7 +1681,8 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify)
EXPORT_SYMBOL(cca_findcard);

int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify)
int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp,
int verify)
{
struct zcrypt_device_status_ext *device_status;
u32 *_apqns = NULL, _nr_apqns = 0;
Expand Down Expand Up @@ -1706,21 +1724,30 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
if (cca_get_info(card, dom, &ci, verify))
continue;
/* current master key needs to be valid */
if (ci.cur_mk_state != '2')
if (mktype == AES_MK_SET && ci.cur_aes_mk_state != '2')
continue;
if (mktype == APKA_MK_SET && ci.cur_apka_mk_state != '2')
continue;
/* check min hardware type */
if (minhwtype > 0 && minhwtype > ci.hwtype)
continue;
if (cur_mkvp || old_mkvp) {
/* check mkvps */
curmatch = oldmatch = 0;
if (cur_mkvp && cur_mkvp == ci.cur_mkvp)
curmatch = 1;
if (old_mkvp && ci.old_mk_state == '2' &&
old_mkvp == ci.old_mkvp)
oldmatch = 1;
if ((cur_mkvp || old_mkvp) &&
(curmatch + oldmatch < 1))
if (mktype == AES_MK_SET) {
if (cur_mkvp && cur_mkvp == ci.cur_aes_mkvp)
curmatch = 1;
if (old_mkvp && ci.old_aes_mk_state == '2' &&
old_mkvp == ci.old_aes_mkvp)
oldmatch = 1;
} else {
if (cur_mkvp && cur_mkvp == ci.cur_apka_mkvp)
curmatch = 1;
if (old_mkvp && ci.old_apka_mk_state == '2' &&
old_mkvp == ci.old_apka_mkvp)
oldmatch = 1;
}
if (curmatch + oldmatch < 1)
continue;
}
/* apqn passed all filtering criterons, add to the array */
Expand Down
30 changes: 21 additions & 9 deletions drivers/s390/crypto/zcrypt_ccamisc.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify);
* - if verify is enabled and a cur_mkvp and/or old_mkvp
* value is given, then refetch the cca_info and make sure the current
* cur_mkvp or old_mkvp values of the apqn are used.
* The mktype determines which set of master keys to use:
* 0 = AES_MK_SET - AES MK set, 1 = APKA MK_SET - APKA MK set
* The array of apqn entries is allocated with kmalloc and returned in *apqns;
* the number of apqns stored into the list is returned in *nr_apqns. One apqn
* entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and
Expand All @@ -194,18 +196,28 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify);
* -ENODEV is returned.
*/
int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify);
int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp,
int verify);

#define AES_MK_SET 0
#define APKA_MK_SET 1

/* struct to hold info for each CCA queue */
struct cca_info {
int hwtype; /* one of the defined AP_DEVICE_TYPE_* */
char new_mk_state; /* '1' empty, '2' partially full, '3' full */
char cur_mk_state; /* '1' invalid, '2' valid */
char old_mk_state; /* '1' invalid, '2' valid */
u64 new_mkvp; /* truncated sha256 hash of new master key */
u64 cur_mkvp; /* truncated sha256 hash of current master key */
u64 old_mkvp; /* truncated sha256 hash of old master key */
char serial[9]; /* serial number string (8 ascii numbers + 0x00) */
int hwtype; /* one of the defined AP_DEVICE_TYPE_* */
char new_aes_mk_state; /* '1' empty, '2' partially full, '3' full */
char cur_aes_mk_state; /* '1' invalid, '2' valid */
char old_aes_mk_state; /* '1' invalid, '2' valid */
char new_apka_mk_state; /* '1' empty, '2' partially full, '3' full */
char cur_apka_mk_state; /* '1' invalid, '2' valid */
char old_apka_mk_state; /* '1' invalid, '2' valid */
u64 new_aes_mkvp; /* truncated sha256 of new aes master key */
u64 cur_aes_mkvp; /* truncated sha256 of current aes master key */
u64 old_aes_mkvp; /* truncated sha256 of old aes master key */
u64 new_apka_mkvp; /* truncated sha256 of new apka master key */
u64 cur_apka_mkvp; /* truncated sha256 of current apka mk */
u64 old_apka_mkvp; /* truncated sha256 of old apka mk */
char serial[9]; /* serial number (8 ascii numbers + 0x00) */
};

/*
Expand Down
39 changes: 33 additions & 6 deletions drivers/s390/crypto/zcrypt_cex2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,26 +109,53 @@ static ssize_t cca_mkvps_show(struct device *dev,
AP_QID_QUEUE(zq->queue->qid),
&ci, zq->online);

if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3')
if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3')
n = scnprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n",
new_state[ci.new_mk_state - '1'], ci.new_mkvp);
new_state[ci.new_aes_mk_state - '1'],
ci.new_aes_mkvp);
else
n = scnprintf(buf, PAGE_SIZE, "AES NEW: - -\n");

if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2')
if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"AES CUR: %s 0x%016llx\n",
cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp);
cao_state[ci.cur_aes_mk_state - '1'],
ci.cur_aes_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n");

if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2')
if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"AES OLD: %s 0x%016llx\n",
cao_state[ci.old_mk_state - '1'], ci.old_mkvp);
cao_state[ci.old_aes_mk_state - '1'],
ci.old_aes_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n");

if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA NEW: %s 0x%016llx\n",
new_state[ci.new_apka_mk_state - '1'],
ci.new_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n");

if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA CUR: %s 0x%016llx\n",
cao_state[ci.cur_apka_mk_state - '1'],
ci.cur_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n");

if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA OLD: %s 0x%016llx\n",
cao_state[ci.old_apka_mk_state - '1'],
ci.old_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n");

return n;
}

Expand Down
39 changes: 33 additions & 6 deletions drivers/s390/crypto/zcrypt_cex4.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,26 +121,53 @@ static ssize_t cca_mkvps_show(struct device *dev,
AP_QID_QUEUE(zq->queue->qid),
&ci, zq->online);

if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3')
if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3')
n = scnprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n",
new_state[ci.new_mk_state - '1'], ci.new_mkvp);
new_state[ci.new_aes_mk_state - '1'],
ci.new_aes_mkvp);
else
n = scnprintf(buf, PAGE_SIZE, "AES NEW: - -\n");

if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2')
if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"AES CUR: %s 0x%016llx\n",
cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp);
cao_state[ci.cur_aes_mk_state - '1'],
ci.cur_aes_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n");

if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2')
if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"AES OLD: %s 0x%016llx\n",
cao_state[ci.old_mk_state - '1'], ci.old_mkvp);
cao_state[ci.old_aes_mk_state - '1'],
ci.old_aes_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n");

if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA NEW: %s 0x%016llx\n",
new_state[ci.new_apka_mk_state - '1'],
ci.new_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n");

if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA CUR: %s 0x%016llx\n",
cao_state[ci.cur_apka_mk_state - '1'],
ci.cur_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n");

if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2')
n += scnprintf(buf + n, PAGE_SIZE - n,
"APKA OLD: %s 0x%016llx\n",
cao_state[ci.old_apka_mk_state - '1'],
ci.old_apka_mkvp);
else
n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n");

return n;
}

Expand Down

0 comments on commit 32ca04b

Please sign in to comment.