s390/zcrypt: extend cca_findcard function and helper

Rework and extension of the cca_findcard function to be prepared for
other types of secure key blobs. Split the function and extract an
internal function which has no awareness of key blobs any
more. Improve this function and the helper code around to be able to
check for a minimal crypto card hardware level (Background: the newer
AES cipher keys need to match to the master key verification pattern
and need to have a crypto card CEX6 or higher).

No API change, neither for the in-kernel API nor the ioctl interface.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
Harald Freudenberger 2019-06-18 15:53:12 +02:00 committed by Vasily Gorbik
parent 183cb46954
commit 4da57a2fea
4 changed files with 83 additions and 24 deletions

View File

@ -1161,6 +1161,34 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus)
}
EXPORT_SYMBOL(zcrypt_device_status_mask_ext);
int zcrypt_device_status_ext(int card, int queue,
struct zcrypt_device_status_ext *devstat)
{
struct zcrypt_card *zc;
struct zcrypt_queue *zq;
memset(devstat, 0, sizeof(*devstat));
spin_lock(&zcrypt_list_lock);
for_each_zcrypt_card(zc) {
for_each_zcrypt_queue(zq, zc) {
if (card == AP_QID_CARD(zq->queue->qid) &&
queue == AP_QID_QUEUE(zq->queue->qid)) {
devstat->hwtype = zc->card->ap_dev.device_type;
devstat->functions = zc->card->functions >> 26;
devstat->qid = zq->queue->qid;
devstat->online = zq->online ? 0x01 : 0x00;
spin_unlock(&zcrypt_list_lock);
return 0;
}
}
}
spin_unlock(&zcrypt_list_lock);
return -ENODEV;
}
EXPORT_SYMBOL(zcrypt_device_status_ext);
static void zcrypt_status_mask(char status[], size_t max_adapters)
{
struct zcrypt_card *zc;

View File

@ -121,9 +121,6 @@ void zcrypt_card_get(struct zcrypt_card *);
int zcrypt_card_put(struct zcrypt_card *);
int zcrypt_card_register(struct zcrypt_card *);
void zcrypt_card_unregister(struct zcrypt_card *);
struct zcrypt_card *zcrypt_card_get_best(unsigned int *,
unsigned int, unsigned int);
void zcrypt_card_put_best(struct zcrypt_card *, unsigned int);
struct zcrypt_queue *zcrypt_queue_alloc(size_t);
void zcrypt_queue_free(struct zcrypt_queue *);
@ -132,8 +129,6 @@ int zcrypt_queue_put(struct zcrypt_queue *);
int zcrypt_queue_register(struct zcrypt_queue *);
void zcrypt_queue_unregister(struct zcrypt_queue *);
void zcrypt_queue_force_online(struct zcrypt_queue *, int);
struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int);
void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int);
int zcrypt_rng_device_add(void);
void zcrypt_rng_device_remove(void);
@ -145,5 +140,7 @@ int zcrypt_api_init(void);
void zcrypt_api_exit(void);
long zcrypt_send_cprb(struct ica_xcRB *xcRB);
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus);
int zcrypt_device_status_ext(int card, int queue,
struct zcrypt_device_status_ext *devstatus);
#endif /* _ZCRYPT_API_H_ */

View File

@ -779,7 +779,17 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
int rc, found = 0;
size_t rlen, vlen;
u8 *rarray, *varray, *pg;
struct zcrypt_device_status_ext devstat;
memset(ci, 0, sizeof(*ci));
/* get first info from zcrypt device driver about this apqn */
rc = zcrypt_device_status_ext(cardnr, domain, &devstat);
if (rc)
return rc;
ci->hwtype = devstat.hwtype;
/* prep page for rule array and var array use */
pg = (u8 *) __get_free_page(GFP_KERNEL);
if (!pg)
return -ENOMEM;
@ -787,10 +797,10 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
varray = pg + PAGE_SIZE/2;
rlen = vlen = PAGE_SIZE/2;
/* QF for this card/domain */
rc = cca_query_crypto_facility(cardnr, domain, "STATICSA",
rarray, &rlen, varray, &vlen);
if (rc == 0 && rlen >= 10*8 && vlen >= 204) {
memset(ci, 0, sizeof(*ci));
memcpy(ci->serial, rarray, 8);
ci->new_mk_state = (char) rarray[7*8];
ci->cur_mk_state = (char) rarray[8*8];
@ -828,23 +838,19 @@ int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify)
EXPORT_SYMBOL(cca_get_info);
/*
* Search for a matching crypto card based on the Master Key
* Verification Pattern provided inside a secure key.
* Returns < 0 on failure, 0 if CURRENT MKVP matches and
* 1 if OLD MKVP matches.
* Search for a matching crypto card based on the
* Master Key Verification Pattern given.
*/
int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain,
int verify, int minhwtype)
{
const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey;
struct zcrypt_device_status_ext *device_status;
u16 card, dom;
struct cca_info ci;
int i, rc, oi = -1;
/* some simple checks of the given secure key token */
if (t->type != TOKTYPE_CCA_INTERNAL ||
t->version != TOKVER_CCA_AES ||
t->mkvp == 0)
/* mkvp must not be zero, minhwtype needs to be >= 0 */
if (mkvp == 0 || minhwtype < 0)
return -EINVAL;
/* fetch status of all crypto cards */
@ -863,15 +869,17 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
device_status[i].functions & 0x04) {
/* 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 == t->mkvp) {
ci.cur_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.cur_mk_state == '2' &&
ci.cur_mkvp == t->mkvp)
if (ci.hwtype >= minhwtype &&
ci.cur_mk_state == '2' &&
ci.cur_mkvp == mkvp)
break;
}
}
@ -892,11 +900,13 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
/* fresh fetch mkvp from adapter */
if (fetch_cca_info(card, dom, &ci) == 0) {
cca_info_cache_update(card, dom, &ci);
if (ci.cur_mk_state == '2' &&
ci.cur_mkvp == t->mkvp)
if (ci.hwtype >= minhwtype &&
ci.cur_mk_state == '2' &&
ci.cur_mkvp == mkvp)
break;
if (ci.old_mk_state == '2' &&
ci.old_mkvp == t->mkvp &&
if (ci.hwtype >= minhwtype &&
ci.old_mk_state == '2' &&
ci.old_mkvp == mkvp &&
oi < 0)
oi = i;
}
@ -919,6 +929,29 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
kfree(device_status);
return rc;
}
/*
* Search for a matching crypto card based on the Master Key
* Verification Pattern provided inside a secure key token.
*/
int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify)
{
u64 mkvp;
const struct keytoken_header *hdr = (struct keytoken_header *) key;
if (hdr->type != TOKTYPE_CCA_INTERNAL)
return -EINVAL;
switch (hdr->version) {
case TOKVER_CCA_AES:
mkvp = ((struct secaeskeytoken *)key)->mkvp;
break;
default:
return -EINVAL;
}
return findcard(mkvp, pcardnr, pdomain, verify, 0);
}
EXPORT_SYMBOL(cca_findcard);
void __exit zcrypt_ccamisc_exit(void)

View File

@ -88,10 +88,11 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
* Returns < 0 on failure, 0 if CURRENT MKVP matches and
* 1 if OLD MKVP matches.
*/
int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify);
int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify);
/* 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 */