mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
crypto: rsassa-pkcs1 - Migrate to sig_alg backend
A sig_alg backend has just been introduced with the intent of moving all asymmetric sign/verify algorithms to it one by one. Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate rsassa-pkcs1.c which uses the new backend. Consequently there are now two templates which build on the "rsa" akcipher_alg: * The existing "pkcs1pad" template, which is instantiated as an akcipher_instance and retains the encrypt/decrypt operations of RSAES-PKCS1-v1_5 (RFC 8017 sec 7.2). * The new "pkcs1" template, which is instantiated as a sig_instance and contains the sign/verify operations of RSASSA-PKCS1-v1_5 (RFC 8017 sec 8.2). In a separate step, rsa-pkcs1pad.c could optionally be renamed to rsaes-pkcs1.c for clarity. Additional "oaep" and "pss" templates could be added for RSAES-OAEP and RSASSA-PSS. Note that it's currently allowed to allocate a "pkcs1pad(rsa)" transform without specifying a hash algorithm. That makes sense if the transform is only used for encrypt/decrypt and continues to be supported. But for sign/verify, such transforms previously did not insert the Full Hash Prefix into the padding. The resulting message encoding was incompliant with EMSA-PKCS1-v1_5 (RFC 8017 sec 9.2) and therefore nonsensical. From here on in, it is no longer allowed to allocate a transform without specifying a hash algorithm if the transform is used for sign/verify operations. This simplifies the code because the insertion of the Full Hash Prefix is no longer optional, so various "if (digest_info)" clauses can be removed. There has been a previous attempt to forbid transform allocation without specifying a hash algorithm, namely by commitc0d20d22e0
("crypto: rsa-pkcs1pad - Require hash to be present"). It had to be rolled back with commitb3a8c8a5eb
("crypto: rsa-pkcs1pad: Allow hash to be optional [ver #2]"), presumably because it broke allocation of a transform which was solely used for encrypt/decrypt, not sign/verify. Avoid such breakage by allowing transform allocation for encrypt/decrypt with and without specifying a hash algorithm (and simply ignoring the hash algorithm in the former case). So again, specifying a hash algorithm is now mandatory for sign/verify, but optional and ignored for encrypt/decrypt. The new sig_alg API uses kernel buffers instead of sglists, which avoids the overhead of copying signature and digest from sglists back into kernel buffers. rsassa-pkcs1.c is thus simplified quite a bit. sig_alg is always synchronous, whereas the underlying "rsa" akcipher_alg may be asynchronous. So await the result of the akcipher_alg, similar to crypto_akcipher_sync_{en,de}crypt(). As part of the migration, rename "rsa_digest_info" to "hash_prefix" to adhere to the spec language in RFC 9580. Otherwise keep the code unmodified wherever possible to ease reviewing and bisecting. Leave several simplification and hardening opportunities to separate commits. rsassa-pkcs1.c uses modern __free() syntax for allocation of buffers which need to be freed by kfree_sensitive(), hence a DEFINE_FREE() clause for kfree_sensitive() is introduced herein as a byproduct. Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
7964b0d4bd
commit
1e562deace
@ -250,6 +250,7 @@ config CRYPTO_RSA
|
|||||||
tristate "RSA (Rivest-Shamir-Adleman)"
|
tristate "RSA (Rivest-Shamir-Adleman)"
|
||||||
select CRYPTO_AKCIPHER
|
select CRYPTO_AKCIPHER
|
||||||
select CRYPTO_MANAGER
|
select CRYPTO_MANAGER
|
||||||
|
select CRYPTO_SIG
|
||||||
select MPILIB
|
select MPILIB
|
||||||
select ASN1
|
select ASN1
|
||||||
help
|
help
|
||||||
|
@ -48,6 +48,7 @@ rsa_generic-y += rsaprivkey.asn1.o
|
|||||||
rsa_generic-y += rsa.o
|
rsa_generic-y += rsa.o
|
||||||
rsa_generic-y += rsa_helper.o
|
rsa_generic-y += rsa_helper.o
|
||||||
rsa_generic-y += rsa-pkcs1pad.o
|
rsa_generic-y += rsa-pkcs1pad.o
|
||||||
|
rsa_generic-y += rsassa-pkcs1.o
|
||||||
obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
|
obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
|
||||||
|
|
||||||
$(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
|
$(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
|
||||||
|
@ -83,13 +83,19 @@ software_key_determine_akcipher(const struct public_key *pkey,
|
|||||||
if (strcmp(encoding, "pkcs1") == 0) {
|
if (strcmp(encoding, "pkcs1") == 0) {
|
||||||
*sig = op == kernel_pkey_sign ||
|
*sig = op == kernel_pkey_sign ||
|
||||||
op == kernel_pkey_verify;
|
op == kernel_pkey_verify;
|
||||||
if (!hash_algo) {
|
if (!*sig) {
|
||||||
|
/*
|
||||||
|
* For encrypt/decrypt, hash_algo is not used
|
||||||
|
* but allowed to be set for historic reasons.
|
||||||
|
*/
|
||||||
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
||||||
"pkcs1pad(%s)",
|
"pkcs1pad(%s)",
|
||||||
pkey->pkey_algo);
|
pkey->pkey_algo);
|
||||||
} else {
|
} else {
|
||||||
|
if (!hash_algo)
|
||||||
|
return -EINVAL;
|
||||||
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
||||||
"pkcs1pad(%s,%s)",
|
"pkcs1(%s,%s)",
|
||||||
pkey->pkey_algo, hash_algo);
|
pkey->pkey_algo, hash_algo);
|
||||||
}
|
}
|
||||||
return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
|
return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
|
||||||
|
@ -16,101 +16,6 @@
|
|||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
|
|
||||||
*/
|
|
||||||
static const u8 rsa_digest_info_md5[] = {
|
|
||||||
0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
|
|
||||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */
|
|
||||||
0x05, 0x00, 0x04, 0x10
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha1[] = {
|
|
||||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
|
||||||
0x2b, 0x0e, 0x03, 0x02, 0x1a,
|
|
||||||
0x05, 0x00, 0x04, 0x14
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_rmd160[] = {
|
|
||||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
|
||||||
0x2b, 0x24, 0x03, 0x02, 0x01,
|
|
||||||
0x05, 0x00, 0x04, 0x14
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha224[] = {
|
|
||||||
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
|
||||||
0x05, 0x00, 0x04, 0x1c
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha256[] = {
|
|
||||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
|
||||||
0x05, 0x00, 0x04, 0x20
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha384[] = {
|
|
||||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
|
||||||
0x05, 0x00, 0x04, 0x30
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha512[] = {
|
|
||||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
|
||||||
0x05, 0x00, 0x04, 0x40
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha3_256[] = {
|
|
||||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
|
|
||||||
0x05, 0x00, 0x04, 0x20
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha3_384[] = {
|
|
||||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
|
|
||||||
0x05, 0x00, 0x04, 0x30
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 rsa_digest_info_sha3_512[] = {
|
|
||||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
|
||||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A,
|
|
||||||
0x05, 0x00, 0x04, 0x40
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct rsa_asn1_template {
|
|
||||||
const char *name;
|
|
||||||
const u8 *data;
|
|
||||||
size_t size;
|
|
||||||
} rsa_asn1_templates[] = {
|
|
||||||
#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) }
|
|
||||||
_(md5),
|
|
||||||
_(sha1),
|
|
||||||
_(rmd160),
|
|
||||||
_(sha256),
|
|
||||||
_(sha384),
|
|
||||||
_(sha512),
|
|
||||||
_(sha224),
|
|
||||||
#undef _
|
|
||||||
#define _(X) { "sha3-" #X, rsa_digest_info_sha3_##X, sizeof(rsa_digest_info_sha3_##X) }
|
|
||||||
_(256),
|
|
||||||
_(384),
|
|
||||||
_(512),
|
|
||||||
#undef _
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name)
|
|
||||||
{
|
|
||||||
const struct rsa_asn1_template *p;
|
|
||||||
|
|
||||||
for (p = rsa_asn1_templates; p->name; p++)
|
|
||||||
if (strcmp(name, p->name) == 0)
|
|
||||||
return p;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pkcs1pad_ctx {
|
struct pkcs1pad_ctx {
|
||||||
struct crypto_akcipher *child;
|
struct crypto_akcipher *child;
|
||||||
unsigned int key_size;
|
unsigned int key_size;
|
||||||
@ -118,7 +23,6 @@ struct pkcs1pad_ctx {
|
|||||||
|
|
||||||
struct pkcs1pad_inst_ctx {
|
struct pkcs1pad_inst_ctx {
|
||||||
struct crypto_akcipher_spawn spawn;
|
struct crypto_akcipher_spawn spawn;
|
||||||
const struct rsa_asn1_template *digest_info;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pkcs1pad_request {
|
struct pkcs1pad_request {
|
||||||
@ -148,9 +52,9 @@ static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm)
|
|||||||
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
|
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The maximum destination buffer size for the encrypt/sign operations
|
* The maximum destination buffer size for the encrypt operation
|
||||||
* will be the same as for RSA, even though it's smaller for
|
* will be the same as for RSA, even though it's smaller for
|
||||||
* decrypt/verify.
|
* decrypt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return ctx->key_size;
|
return ctx->key_size;
|
||||||
@ -168,7 +72,7 @@ static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len,
|
|||||||
sg_chain(sg, nsegs, next);
|
sg_chain(sg, nsegs, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
|
static int pkcs1pad_encrypt_complete(struct akcipher_request *req, int err)
|
||||||
{
|
{
|
||||||
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
|
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
|
||||||
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
|
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
|
||||||
@ -207,14 +111,14 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pkcs1pad_encrypt_sign_complete_cb(void *data, int err)
|
static void pkcs1pad_encrypt_complete_cb(void *data, int err)
|
||||||
{
|
{
|
||||||
struct akcipher_request *req = data;
|
struct akcipher_request *req = data;
|
||||||
|
|
||||||
if (err == -EINPROGRESS)
|
if (err == -EINPROGRESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = pkcs1pad_encrypt_sign_complete(req, err);
|
err = pkcs1pad_encrypt_complete(req, err);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
akcipher_request_complete(req, err);
|
akcipher_request_complete(req, err);
|
||||||
@ -255,7 +159,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req)
|
|||||||
|
|
||||||
akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
|
akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
|
||||||
akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
|
akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
|
||||||
pkcs1pad_encrypt_sign_complete_cb, req);
|
pkcs1pad_encrypt_complete_cb, req);
|
||||||
|
|
||||||
/* Reuse output buffer */
|
/* Reuse output buffer */
|
||||||
akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
|
akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
|
||||||
@ -263,7 +167,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req)
|
|||||||
|
|
||||||
err = crypto_akcipher_encrypt(&req_ctx->child_req);
|
err = crypto_akcipher_encrypt(&req_ctx->child_req);
|
||||||
if (err != -EINPROGRESS && err != -EBUSY)
|
if (err != -EINPROGRESS && err != -EBUSY)
|
||||||
return pkcs1pad_encrypt_sign_complete(req, err);
|
return pkcs1pad_encrypt_complete(req, err);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -368,195 +272,6 @@ static int pkcs1pad_decrypt(struct akcipher_request *req)
|
|||||||
return 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_info_size = 0;
|
|
||||||
|
|
||||||
if (!ctx->key_size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (digest_info)
|
|
||||||
digest_info_size = digest_info->size;
|
|
||||||
|
|
||||||
if (req->src_len + digest_info_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_info_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_decrypt(&req_ctx->child_req);
|
|
||||||
if (err != -EINPROGRESS && err != -EBUSY)
|
|
||||||
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;
|
|
||||||
const unsigned int sig_size = req->src_len;
|
|
||||||
const unsigned int digest_size = req->dst_len;
|
|
||||||
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 (digest_info->size > dst_len - pos)
|
|
||||||
goto done;
|
|
||||||
if (crypto_memneq(out_buf + pos, digest_info->data,
|
|
||||||
digest_info->size))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pos += digest_info->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
if (digest_size != dst_len - pos) {
|
|
||||||
err = -EKEYREJECTED;
|
|
||||||
req->dst_len = dst_len - pos;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Extract appended digest. */
|
|
||||||
sg_pcopy_to_buffer(req->src,
|
|
||||||
sg_nents_for_len(req->src, sig_size + digest_size),
|
|
||||||
req_ctx->out_buf + ctx->key_size,
|
|
||||||
digest_size, sig_size);
|
|
||||||
/* Do the actual verification step. */
|
|
||||||
if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
|
|
||||||
digest_size) != 0)
|
|
||||||
err = -EKEYREJECTED;
|
|
||||||
done:
|
|
||||||
kfree_sensitive(req_ctx->out_buf);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pkcs1pad_verify_complete_cb(void *data, int err)
|
|
||||||
{
|
|
||||||
struct akcipher_request *req = data;
|
|
||||||
|
|
||||||
if (err == -EINPROGRESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
err = pkcs1pad_verify_complete(req, err);
|
|
||||||
|
|
||||||
out:
|
|
||||||
akcipher_request_complete(req, 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);
|
|
||||||
const unsigned int sig_size = req->src_len;
|
|
||||||
const unsigned int digest_size = req->dst_len;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (WARN_ON(req->dst) || WARN_ON(!digest_size) ||
|
|
||||||
!ctx->key_size || sig_size != ctx->key_size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
req_ctx->out_buf = kmalloc(ctx->key_size + digest_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, sig_size, ctx->key_size);
|
|
||||||
|
|
||||||
err = crypto_akcipher_encrypt(&req_ctx->child_req);
|
|
||||||
if (err != -EINPROGRESS && err != -EBUSY)
|
|
||||||
return pkcs1pad_verify_complete(req, err);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
|
static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
|
||||||
{
|
{
|
||||||
struct akcipher_instance *inst = akcipher_alg_instance(tfm);
|
struct akcipher_instance *inst = akcipher_alg_instance(tfm);
|
||||||
@ -598,7 +313,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
|
|||||||
struct akcipher_instance *inst;
|
struct akcipher_instance *inst;
|
||||||
struct pkcs1pad_inst_ctx *ctx;
|
struct pkcs1pad_inst_ctx *ctx;
|
||||||
struct akcipher_alg *rsa_alg;
|
struct akcipher_alg *rsa_alg;
|
||||||
const char *hash_name;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask);
|
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask);
|
||||||
@ -624,36 +338,15 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = -ENAMETOOLONG;
|
err = -ENAMETOOLONG;
|
||||||
hash_name = crypto_attr_alg_name(tb[2]);
|
if (snprintf(inst->alg.base.cra_name,
|
||||||
if (IS_ERR(hash_name)) {
|
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
|
||||||
if (snprintf(inst->alg.base.cra_name,
|
rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
|
goto err_free_inst;
|
||||||
rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
|
|
||||||
goto err_free_inst;
|
|
||||||
|
|
||||||
if (snprintf(inst->alg.base.cra_driver_name,
|
if (snprintf(inst->alg.base.cra_driver_name,
|
||||||
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
|
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
|
||||||
rsa_alg->base.cra_driver_name) >=
|
rsa_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
CRYPTO_MAX_ALG_NAME)
|
goto err_free_inst;
|
||||||
goto err_free_inst;
|
|
||||||
} else {
|
|
||||||
ctx->digest_info = rsa_lookup_asn1(hash_name);
|
|
||||||
if (!ctx->digest_info) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err_free_inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
|
||||||
"pkcs1pad(%s,%s)", rsa_alg->base.cra_name,
|
|
||||||
hash_name) >= CRYPTO_MAX_ALG_NAME)
|
|
||||||
goto err_free_inst;
|
|
||||||
|
|
||||||
if (snprintf(inst->alg.base.cra_driver_name,
|
|
||||||
CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
|
|
||||||
rsa_alg->base.cra_driver_name,
|
|
||||||
hash_name) >= CRYPTO_MAX_ALG_NAME)
|
|
||||||
goto err_free_inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
|
inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
|
||||||
inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx);
|
inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx);
|
||||||
@ -663,8 +356,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
|
|||||||
|
|
||||||
inst->alg.encrypt = pkcs1pad_encrypt;
|
inst->alg.encrypt = pkcs1pad_encrypt;
|
||||||
inst->alg.decrypt = pkcs1pad_decrypt;
|
inst->alg.decrypt = pkcs1pad_decrypt;
|
||||||
inst->alg.sign = pkcs1pad_sign;
|
|
||||||
inst->alg.verify = pkcs1pad_verify;
|
|
||||||
inst->alg.set_pub_key = pkcs1pad_set_pub_key;
|
inst->alg.set_pub_key = pkcs1pad_set_pub_key;
|
||||||
inst->alg.set_priv_key = pkcs1pad_set_priv_key;
|
inst->alg.set_priv_key = pkcs1pad_set_priv_key;
|
||||||
inst->alg.max_size = pkcs1pad_get_max_size;
|
inst->alg.max_size = pkcs1pad_get_max_size;
|
||||||
|
17
crypto/rsa.c
17
crypto/rsa.c
@ -407,16 +407,25 @@ static int __init rsa_init(void)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = crypto_register_template(&rsa_pkcs1pad_tmpl);
|
err = crypto_register_template(&rsa_pkcs1pad_tmpl);
|
||||||
if (err) {
|
if (err)
|
||||||
crypto_unregister_akcipher(&rsa);
|
goto err_unregister_rsa;
|
||||||
return err;
|
|
||||||
}
|
err = crypto_register_template(&rsassa_pkcs1_tmpl);
|
||||||
|
if (err)
|
||||||
|
goto err_unregister_rsa_pkcs1pad;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_rsa_pkcs1pad:
|
||||||
|
crypto_unregister_template(&rsa_pkcs1pad_tmpl);
|
||||||
|
err_unregister_rsa:
|
||||||
|
crypto_unregister_akcipher(&rsa);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit rsa_exit(void)
|
static void __exit rsa_exit(void)
|
||||||
{
|
{
|
||||||
|
crypto_unregister_template(&rsassa_pkcs1_tmpl);
|
||||||
crypto_unregister_template(&rsa_pkcs1pad_tmpl);
|
crypto_unregister_template(&rsa_pkcs1pad_tmpl);
|
||||||
crypto_unregister_akcipher(&rsa);
|
crypto_unregister_akcipher(&rsa);
|
||||||
}
|
}
|
||||||
|
422
crypto/rsassa-pkcs1.c
Normal file
422
crypto/rsassa-pkcs1.c
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* RSA Signature Scheme with Appendix - PKCS #1 v1.5 (RFC 8017 sec 8.2)
|
||||||
|
*
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc8017#section-8.2
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 - 2024 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/scatterlist.h>
|
||||||
|
#include <crypto/akcipher.h>
|
||||||
|
#include <crypto/algapi.h>
|
||||||
|
#include <crypto/sig.h>
|
||||||
|
#include <crypto/internal/akcipher.h>
|
||||||
|
#include <crypto/internal/rsa.h>
|
||||||
|
#include <crypto/internal/sig.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Full Hash Prefix for EMSA-PKCS1-v1_5 encoding method (RFC 9580 table 24)
|
||||||
|
*
|
||||||
|
* RSA keys are usually much larger than the hash of the message to be signed.
|
||||||
|
* The hash is therefore prepended by the Full Hash Prefix and a 0xff padding.
|
||||||
|
* The Full Hash Prefix is an ASN.1 SEQUENCE containing the hash algorithm OID.
|
||||||
|
*
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9580#table-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const u8 hash_prefix_md5[] = {
|
||||||
|
0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, /* SEQUENCE (SEQUENCE (OID */
|
||||||
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* <algorithm>, */
|
||||||
|
0x05, 0x00, 0x04, 0x10 /* NULL), OCTET STRING <hash>) */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha1[] = {
|
||||||
|
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||||
|
0x2b, 0x0e, 0x03, 0x02, 0x1a,
|
||||||
|
0x05, 0x00, 0x04, 0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_rmd160[] = {
|
||||||
|
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||||
|
0x2b, 0x24, 0x03, 0x02, 0x01,
|
||||||
|
0x05, 0x00, 0x04, 0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha224[] = {
|
||||||
|
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
||||||
|
0x05, 0x00, 0x04, 0x1c
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha256[] = {
|
||||||
|
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||||
|
0x05, 0x00, 0x04, 0x20
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha384[] = {
|
||||||
|
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
||||||
|
0x05, 0x00, 0x04, 0x30
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha512[] = {
|
||||||
|
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
||||||
|
0x05, 0x00, 0x04, 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha3_256[] = {
|
||||||
|
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
|
||||||
|
0x05, 0x00, 0x04, 0x20
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha3_384[] = {
|
||||||
|
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
|
||||||
|
0x05, 0x00, 0x04, 0x30
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 hash_prefix_sha3_512[] = {
|
||||||
|
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
||||||
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a,
|
||||||
|
0x05, 0x00, 0x04, 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hash_prefix {
|
||||||
|
const char *name;
|
||||||
|
const u8 *data;
|
||||||
|
size_t size;
|
||||||
|
} hash_prefixes[] = {
|
||||||
|
#define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
|
||||||
|
_(md5),
|
||||||
|
_(sha1),
|
||||||
|
_(rmd160),
|
||||||
|
_(sha256),
|
||||||
|
_(sha384),
|
||||||
|
_(sha512),
|
||||||
|
_(sha224),
|
||||||
|
#undef _
|
||||||
|
#define _(X) { "sha3-" #X, hash_prefix_sha3_##X, sizeof(hash_prefix_sha3_##X) }
|
||||||
|
_(256),
|
||||||
|
_(384),
|
||||||
|
_(512),
|
||||||
|
#undef _
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
|
||||||
|
{
|
||||||
|
const struct hash_prefix *p;
|
||||||
|
|
||||||
|
for (p = hash_prefixes; p->name; p++)
|
||||||
|
if (strcmp(name, p->name) == 0)
|
||||||
|
return p;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rsassa_pkcs1_ctx {
|
||||||
|
struct crypto_akcipher *child;
|
||||||
|
unsigned int key_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rsassa_pkcs1_inst_ctx {
|
||||||
|
struct crypto_akcipher_spawn spawn;
|
||||||
|
const struct hash_prefix *hash_prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
|
||||||
|
const void *src, unsigned int slen,
|
||||||
|
void *dst, unsigned int dlen)
|
||||||
|
{
|
||||||
|
struct sig_instance *inst = sig_alg_instance(tfm);
|
||||||
|
struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
|
||||||
|
const struct hash_prefix *hash_prefix = ictx->hash_prefix;
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
|
||||||
|
struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
|
||||||
|
struct scatterlist in_sg[2], out_sg;
|
||||||
|
struct crypto_wait cwait;
|
||||||
|
unsigned int pad_len;
|
||||||
|
unsigned int ps_end;
|
||||||
|
unsigned int len;
|
||||||
|
u8 *in_buf;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!ctx->key_size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (dlen < ctx->key_size)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
if (slen + hash_prefix->size > ctx->key_size - 11)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
child_req = kmalloc(sizeof(*child_req) + child_reqsize +
|
||||||
|
ctx->key_size - 1 - slen, GFP_KERNEL);
|
||||||
|
if (!child_req)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */
|
||||||
|
in_buf = (u8 *)(child_req + 1) + child_reqsize;
|
||||||
|
ps_end = ctx->key_size - hash_prefix->size - slen - 2;
|
||||||
|
in_buf[0] = 0x01;
|
||||||
|
memset(in_buf + 1, 0xff, ps_end - 1);
|
||||||
|
in_buf[ps_end] = 0x00;
|
||||||
|
memcpy(in_buf + ps_end + 1, hash_prefix->data, hash_prefix->size);
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.1 step 2 - RSA signature */
|
||||||
|
crypto_init_wait(&cwait);
|
||||||
|
sg_init_table(in_sg, 2);
|
||||||
|
sg_set_buf(&in_sg[0], in_buf, ctx->key_size - 1 - slen);
|
||||||
|
sg_set_buf(&in_sg[1], src, slen);
|
||||||
|
sg_init_one(&out_sg, dst, dlen);
|
||||||
|
akcipher_request_set_tfm(child_req, ctx->child);
|
||||||
|
akcipher_request_set_crypt(child_req, in_sg, &out_sg,
|
||||||
|
ctx->key_size - 1, dlen);
|
||||||
|
akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||||
|
crypto_req_done, &cwait);
|
||||||
|
|
||||||
|
err = crypto_akcipher_decrypt(child_req);
|
||||||
|
err = crypto_wait_req(err, &cwait);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
len = child_req->dst_len;
|
||||||
|
pad_len = ctx->key_size - len;
|
||||||
|
|
||||||
|
/* Four billion to one */
|
||||||
|
if (unlikely(pad_len)) {
|
||||||
|
memmove(dst + pad_len, dst, len);
|
||||||
|
memset(dst, 0, pad_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
|
||||||
|
const void *src, unsigned int slen,
|
||||||
|
const void *digest, unsigned int dlen)
|
||||||
|
{
|
||||||
|
struct sig_instance *inst = sig_alg_instance(tfm);
|
||||||
|
struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
|
||||||
|
const struct hash_prefix *hash_prefix = ictx->hash_prefix;
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
|
||||||
|
struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
|
||||||
|
struct scatterlist in_sg, out_sg;
|
||||||
|
struct crypto_wait cwait;
|
||||||
|
unsigned int dst_len;
|
||||||
|
unsigned int pos;
|
||||||
|
u8 *out_buf;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.2 step 1 - length checking */
|
||||||
|
if (!ctx->key_size ||
|
||||||
|
slen != ctx->key_size ||
|
||||||
|
!dlen)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
|
||||||
|
child_req = kmalloc(sizeof(*child_req) + child_reqsize + ctx->key_size,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!child_req)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
out_buf = (u8 *)(child_req + 1) + child_reqsize;
|
||||||
|
|
||||||
|
crypto_init_wait(&cwait);
|
||||||
|
sg_init_one(&in_sg, src, slen);
|
||||||
|
sg_init_one(&out_sg, out_buf, ctx->key_size);
|
||||||
|
akcipher_request_set_tfm(child_req, ctx->child);
|
||||||
|
akcipher_request_set_crypt(child_req, &in_sg, &out_sg,
|
||||||
|
slen, ctx->key_size);
|
||||||
|
akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||||
|
crypto_req_done, &cwait);
|
||||||
|
|
||||||
|
err = crypto_akcipher_encrypt(child_req);
|
||||||
|
err = crypto_wait_req(err, &cwait);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.2 step 3 - EMSA-PKCS1-v1_5 encoding verification */
|
||||||
|
dst_len = child_req->dst_len;
|
||||||
|
if (dst_len < ctx->key_size - 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (dst_len == ctx->key_size) {
|
||||||
|
if (out_buf[0] != 0x00)
|
||||||
|
/* Encrypted value had no leading 0 byte */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dst_len--;
|
||||||
|
out_buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_buf[0] != 0x01)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
for (pos = 1; pos < dst_len; pos++)
|
||||||
|
if (out_buf[pos] != 0xff)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00)
|
||||||
|
return -EBADMSG;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if (hash_prefix->size > dst_len - pos)
|
||||||
|
return -EBADMSG;
|
||||||
|
if (crypto_memneq(out_buf + pos, hash_prefix->data, hash_prefix->size))
|
||||||
|
return -EBADMSG;
|
||||||
|
pos += hash_prefix->size;
|
||||||
|
|
||||||
|
/* RFC 8017 sec 8.2.2 step 4 - comparison of digest with out_buf */
|
||||||
|
if (dlen != dst_len - pos)
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
if (memcmp(digest, out_buf + pos, dlen) != 0)
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int rsassa_pkcs1_max_size(struct crypto_sig *tfm)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
|
||||||
|
return ctx->key_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_set_pub_key(struct crypto_sig *tfm,
|
||||||
|
const void *key, unsigned int keylen)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
|
||||||
|
return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_set_priv_key(struct crypto_sig *tfm,
|
||||||
|
const void *key, unsigned int keylen)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
|
||||||
|
return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_init_tfm(struct crypto_sig *tfm)
|
||||||
|
{
|
||||||
|
struct sig_instance *inst = sig_alg_instance(tfm);
|
||||||
|
struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
struct crypto_akcipher *child_tfm;
|
||||||
|
|
||||||
|
child_tfm = crypto_spawn_akcipher(&ictx->spawn);
|
||||||
|
if (IS_ERR(child_tfm))
|
||||||
|
return PTR_ERR(child_tfm);
|
||||||
|
|
||||||
|
ctx->child = child_tfm;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rsassa_pkcs1_exit_tfm(struct crypto_sig *tfm)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
|
||||||
|
|
||||||
|
crypto_free_akcipher(ctx->child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rsassa_pkcs1_free(struct sig_instance *inst)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_inst_ctx *ctx = sig_instance_ctx(inst);
|
||||||
|
struct crypto_akcipher_spawn *spawn = &ctx->spawn;
|
||||||
|
|
||||||
|
crypto_drop_akcipher(spawn);
|
||||||
|
kfree(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsassa_pkcs1_create(struct crypto_template *tmpl, struct rtattr **tb)
|
||||||
|
{
|
||||||
|
struct rsassa_pkcs1_inst_ctx *ctx;
|
||||||
|
struct akcipher_alg *rsa_alg;
|
||||||
|
struct sig_instance *inst;
|
||||||
|
const char *hash_name;
|
||||||
|
u32 mask;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
|
||||||
|
if (!inst)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ctx = sig_instance_ctx(inst);
|
||||||
|
|
||||||
|
err = crypto_grab_akcipher(&ctx->spawn, sig_crypto_instance(inst),
|
||||||
|
crypto_attr_alg_name(tb[1]), 0, mask);
|
||||||
|
if (err)
|
||||||
|
goto err_free_inst;
|
||||||
|
|
||||||
|
rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn);
|
||||||
|
|
||||||
|
if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_free_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_name = crypto_attr_alg_name(tb[2]);
|
||||||
|
if (IS_ERR(hash_name)) {
|
||||||
|
err = PTR_ERR(hash_name);
|
||||||
|
goto err_free_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->hash_prefix = rsassa_pkcs1_find_hash_prefix(hash_name);
|
||||||
|
if (!ctx->hash_prefix) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_free_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = -ENAMETOOLONG;
|
||||||
|
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
||||||
|
"pkcs1(%s,%s)", rsa_alg->base.cra_name,
|
||||||
|
hash_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
|
goto err_free_inst;
|
||||||
|
|
||||||
|
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
|
||||||
|
"pkcs1(%s,%s)", rsa_alg->base.cra_driver_name,
|
||||||
|
hash_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
|
goto err_free_inst;
|
||||||
|
|
||||||
|
inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
|
||||||
|
inst->alg.base.cra_ctxsize = sizeof(struct rsassa_pkcs1_ctx);
|
||||||
|
|
||||||
|
inst->alg.init = rsassa_pkcs1_init_tfm;
|
||||||
|
inst->alg.exit = rsassa_pkcs1_exit_tfm;
|
||||||
|
|
||||||
|
inst->alg.sign = rsassa_pkcs1_sign;
|
||||||
|
inst->alg.verify = rsassa_pkcs1_verify;
|
||||||
|
inst->alg.max_size = rsassa_pkcs1_max_size;
|
||||||
|
inst->alg.set_pub_key = rsassa_pkcs1_set_pub_key;
|
||||||
|
inst->alg.set_priv_key = rsassa_pkcs1_set_priv_key;
|
||||||
|
|
||||||
|
inst->free = rsassa_pkcs1_free;
|
||||||
|
|
||||||
|
err = sig_register_instance(tmpl, inst);
|
||||||
|
if (err) {
|
||||||
|
err_free_inst:
|
||||||
|
rsassa_pkcs1_free(inst);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_template rsassa_pkcs1_tmpl = {
|
||||||
|
.name = "pkcs1",
|
||||||
|
.create = rsassa_pkcs1_create,
|
||||||
|
.module = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_ALIAS_CRYPTO("pkcs1");
|
@ -5569,34 +5569,38 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||||||
.cipher = __VECS(fcrypt_pcbc_tv_template)
|
.cipher = __VECS(fcrypt_pcbc_tv_template)
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha224)",
|
.alg = "pkcs1(rsa,sha224)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha256)",
|
.alg = "pkcs1(rsa,sha256)",
|
||||||
.test = alg_test_akcipher,
|
.test = alg_test_sig,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
.suite = {
|
.suite = {
|
||||||
.akcipher = __VECS(pkcs1pad_rsa_tv_template)
|
.sig = __VECS(pkcs1_rsa_tv_template)
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha3-256)",
|
.alg = "pkcs1(rsa,sha3-256)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha3-384)",
|
.alg = "pkcs1(rsa,sha3-384)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha3-512)",
|
.alg = "pkcs1(rsa,sha3-512)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha384)",
|
.alg = "pkcs1(rsa,sha384)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
.alg = "pkcs1pad(rsa,sha512)",
|
.alg = "pkcs1(rsa,sha512)",
|
||||||
|
.test = alg_test_null,
|
||||||
|
.fips_allowed = 1,
|
||||||
|
}, {
|
||||||
|
.alg = "pkcs1pad(rsa)",
|
||||||
.test = alg_test_null,
|
.test = alg_test_null,
|
||||||
.fips_allowed = 1,
|
.fips_allowed = 1,
|
||||||
}, {
|
}, {
|
||||||
|
@ -1268,7 +1268,7 @@ static const struct sig_testvec ecrdsa_tv_template[] = {
|
|||||||
/*
|
/*
|
||||||
* PKCS#1 RSA test vectors. Obtained from CAVS testing.
|
* PKCS#1 RSA test vectors. Obtained from CAVS testing.
|
||||||
*/
|
*/
|
||||||
static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
|
static const struct sig_testvec pkcs1_rsa_tv_template[] = {
|
||||||
{
|
{
|
||||||
.key =
|
.key =
|
||||||
"\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
|
"\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
|
||||||
@ -1380,7 +1380,6 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
|
|||||||
"\xda\x62\x8d\xe1\x2a\x71\x91\x43\x40\x61\x3c\x5a\xbe\x86\xfc\x5b"
|
"\xda\x62\x8d\xe1\x2a\x71\x91\x43\x40\x61\x3c\x5a\xbe\x86\xfc\x5b"
|
||||||
"\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2",
|
"\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2",
|
||||||
.c_size = 256,
|
.c_size = 256,
|
||||||
.siggen_sigver_test = true,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,4 +82,5 @@ static inline int rsa_set_key(struct crypto_akcipher *child,
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern struct crypto_template rsa_pkcs1pad_tmpl;
|
extern struct crypto_template rsa_pkcs1pad_tmpl;
|
||||||
|
extern struct crypto_template rsassa_pkcs1_tmpl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -448,6 +448,7 @@ void kfree_sensitive(const void *objp);
|
|||||||
size_t __ksize(const void *objp);
|
size_t __ksize(const void *objp);
|
||||||
|
|
||||||
DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
|
DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
|
||||||
|
DEFINE_FREE(kfree_sensitive, void *, if (_T) kfree_sensitive(_T))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ksize - Report actual allocation size of associated object
|
* ksize - Report actual allocation size of associated object
|
||||||
|
@ -1114,7 +1114,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
|
|||||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
|
* ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests
|
||||||
* @kmod_name: kernel module name
|
* @kmod_name: kernel module name
|
||||||
*
|
*
|
||||||
* Avoid a verification loop where verifying the signature of the modprobe
|
* Avoid a verification loop where verifying the signature of the modprobe
|
||||||
@ -1128,7 +1128,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
|
|||||||
* algorithm on the fly, but crypto_larval_lookup() will try to use alg_name
|
* algorithm on the fly, but crypto_larval_lookup() will try to use alg_name
|
||||||
* in order to load a kernel module with same name.
|
* in order to load a kernel module with same name.
|
||||||
*
|
*
|
||||||
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
|
* Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules,
|
||||||
* we are safe to fail such module request from crypto_larval_lookup(), and
|
* we are safe to fail such module request from crypto_larval_lookup(), and
|
||||||
* avoid the verification loop.
|
* avoid the verification loop.
|
||||||
*
|
*
|
||||||
@ -1136,7 +1136,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
|
|||||||
*/
|
*/
|
||||||
static int ima_kernel_module_request(char *kmod_name)
|
static int ima_kernel_module_request(char *kmod_name)
|
||||||
{
|
{
|
||||||
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
|
if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user