diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c index d8100790088..4c57a9392d2 100644 --- a/crypto/cryptodev.c +++ b/crypto/cryptodev.c @@ -111,6 +111,7 @@ static int cryptof_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int cryptof_poll(FAR struct file *filep, struct pollfd *fds, bool setup); +static int cryptof_open(FAR struct file *filep); static int cryptof_close(FAR struct file *filep); static int cryptoopen(FAR struct file *filep); @@ -127,7 +128,7 @@ static int cryptoioctl(FAR struct file *filep, int cmd, unsigned long arg); static const struct file_operations g_cryptofops = { - NULL, /* open */ + cryptof_open, /* open */ cryptof_close, /* close */ cryptof_read, /* read */ cryptof_write, /* write */ @@ -283,6 +284,7 @@ static int cryptof_ioctl(FAR struct file *filep, if (thash) { cria.cri_alg = sop->mac; + cria.cri_sid = -1; cria.cri_klen = sop->mackeylen * 8; if (cria.cri_klen) @@ -364,7 +366,7 @@ bail: error = crypto_getfeat((FAR int *)arg); break; default: - error = -EINVAL; + error = -ENOTTY; } return error; @@ -702,6 +704,122 @@ static int cryptof_close(FAR struct file *filep) return 0; } +/* Clone csessions into a new fd */ + +static int cryptof_open(FAR struct file *filep) +{ + FAR struct fcrypt *fcr = filep->f_priv; + FAR struct fcrypt *fcrd = NULL; + FAR struct csession *cse; + FAR struct csession *csed; + struct cryptoini cria; + struct cryptoini crie; + uint64_t sid; + int ret = 0; + + if (fcr == NULL) + { + return -EINVAL; + } + + /* A 'struct fcrypt' is bound to the fd of the cryptodev, + * which stores a list of sessions. Each encryption operation + * would create a context and get a session id, which can be + * used to find the specific encryption operation. Therefore, + * in order to complete the copy operation, it is necessary to + * create same session based on the copy fd and obtain the newly + * generated session id. + */ + + fcrd = kmm_zalloc(sizeof(struct fcrypt)); + if (fcrd == NULL) + { + return -ENOMEM; + } + + TAILQ_INIT(&fcrd->csessions); + TAILQ_FOREACH(cse, &fcr->csessions, next) + { + bzero(&crie, sizeof(crie)); + bzero(&cria, sizeof(cria)); + if (cse->txform) + { + crie.cri_alg = cse->cipher; + crie.cri_klen = cse->keylen * 8; + + crie.cri_key = kmm_malloc(cse->keylen); + if (crie.cri_key == NULL) + { + ret = -ENOMEM; + goto bail; + } + + memcpy(crie.cri_key, cse->key, cse->keylen); + if (cse->thash) + { + crie.cri_next = &cria; + } + } + + if (cse->thash) + { + cria.cri_alg = cse->mac; + cria.cri_sid = cse->sid; + cria.cri_klen = cse->mackeylen * 8; + + if (cria.cri_klen) + { + cria.cri_key = kmm_malloc(cse->mackeylen); + if (cria.cri_key == NULL) + { + ret = -ENOMEM; + goto bail; + } + + memcpy(cria.cri_key, cse->mackey, cse->mackeylen); + } + } + + ret = crypto_newsession(&sid, cse->txform ? &crie : &cria, + !cryptodevallowsoft); + if (ret < 0) + { + goto bail; + } + + csed = csecreate(fcrd, sid, crie.cri_key, crie.cri_klen, + cria.cri_key, cria.cri_klen, + cse->cipher, cse->mac, cse->txform, + cse->thash); + if (csed == NULL) + { + crypto_freesession(sid); + ret = -EINVAL; + goto bail; + } + + csed->ses = cse->ses; + } + + filep->f_priv = fcrd; + return 0; + +bail: + if (crie.cri_key) + { + explicit_bzero(crie.cri_key, crie.cri_klen / 8); + kmm_free(crie.cri_key); + } + + if (cria.cri_key) + { + explicit_bzero(cria.cri_key, cria.cri_klen / 8); + kmm_free(cria.cri_key); + } + + return ret; +} + static int cryptoopen(FAR struct file *filep) { if (usercrypto == 0) diff --git a/crypto/cryptosoft.c b/crypto/cryptosoft.c index fc007eb5cd2..2fe76bd0d02 100644 --- a/crypto/cryptosoft.c +++ b/crypto/cryptosoft.c @@ -802,6 +802,18 @@ int swcr_newsession(FAR uint32_t *sid, FAR struct cryptoini *cri) axf->init((*swd)->sw_ictx); (*swd)->sw_axf = axf; bcopy((*swd)->sw_ictx, &(*swd)->sw_ctx, axf->ctxsize); + + if (cri->cri_sid != -1) + { + if (swcr_sessions[cri->cri_sid] == NULL) + { + swcr_freesession(i); + return -EINVAL; + } + + bcopy(&swcr_sessions[cri->cri_sid]->sw_ctx, &(*swd)->sw_ctx, + axf->ctxsize); + } break; case CRYPTO_AES_128_GMAC: diff --git a/include/crypto/cryptodev.h b/include/crypto/cryptodev.h index 86c8e7e4dd9..3fe12b14a52 100644 --- a/include/crypto/cryptodev.h +++ b/include/crypto/cryptodev.h @@ -138,6 +138,7 @@ struct cryptoini int cri_alg; /* Algorithm to use */ int cri_klen; /* Key length, in bits */ int cri_rnd; /* Algorithm rounds, where relevant */ + int cri_sid; caddr_t cri_key; /* key to use */ union {