static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); const struct rsa_asn1_template *digest_info; unsigned int pos; if (err == -EOVERFLOW) /* Decrypted value had no leading 0 byte */ err = -EINVAL; if (err) goto done; if (req_ctx->child_req.dst_len != ctx->key_size - 1) { err = -EINVAL; goto done; } err = -EBADMSG; if (req_ctx->out_buf[0] != 0x01) goto done; for (pos = 1; pos < req_ctx->child_req.dst_len; pos++) if (req_ctx->out_buf[pos] != 0xff) break; if (pos < 9 || pos == req_ctx->child_req.dst_len || req_ctx->out_buf[pos] != 0x00) goto done; pos++; if (ctx->hash_name) { digest_info = rsa_lookup_asn1(ctx->hash_name); if (!digest_info) goto done; if (memcmp(req_ctx->out_buf + pos, digest_info->data, digest_info->size)) goto done; pos += digest_info->size; } err = 0; if (req->dst_len < req_ctx->child_req.dst_len - pos) err = -EOVERFLOW; req->dst_len = req_ctx->child_req.dst_len - pos; if (!err) sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, req->dst_len), req_ctx->out_buf + pos, req->dst_len); done: kzfree(req_ctx->out_buf); return err; }
/* * The verify operation is here for completeness similar to the verification * defined in RFC2313 section 10.2 except that block type 0 is not accepted, * as in RFC2437. RFC2437 section 9.2 doesn't define any operation to * retrieve the DigestInfo from a signature, instead the user is expected * to call the sign operation to generate the expected signature and compare * signatures instead of the message-digests. */ static int pkcs1pad_verify(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); int err; if (!ctx->key_size || req->src_len < ctx->key_size) return -EINVAL; req_ctx->out_buf = kmalloc(ctx->key_size, GFP_KERNEL); if (!req_ctx->out_buf) return -ENOMEM; pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, ctx->key_size, NULL); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_verify_complete_cb, req); /* Reuse input buffer, output to a new buffer */ akcipher_request_set_crypt(&req_ctx->child_req, req->src, req_ctx->out_sg, req->src_len, ctx->key_size); err = crypto_akcipher_verify(&req_ctx->child_req); if (err != -EINPROGRESS && err != -EBUSY) return pkcs1pad_verify_complete(req, err); return err; }
static int pkcs1pad_sign(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); struct akcipher_instance *inst = akcipher_alg_instance(tfm); struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst); const struct rsa_asn1_template *digest_info = ictx->digest_info; int err; unsigned int ps_end, digest_size = 0; if (!ctx->key_size) return -EINVAL; if (digest_info) digest_size = digest_info->size; if (req->src_len + digest_size > ctx->key_size - 11) return -EOVERFLOW; if (req->dst_len < ctx->key_size) { req->dst_len = ctx->key_size; return -EOVERFLOW; } req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, GFP_KERNEL); if (!req_ctx->in_buf) return -ENOMEM; ps_end = ctx->key_size - digest_size - req->src_len - 2; req_ctx->in_buf[0] = 0x01; memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); req_ctx->in_buf[ps_end] = 0x00; if (digest_info) memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data, digest_info->size); pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_encrypt_sign_complete_cb, req); /* Reuse output buffer */ akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg, req->dst, ctx->key_size - 1, req->dst_len); err = crypto_akcipher_sign(&req_ctx->child_req); if (err != -EINPROGRESS && err != -EBUSY) return pkcs1pad_encrypt_sign_complete(req, err); return err; }
static int pkcs1pad_decrypt_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); unsigned int dst_len; unsigned int pos; u8 *out_buf; if (err) goto done; err = -EINVAL; dst_len = req_ctx->child_req.dst_len; if (dst_len < ctx->key_size - 1) goto done; out_buf = req_ctx->out_buf; if (dst_len == ctx->key_size) { if (out_buf[0] != 0x00) /* Decrypted value had no leading 0 byte */ goto done; dst_len--; out_buf++; } if (out_buf[0] != 0x02) goto done; for (pos = 1; pos < dst_len; pos++) if (out_buf[pos] == 0x00) break; if (pos < 9 || pos == dst_len) goto done; pos++; err = 0; if (req->dst_len < dst_len - pos) err = -EOVERFLOW; req->dst_len = dst_len - pos; if (!err) sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, req->dst_len), out_buf + pos, req->dst_len); done: kzfree(req_ctx->out_buf); return err; }
static int pkcs1pad_encrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); int err; unsigned int i, ps_end; if (!ctx->key_size) return -EINVAL; if (req->src_len > ctx->key_size - 11) return -EOVERFLOW; if (req->dst_len < ctx->key_size) { req->dst_len = ctx->key_size; return -EOVERFLOW; } req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, GFP_KERNEL); if (!req_ctx->in_buf) return -ENOMEM; ps_end = ctx->key_size - req->src_len - 2; req_ctx->in_buf[0] = 0x02; for (i = 1; i < ps_end; i++) req_ctx->in_buf[i] = 1 + prandom_u32_max(255); req_ctx->in_buf[ps_end] = 0x00; pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_encrypt_sign_complete_cb, req); /* Reuse output buffer */ akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg, req->dst, ctx->key_size - 1, req->dst_len); err = crypto_akcipher_encrypt(&req_ctx->child_req); if (err != -EINPROGRESS && err != -EBUSY) return pkcs1pad_encrypt_sign_complete(req, err); return err; }
/* * The verify operation is here for completeness similar to the verification * defined in RFC2313 section 10.2 except that block type 0 is not accepted, * as in RFC2437. RFC2437 section 9.2 doesn't define any operation to * retrieve the DigestInfo from a signature, instead the user is expected * to call the sign operation to generate the expected signature and compare * signatures instead of the message-digests. */ static int pkcs1pad_verify(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); int err; if (!ctx->key_size || req->src_len < ctx->key_size) return -EINVAL; if (ctx->key_size > PAGE_SIZE) return -ENOTSUPP; /* Reuse input buffer, output to a new buffer */ req_ctx->child_req.src = req->src; req_ctx->child_req.src_len = req->src_len; req_ctx->child_req.dst = req_ctx->out_sg; req_ctx->child_req.dst_len = ctx->key_size - 1; req_ctx->out_buf = kmalloc(ctx->key_size - 1, (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC); if (!req_ctx->out_buf) return -ENOMEM; pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, ctx->key_size - 1, NULL); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_verify_complete_cb, req); err = crypto_akcipher_verify(&req_ctx->child_req); if (err != -EINPROGRESS && (err != -EBUSY || !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) return pkcs1pad_verify_complete(req, err); return err; }
static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); size_t pad_len = ctx->key_size - req_ctx->child_req.dst_len; size_t chunk_len, pad_left; struct sg_mapping_iter miter; if (!err) { if (pad_len) { sg_miter_start(&miter, req->dst, sg_nents_for_len(req->dst, pad_len), SG_MITER_ATOMIC | SG_MITER_TO_SG); pad_left = pad_len; while (pad_left) { sg_miter_next(&miter); chunk_len = min(miter.length, pad_left); memset(miter.addr, 0, chunk_len); pad_left -= chunk_len; } sg_miter_stop(&miter); } sg_pcopy_from_buffer(req->dst, sg_nents_for_len(req->dst, ctx->key_size), req_ctx->out_buf, req_ctx->child_req.dst_len, pad_len); } req->dst_len = ctx->key_size; kfree(req_ctx->in_buf); kzfree(req_ctx->out_buf); return err; }
static void qat_rsa_cb(struct icp_qat_fw_pke_resp *resp) { struct akcipher_request *areq = (void *)(__force long)resp->opaque; struct qat_rsa_request *req = PTR_ALIGN(akcipher_request_ctx(areq), 64); struct device *dev = &GET_DEV(req->ctx->inst->accel_dev); int err = ICP_QAT_FW_PKE_RESP_PKE_STAT_GET( resp->pke_resp_hdr.comn_resp_flags); char *ptr = areq->dst; err = (err == ICP_QAT_FW_COMN_STATUS_FLAG_OK) ? 0 : -EINVAL; if (req->src_align) dma_free_coherent(dev, req->ctx->key_sz, req->src_align, req->in.enc.m); else dma_unmap_single(dev, req->in.enc.m, req->ctx->key_sz, DMA_TO_DEVICE); dma_unmap_single(dev, req->out.enc.c, req->ctx->key_sz, DMA_FROM_DEVICE); dma_unmap_single(dev, req->phy_in, sizeof(struct qat_rsa_input_params), DMA_TO_DEVICE); dma_unmap_single(dev, req->phy_out, sizeof(struct qat_rsa_output_params), DMA_TO_DEVICE); areq->dst_len = req->ctx->key_sz; /* Need to set the corect length of the output */ while (!(*ptr) && areq->dst_len) { areq->dst_len--; ptr++; } if (areq->dst_len != req->ctx->key_sz) memmove(areq->dst, ptr, areq->dst_len); akcipher_request_complete(areq, err); }
static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); unsigned int pad_len; unsigned int len; u8 *out_buf; if (err) goto out; len = req_ctx->child_req.dst_len; pad_len = ctx->key_size - len; /* Four billion to one */ if (likely(!pad_len)) goto out; out_buf = kzalloc(ctx->key_size, GFP_KERNEL); err = -ENOMEM; if (!out_buf) goto out; sg_copy_to_buffer(req->dst, sg_nents_for_len(req->dst, len), out_buf + pad_len, len); sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, ctx->key_size), out_buf, ctx->key_size); kzfree(out_buf); out: req->dst_len = ctx->key_size; kfree(req_ctx->in_buf); return err; }
static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, size_t desclen) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct device *dev = ctx->dev; struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); struct rsa_edesc *edesc; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int sg_flags = (flags == GFP_ATOMIC) ? SG_MITER_ATOMIC : 0; int sgc; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; int src_nents, dst_nents; int lzeros; lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len, sg_flags); if (lzeros < 0) return ERR_PTR(lzeros); req->src_len -= lzeros; req->src = scatterwalk_ffwd(req_ctx->src, req->src, lzeros); src_nents = sg_nents_for_len(req->src, req->src_len); dst_nents = sg_nents_for_len(req->dst, req->dst_len); if (src_nents > 1) sec4_sg_len = src_nents; if (dst_nents > 1) sec4_sg_len += dst_nents; sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); /* allocate space for base edesc, hw desc commands and link tables */ edesc = kzalloc(sizeof(*edesc) + desclen + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) return ERR_PTR(-ENOMEM); sgc = dma_map_sg(dev, req->src, src_nents, DMA_TO_DEVICE); if (unlikely(!sgc)) { dev_err(dev, "unable to map source\n"); goto src_fail; } sgc = dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE); if (unlikely(!sgc)) { dev_err(dev, "unable to map destination\n"); goto dst_fail; } edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen; sec4_sg_index = 0; if (src_nents > 1) { sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); sec4_sg_index += src_nents; } if (dst_nents > 1) sg_to_sec4_sg_last(req->dst, dst_nents, edesc->sec4_sg + sec4_sg_index, 0); /* Save nents for later use in Job Descriptor */ edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; if (!sec4_sg_bytes) return edesc; edesc->sec4_sg_dma = dma_map_single(dev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(dev, edesc->sec4_sg_dma)) { dev_err(dev, "unable to map S/G table\n"); goto sec4_sg_fail; } edesc->sec4_sg_bytes = sec4_sg_bytes; return edesc; sec4_sg_fail: dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE); dst_fail: dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); src_fail: kfree(edesc); return ERR_PTR(-ENOMEM); }
static int qat_rsa_dec(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct qat_crypto_instance *inst = ctx->inst; struct device *dev = &GET_DEV(inst->accel_dev); struct qat_rsa_request *qat_req = PTR_ALIGN(akcipher_request_ctx(req), 64); struct icp_qat_fw_pke_request *msg = &qat_req->req; int ret, ctr = 0; if (unlikely(!ctx->n || !ctx->d)) return -EINVAL; if (req->dst_len < ctx->key_sz) { req->dst_len = ctx->key_sz; return -EOVERFLOW; } memset(msg, '\0', sizeof(*msg)); ICP_QAT_FW_PKE_HDR_VALID_FLAG_SET(msg->pke_hdr, ICP_QAT_FW_COMN_REQ_FLAG_SET); msg->pke_hdr.cd_pars.func_id = qat_rsa_dec_fn_id(ctx->key_sz); if (unlikely(!msg->pke_hdr.cd_pars.func_id)) return -EINVAL; qat_req->ctx = ctx; msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; msg->pke_hdr.comn_req_flags = ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, QAT_COMN_CD_FLD_TYPE_64BIT_ADR); qat_req->in.dec.d = ctx->dma_d; qat_req->in.dec.n = ctx->dma_n; ret = -ENOMEM; /* * src can be of any size in valid range, but HW expects it to be the * same as modulo n so in case it is different we need to allocate a * new buf and copy src data. * In other case we just need to map the user provided buffer. */ if (req->src_len < ctx->key_sz) { int shift = ctx->key_sz - req->src_len; qat_req->src_align = dma_zalloc_coherent(dev, ctx->key_sz, &qat_req->in.dec.c, GFP_KERNEL); if (unlikely(!qat_req->src_align)) return ret; memcpy(qat_req->src_align + shift, req->src, req->src_len); } else { qat_req->src_align = NULL; qat_req->in.dec.c = dma_map_single(dev, req->src, req->src_len, DMA_TO_DEVICE); } qat_req->in.in_tab[3] = 0; qat_req->out.dec.m = dma_map_single(dev, req->dst, req->dst_len, DMA_FROM_DEVICE); qat_req->out.out_tab[1] = 0; qat_req->phy_in = dma_map_single(dev, &qat_req->in.dec.c, sizeof(struct qat_rsa_input_params), DMA_TO_DEVICE); qat_req->phy_out = dma_map_single(dev, &qat_req->out.dec.m, sizeof(struct qat_rsa_output_params), DMA_TO_DEVICE); if (unlikely((!qat_req->src_align && dma_mapping_error(dev, qat_req->in.dec.c)) || dma_mapping_error(dev, qat_req->out.dec.m) || dma_mapping_error(dev, qat_req->phy_in) || dma_mapping_error(dev, qat_req->phy_out))) goto unmap; msg->pke_mid.src_data_addr = qat_req->phy_in; msg->pke_mid.dest_data_addr = qat_req->phy_out; msg->pke_mid.opaque = (uint64_t)(__force long)req; msg->input_param_count = 3; msg->output_param_count = 1; do { ret = adf_send_message(ctx->inst->pke_tx, (uint32_t *)msg); } while (ret == -EBUSY && ctr++ < 100); if (!ret) return -EINPROGRESS; unmap: if (qat_req->src_align) dma_free_coherent(dev, ctx->key_sz, qat_req->src_align, qat_req->in.dec.c); else if (!dma_mapping_error(dev, qat_req->in.dec.c)) dma_unmap_single(dev, qat_req->in.dec.c, ctx->key_sz, DMA_TO_DEVICE); if (!dma_mapping_error(dev, qat_req->out.dec.m)) dma_unmap_single(dev, qat_req->out.dec.m, ctx->key_sz, DMA_FROM_DEVICE); if (!dma_mapping_error(dev, qat_req->phy_in)) dma_unmap_single(dev, qat_req->phy_in, sizeof(struct qat_rsa_input_params), DMA_TO_DEVICE); if (!dma_mapping_error(dev, qat_req->phy_out)) dma_unmap_single(dev, qat_req->phy_out, sizeof(struct qat_rsa_output_params), DMA_TO_DEVICE); return ret; }
static int pkcs1pad_sign(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); const struct rsa_asn1_template *digest_info = NULL; int err; unsigned int ps_end, digest_size = 0; if (!ctx->key_size) return -EINVAL; if (ctx->hash_name) { digest_info = rsa_lookup_asn1(ctx->hash_name); if (!digest_info) return -EINVAL; digest_size = digest_info->size; } if (req->src_len + digest_size > ctx->key_size - 11) return -EOVERFLOW; if (req->dst_len < ctx->key_size) { req->dst_len = ctx->key_size; return -EOVERFLOW; } if (ctx->key_size > PAGE_SIZE) return -ENOTSUPP; /* * Replace both input and output to add the padding in the input and * the potential missing leading zeros in the output. */ req_ctx->child_req.src = req_ctx->in_sg; req_ctx->child_req.src_len = ctx->key_size - 1; req_ctx->child_req.dst = req_ctx->out_sg; req_ctx->child_req.dst_len = ctx->key_size; req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC); if (!req_ctx->in_buf) return -ENOMEM; ps_end = ctx->key_size - digest_size - req->src_len - 2; req_ctx->in_buf[0] = 0x01; memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); req_ctx->in_buf[ps_end] = 0x00; if (digest_info) { memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data, digest_info->size); } pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); req_ctx->out_buf = kmalloc(ctx->key_size, (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC); if (!req_ctx->out_buf) { kfree(req_ctx->in_buf); return -ENOMEM; } pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, ctx->key_size, NULL); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_encrypt_sign_complete_cb, req); err = crypto_akcipher_sign(&req_ctx->child_req); if (err != -EINPROGRESS && (err != -EBUSY || !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) return pkcs1pad_encrypt_sign_complete(req, err); return err; }
static int pkcs1pad_encrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); int err; unsigned int i, ps_end; if (!ctx->key_size) return -EINVAL; if (req->src_len > ctx->key_size - 11) return -EOVERFLOW; if (req->dst_len < ctx->key_size) { req->dst_len = ctx->key_size; return -EOVERFLOW; } if (ctx->key_size > PAGE_SIZE) return -ENOTSUPP; /* * Replace both input and output to add the padding in the input and * the potential missing leading zeros in the output. */ req_ctx->child_req.src = req_ctx->in_sg; req_ctx->child_req.src_len = ctx->key_size - 1; req_ctx->child_req.dst = req_ctx->out_sg; req_ctx->child_req.dst_len = ctx->key_size; req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC); if (!req_ctx->in_buf) return -ENOMEM; ps_end = ctx->key_size - req->src_len - 2; req_ctx->in_buf[0] = 0x02; for (i = 1; i < ps_end; i++) req_ctx->in_buf[i] = 1 + prandom_u32_max(255); req_ctx->in_buf[ps_end] = 0x00; pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); req_ctx->out_buf = kmalloc(ctx->key_size, (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC); if (!req_ctx->out_buf) { kfree(req_ctx->in_buf); return -ENOMEM; } pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, ctx->key_size, NULL); akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_encrypt_sign_complete_cb, req); err = crypto_akcipher_encrypt(&req_ctx->child_req); if (err != -EINPROGRESS && (err != -EBUSY || !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) return pkcs1pad_encrypt_sign_complete(req, err); return err; }
static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); struct akcipher_instance *inst = akcipher_alg_instance(tfm); struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst); const struct rsa_asn1_template *digest_info = ictx->digest_info; unsigned int dst_len; unsigned int pos; u8 *out_buf; if (err) goto done; err = -EINVAL; dst_len = req_ctx->child_req.dst_len; if (dst_len < ctx->key_size - 1) goto done; out_buf = req_ctx->out_buf; if (dst_len == ctx->key_size) { if (out_buf[0] != 0x00) /* Decrypted value had no leading 0 byte */ goto done; dst_len--; out_buf++; } err = -EBADMSG; if (out_buf[0] != 0x01) goto done; for (pos = 1; pos < dst_len; pos++) if (out_buf[pos] != 0xff) break; if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00) goto done; pos++; if (digest_info) { if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) goto done; pos += digest_info->size; } err = 0; if (req->dst_len < dst_len - pos) err = -EOVERFLOW; req->dst_len = dst_len - pos; if (!err) sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, req->dst_len), out_buf + pos, req->dst_len); done: kzfree(req_ctx->out_buf); return err; }