crypto: caam - add support for RSA key form 3
authorRadu Alexe <radu.alexe@nxp.com>
Tue, 25 Apr 2017 13:26:39 +0000 (16:26 +0300)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 18 May 2017 05:19:51 +0000 (13:19 +0800)
CAAM RSA private key may have either of three representations.

1. The first representation consists of the pair (n, d), where the
   components have the following meanings:
      n      the RSA modulus
      d      the RSA private exponent

2. The second representation consists of the triplet (p, q, d), where
the
   components have the following meanings:
      p      the first prime factor of the RSA modulus n
      q      the second prime factor of the RSA modulus n
      d      the RSA private exponent

3. The third representation consists of the quintuple (p, q, dP, dQ,
qInv),
   where the components have the following meanings:
      p      the first prime factor of the RSA modulus n
      q      the second prime factor of the RSA modulus n
      dP     the first factors's CRT exponent
      dQ     the second factors's CRT exponent
      qInv   the (first) CRT coefficient

The benefit of using the third or the second key form is lower
computational cost for the decryption and signature operations.

This patch adds support for the third RSA private key
representations and extends caampkc to use the fastest key when all
related components are present in the private key.

Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/caam/caampkc.c
drivers/crypto/caam/caampkc.h
drivers/crypto/caam/pdb.h
drivers/crypto/caam/pkc_desc.c

index 912e41700522951aa0f0084aa584320aa04435db..57f399caa977b1f43832126e2cfb098df3313703 100644 (file)
@@ -20,6 +20,8 @@
                                 sizeof(struct rsa_priv_f1_pdb))
 #define DESC_RSA_PRIV_F2_LEN   (2 * CAAM_CMD_SZ + \
                                 sizeof(struct rsa_priv_f2_pdb))
+#define DESC_RSA_PRIV_F3_LEN   (2 * CAAM_CMD_SZ + \
+                                sizeof(struct rsa_priv_f3_pdb))
 
 static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc,
                         struct akcipher_request *req)
@@ -73,6 +75,25 @@ static void rsa_priv_f2_unmap(struct device *dev, struct rsa_edesc *edesc,
        dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE);
 }
 
+static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc,
+                             struct akcipher_request *req)
+{
+       struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+       struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+       struct caam_rsa_key *key = &ctx->key;
+       struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3;
+       size_t p_sz = key->p_sz;
+       size_t q_sz = key->p_sz;
+
+       dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->dp_dma, p_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->dq_dma, q_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE);
+       dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE);
+}
+
 /* RSA Job Completion handler */
 static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context)
 {
@@ -127,6 +148,24 @@ static void rsa_priv_f2_done(struct device *dev, u32 *desc, u32 err,
        akcipher_request_complete(req, err);
 }
 
+static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err,
+                            void *context)
+{
+       struct akcipher_request *req = context;
+       struct rsa_edesc *edesc;
+
+       if (err)
+               caam_jr_strstatus(dev, err);
+
+       edesc = container_of(desc, struct rsa_edesc, hw_desc[0]);
+
+       rsa_priv_f3_unmap(dev, edesc, req);
+       rsa_io_unmap(dev, edesc, req);
+       kfree(edesc);
+
+       akcipher_request_complete(req, err);
+}
+
 static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
                                         size_t desclen)
 {
@@ -370,6 +409,97 @@ unmap_d:
        return -ENOMEM;
 }
 
+static int set_rsa_priv_f3_pdb(struct akcipher_request *req,
+                              struct rsa_edesc *edesc)
+{
+       struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+       struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+       struct caam_rsa_key *key = &ctx->key;
+       struct device *dev = ctx->dev;
+       struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3;
+       int sec4_sg_index = 0;
+       size_t p_sz = key->p_sz;
+       size_t q_sz = key->p_sz;
+
+       pdb->p_dma = dma_map_single(dev, key->p, p_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->p_dma)) {
+               dev_err(dev, "Unable to map RSA prime factor p memory\n");
+               return -ENOMEM;
+       }
+
+       pdb->q_dma = dma_map_single(dev, key->q, q_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->q_dma)) {
+               dev_err(dev, "Unable to map RSA prime factor q memory\n");
+               goto unmap_p;
+       }
+
+       pdb->dp_dma = dma_map_single(dev, key->dp, p_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->dp_dma)) {
+               dev_err(dev, "Unable to map RSA exponent dp memory\n");
+               goto unmap_q;
+       }
+
+       pdb->dq_dma = dma_map_single(dev, key->dq, q_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->dq_dma)) {
+               dev_err(dev, "Unable to map RSA exponent dq memory\n");
+               goto unmap_dp;
+       }
+
+       pdb->c_dma = dma_map_single(dev, key->qinv, p_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->c_dma)) {
+               dev_err(dev, "Unable to map RSA CRT coefficient qinv memory\n");
+               goto unmap_dq;
+       }
+
+       pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->tmp1_dma)) {
+               dev_err(dev, "Unable to map RSA tmp1 memory\n");
+               goto unmap_qinv;
+       }
+
+       pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, pdb->tmp2_dma)) {
+               dev_err(dev, "Unable to map RSA tmp2 memory\n");
+               goto unmap_tmp1;
+       }
+
+       if (edesc->src_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_G;
+               pdb->g_dma = edesc->sec4_sg_dma;
+               sec4_sg_index += edesc->src_nents;
+       } else {
+               pdb->g_dma = sg_dma_address(req->src);
+       }
+
+       if (edesc->dst_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_F;
+               pdb->f_dma = edesc->sec4_sg_dma +
+                            sec4_sg_index * sizeof(struct sec4_sg_entry);
+       } else {
+               pdb->f_dma = sg_dma_address(req->dst);
+       }
+
+       pdb->sgf |= key->n_sz;
+       pdb->p_q_len = (q_sz << RSA_PDB_Q_SHIFT) | p_sz;
+
+       return 0;
+
+unmap_tmp1:
+       dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE);
+unmap_qinv:
+       dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE);
+unmap_dq:
+       dma_unmap_single(dev, pdb->dq_dma, q_sz, DMA_TO_DEVICE);
+unmap_dp:
+       dma_unmap_single(dev, pdb->dp_dma, p_sz, DMA_TO_DEVICE);
+unmap_q:
+       dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE);
+unmap_p:
+       dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE);
+
+       return -ENOMEM;
+}
+
 static int caam_rsa_enc(struct akcipher_request *req)
 {
        struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
@@ -479,6 +609,39 @@ init_fail:
        return ret;
 }
 
+static int caam_rsa_dec_priv_f3(struct akcipher_request *req)
+{
+       struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+       struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+       struct device *jrdev = ctx->dev;
+       struct rsa_edesc *edesc;
+       int ret;
+
+       /* Allocate extended descriptor */
+       edesc = rsa_edesc_alloc(req, DESC_RSA_PRIV_F3_LEN);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       /* Set RSA Decrypt Protocol Data Block - Private Key Form #3 */
+       ret = set_rsa_priv_f3_pdb(req, edesc);
+       if (ret)
+               goto init_fail;
+
+       /* Initialize Job Descriptor */
+       init_rsa_priv_f3_desc(edesc->hw_desc, &edesc->pdb.priv_f3);
+
+       ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f3_done, req);
+       if (!ret)
+               return -EINPROGRESS;
+
+       rsa_priv_f3_unmap(jrdev, edesc, req);
+
+init_fail:
+       rsa_io_unmap(jrdev, edesc, req);
+       kfree(edesc);
+       return ret;
+}
+
 static int caam_rsa_dec(struct akcipher_request *req)
 {
        struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
@@ -495,7 +658,9 @@ static int caam_rsa_dec(struct akcipher_request *req)
                return -EOVERFLOW;
        }
 
-       if (key->priv_form == FORM2)
+       if (key->priv_form == FORM3)
+               ret = caam_rsa_dec_priv_f3(req);
+       else if (key->priv_form == FORM2)
                ret = caam_rsa_dec_priv_f2(req);
        else
                ret = caam_rsa_dec_priv_f1(req);
@@ -508,6 +673,9 @@ static void caam_rsa_free_key(struct caam_rsa_key *key)
        kzfree(key->d);
        kzfree(key->p);
        kzfree(key->q);
+       kzfree(key->dp);
+       kzfree(key->dq);
+       kzfree(key->qinv);
        kzfree(key->tmp1);
        kzfree(key->tmp2);
        kfree(key->e);
@@ -523,6 +691,34 @@ static void caam_rsa_drop_leading_zeros(const u8 **ptr, size_t *nbytes)
        }
 }
 
+/**
+ * caam_read_rsa_crt - Used for reading dP, dQ, qInv CRT members.
+ * dP, dQ and qInv could decode to less than corresponding p, q length, as the
+ * BER-encoding requires that the minimum number of bytes be used to encode the
+ * integer. dP, dQ, qInv decoded values have to be zero-padded to appropriate
+ * length.
+ *
+ * @ptr   : pointer to {dP, dQ, qInv} CRT member
+ * @nbytes: length in bytes of {dP, dQ, qInv} CRT member
+ * @dstlen: length in bytes of corresponding p or q prime factor
+ */
+static u8 *caam_read_rsa_crt(const u8 *ptr, size_t nbytes, size_t dstlen)
+{
+       u8 *dst;
+
+       caam_rsa_drop_leading_zeros(&ptr, &nbytes);
+       if (!nbytes)
+               return NULL;
+
+       dst = kzalloc(dstlen, GFP_DMA | GFP_KERNEL);
+       if (!dst)
+               return NULL;
+
+       memcpy(dst + (dstlen - nbytes), ptr, nbytes);
+
+       return dst;
+}
+
 /**
  * caam_read_raw_data - Read a raw byte stream as a positive integer.
  * The function skips buffer's leading zeros, copies the remained data
@@ -629,8 +825,29 @@ static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx,
 
        rsa_key->priv_form = FORM2;
 
+       rsa_key->dp = caam_read_rsa_crt(raw_key->dp, raw_key->dp_sz, p_sz);
+       if (!rsa_key->dp)
+               goto free_tmp2;
+
+       rsa_key->dq = caam_read_rsa_crt(raw_key->dq, raw_key->dq_sz, q_sz);
+       if (!rsa_key->dq)
+               goto free_dp;
+
+       rsa_key->qinv = caam_read_rsa_crt(raw_key->qinv, raw_key->qinv_sz,
+                                         q_sz);
+       if (!rsa_key->qinv)
+               goto free_dq;
+
+       rsa_key->priv_form = FORM3;
+
        return;
 
+free_dq:
+       kzfree(rsa_key->dq);
+free_dp:
+       kzfree(rsa_key->dp);
+free_tmp2:
+       kzfree(rsa_key->tmp2);
 free_tmp1:
        kzfree(rsa_key->tmp1);
 free_q:
index 48e408ceaf752bcb9bf7f0c26b8ed7d2221ee80a..87ab75e9df43d6b055a0080316db9166e5cf0f81 100644 (file)
@@ -14,7 +14,7 @@
 
 /**
  * caam_priv_key_form - CAAM RSA private key representation
- * CAAM RSA private key may have either of two forms.
+ * CAAM RSA private key may have either of three forms.
  *
  * 1. The first representation consists of the pair (n, d), where the
  *    components have the following meanings:
  *        p      the first prime factor of the RSA modulus n
  *        q      the second prime factor of the RSA modulus n
  *        d      the RSA private exponent
+ *
+ * 3. The third representation consists of the quintuple (p, q, dP, dQ, qInv),
+ *    where the components have the following meanings:
+ *        p      the first prime factor of the RSA modulus n
+ *        q      the second prime factor of the RSA modulus n
+ *        dP     the first factors's CRT exponent
+ *        dQ     the second factors's CRT exponent
+ *        qInv   the (first) CRT coefficient
+ *
+ * The benefit of using the third or the second key form is lower computational
+ * cost for the decryption and signature operations.
  */
 enum caam_priv_key_form {
        FORM1,
        FORM2,
+       FORM3
 };
 
 /**
@@ -39,6 +51,9 @@ enum caam_priv_key_form {
  * @d           : RSA private exponent raw byte stream
  * @p           : RSA prime factor p of RSA modulus n
  * @q           : RSA prime factor q of RSA modulus n
+ * @dp          : RSA CRT exponent of p
+ * @dp          : RSA CRT exponent of q
+ * @qinv        : RSA CRT coefficient
  * @tmp1        : CAAM uses this temporary buffer as internal state buffer.
  *                It is assumed to be as long as p.
  * @tmp2        : CAAM uses this temporary buffer as internal state buffer.
@@ -56,6 +71,9 @@ struct caam_rsa_key {
        u8 *d;
        u8 *p;
        u8 *q;
+       u8 *dp;
+       u8 *dq;
+       u8 *qinv;
        u8 *tmp1;
        u8 *tmp2;
        size_t n_sz;
@@ -96,6 +114,7 @@ struct rsa_edesc {
                struct rsa_pub_pdb pub;
                struct rsa_priv_f1_pdb priv_f1;
                struct rsa_priv_f2_pdb priv_f2;
+               struct rsa_priv_f3_pdb priv_f3;
        } pdb;
        u32 hw_desc[];
 };
@@ -104,5 +123,6 @@ struct rsa_edesc {
 void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb);
 void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb);
 void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb);
+void init_rsa_priv_f3_desc(u32 *desc, struct rsa_priv_f3_pdb *pdb);
 
 #endif
index 8ea5e612927ef627946680123fe82b259d602a2f..31e59963f4d227f0645e9ed2858c17d92b1e5590 100644 (file)
@@ -493,6 +493,7 @@ struct dsa_verify_pdb {
 
 #define RSA_PRIV_KEY_FRM_1      0
 #define RSA_PRIV_KEY_FRM_2      1
+#define RSA_PRIV_KEY_FRM_3      2
 
 /**
  * RSA Encrypt Protocol Data Block
@@ -554,4 +555,36 @@ struct rsa_priv_f2_pdb {
        u32             p_q_len;
 } __packed;
 
+/**
+ * RSA Decrypt PDB - Private Key Form #3
+ * This is the RSA Chinese Reminder Theorem (CRT) form for two prime factors of
+ * the RSA modulus.
+ * @sgf     : scatter-gather field
+ * @g_dma   : dma address of encrypted input data
+ * @f_dma   : dma address of output data
+ * @c_dma   : dma address of RSA CRT coefficient
+ * @p_dma   : dma address of RSA prime factor p of RSA modulus n
+ * @q_dma   : dma address of RSA prime factor q of RSA modulus n
+ * @dp_dma  : dma address of RSA CRT exponent of RSA prime factor p
+ * @dp_dma  : dma address of RSA CRT exponent of RSA prime factor q
+ * @tmp1_dma: dma address of temporary buffer. CAAM uses this temporary buffer
+ *            as internal state buffer. It is assumed to be as long as p.
+ * @tmp2_dma: dma address of temporary buffer. CAAM uses this temporary buffer
+ *            as internal state buffer. It is assumed to be as long as q.
+ * @p_q_len : length in bytes of first two prime factors of the RSA modulus n
+ */
+struct rsa_priv_f3_pdb {
+       u32             sgf;
+       dma_addr_t      g_dma;
+       dma_addr_t      f_dma;
+       dma_addr_t      c_dma;
+       dma_addr_t      p_dma;
+       dma_addr_t      q_dma;
+       dma_addr_t      dp_dma;
+       dma_addr_t      dq_dma;
+       dma_addr_t      tmp1_dma;
+       dma_addr_t      tmp2_dma;
+       u32             p_q_len;
+} __packed;
+
 #endif
index 9d03c7055ed7d2503de5460a9858ca1e30cc5f15..9e2ce6fe2e43f7717e462f558c31cf997a4888ad 100644 (file)
@@ -51,3 +51,22 @@ void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb)
        append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY |
                         RSA_PRIV_KEY_FRM_2);
 }
+
+/* Descriptor for RSA Private operation - Private Key Form #3 */
+void init_rsa_priv_f3_desc(u32 *desc, struct rsa_priv_f3_pdb *pdb)
+{
+       init_job_desc_pdb(desc, 0, sizeof(*pdb));
+       append_cmd(desc, pdb->sgf);
+       append_ptr(desc, pdb->g_dma);
+       append_ptr(desc, pdb->f_dma);
+       append_ptr(desc, pdb->c_dma);
+       append_ptr(desc, pdb->p_dma);
+       append_ptr(desc, pdb->q_dma);
+       append_ptr(desc, pdb->dp_dma);
+       append_ptr(desc, pdb->dq_dma);
+       append_ptr(desc, pdb->tmp1_dma);
+       append_ptr(desc, pdb->tmp2_dma);
+       append_cmd(desc, pdb->p_q_len);
+       append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY |
+                        RSA_PRIV_KEY_FRM_3);
+}