s390/zcrypt: Support for CCA APKA master keys
authorHarald Freudenberger <freude@linux.ibm.com>
Fri, 4 Sep 2020 14:11:37 +0000 (16:11 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Thu, 24 Sep 2020 08:03:28 +0000 (10:03 +0200)
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>
drivers/s390/crypto/pkey_api.c
drivers/s390/crypto/zcrypt_ccamisc.c
drivers/s390/crypto/zcrypt_ccamisc.h
drivers/s390/crypto/zcrypt_cex2c.c
drivers/s390/crypto/zcrypt_cex4.c

index 5896e5282a4e80365f4c6b606ef07317c8165210..e48c13acc5daf485d3f7cea623938ab445772f3f 100644 (file)
@@ -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;
                }
@@ -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;
                }
@@ -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
@@ -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) {
@@ -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;
 
index 40b59a77ec0cfd4fb26bbe7a9ee79b84ccbfcf34..e969188a1ec4e7933fa59c7497f86f4cad4b3d94 100644 (file)
@@ -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;
 }
 
 /*
@@ -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;
                                }
                        }
@@ -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;
                        }
@@ -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;
@@ -1706,7 +1724,9 @@ 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)
@@ -1714,13 +1734,20 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
                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 */
index 8b7a641671c909a440bdb996362d8e0003f1b0f5..4d88a1d6af21803aa2d90a3b919121a84174d606 100644 (file)
@@ -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
@@ -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) */
 };
 
 /*
index f00127a78bab18ed0c85a3f52c7f63c6f8e5dabc..146eb9f2469422e352293ae7d34eb03e7a86def1 100644 (file)
@@ -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;
 }
 
index dc20d983e4682d88f178e37494f0616c5c735cb2..d9ebe3a3c210a7a6d880abe7b8d6b1dc92450fca 100644 (file)
@@ -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;
 }