Add support for RSASSA-PSS keys and signatures to the PKCS#7 and X.509
implementations.  This requires adding support for algorithm parameters for
keys and signatures as RSASSA-PSS needs metadata.  The ASN.1 encoded data
is converted into a printable key=value list string and passed to the
verification code.

Signed-off-by: David Howells <[email protected]>
cc: Lukas Wunner <[email protected]>
cc: Ignat Korchagin <[email protected]>
cc: Herbert Xu <[email protected]>
cc: [email protected]
cc: [email protected]
---
 crypto/asymmetric_keys/Makefile           |  12 +-
 crypto/asymmetric_keys/mgf1_params.asn1   |  12 ++
 crypto/asymmetric_keys/pkcs7.asn1         |   2 +-
 crypto/asymmetric_keys/pkcs7_parser.c     | 113 ++++++-----
 crypto/asymmetric_keys/public_key.c       |  10 +
 crypto/asymmetric_keys/rsassa_params.asn1 |  25 +++
 crypto/asymmetric_keys/rsassa_parser.c    | 233 ++++++++++++++++++++++
 crypto/asymmetric_keys/rsassa_parser.h    |  25 +++
 crypto/asymmetric_keys/x509.asn1          |   2 +-
 crypto/asymmetric_keys/x509_cert_parser.c |  96 +++++----
 crypto/asymmetric_keys/x509_parser.h      |  33 ++-
 crypto/asymmetric_keys/x509_public_key.c  |  28 ++-
 include/linux/oid_registry.h              |   2 +
 13 files changed, 490 insertions(+), 103 deletions(-)
 create mode 100644 crypto/asymmetric_keys/mgf1_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.c
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.h

diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index bc65d3b98dcb..c5aed382ee8a 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -21,7 +21,11 @@ x509_key_parser-y := \
        x509_akid.asn1.o \
        x509_cert_parser.o \
        x509_loader.o \
-       x509_public_key.o
+       x509_public_key.o \
+       rsassa_params.asn1.o \
+       rsassa_parser.o \
+       mgf1_params.asn1.o
+
 obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o
 x509_selftest-y += selftest.o
 x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_RSA) += selftest_rsa.o
@@ -31,8 +35,14 @@ $(obj)/x509_cert_parser.o: \
        $(obj)/x509.asn1.h \
        $(obj)/x509_akid.asn1.h
 
+$(obj)/rsassa_parser.o: \
+       $(obj)/rsassa_params.asn1.h \
+       $(obj)/mgf1_params.asn1.h
+
 $(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h
 $(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h
+$(obj)/rsassa_params.asn1.o: $(obj)/rsassa_params.asn1.c 
$(obj)/rsassa_params.asn1.h
+$(obj)/mgf1_params.asn1.o: $(obj)/mgf1_params.asn1.c $(obj)/mgf1_params.asn1.h
 
 #
 # PKCS#8 private key handling
diff --git a/crypto/asymmetric_keys/mgf1_params.asn1 
b/crypto/asymmetric_keys/mgf1_params.asn1
new file mode 100644
index 000000000000..c3bc4643e72c
--- /dev/null
+++ b/crypto/asymmetric_keys/mgf1_params.asn1
@@ -0,0 +1,12 @@
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Copyright (C) 2009 IETF Trust and the persons identified as authors
+-- of the code
+--
+--
+-- https://datatracker.ietf.org/doc/html/rfc4055 Section 6.
+
+AlgorithmIdentifier ::= SEQUENCE {
+       algorithm       OBJECT IDENTIFIER ({ mgf1_note_OID }),
+       parameters      ANY OPTIONAL
+}
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 
b/crypto/asymmetric_keys/pkcs7.asn1
index 28e1f4a41c14..03c2248f23bc 100644
--- a/crypto/asymmetric_keys/pkcs7.asn1
+++ b/crypto/asymmetric_keys/pkcs7.asn1
@@ -124,7 +124,7 @@ UnauthenticatedAttribute ::= SEQUENCE {
 
 DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
        algorithm               OBJECT IDENTIFIER ({ pkcs7_note_OID }),
-       parameters              ANY OPTIONAL
+       parameters              ANY OPTIONAL ({ pkcs7_sig_note_algo_params })
 }
 
 EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c 
b/crypto/asymmetric_keys/pkcs7_parser.c
index 90c36fe1b5ed..81996b60c1f1 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -14,6 +14,7 @@
 #include <linux/oid_registry.h>
 #include <crypto/public_key.h>
 #include "pkcs7_parser.h"
+#include "rsassa_parser.h"
 #include "pkcs7.asn1.h"
 
 MODULE_DESCRIPTION("PKCS#7 parser");
@@ -30,6 +31,8 @@ struct pkcs7_parse_context {
        enum OID        last_oid;               /* Last OID encountered */
        unsigned        x509_index;
        unsigned        sinfo_index;
+       unsigned        algo_params_size;
+       const void      *algo_params;
        const void      *raw_serial;
        unsigned        raw_serial_size;
        unsigned        raw_issuer_size;
@@ -225,45 +228,29 @@ int pkcs7_sig_note_digest_algo(void *context, size_t 
hdrlen,
                               const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
+       const char *algo;
 
-       switch (ctx->last_oid) {
-       case OID_sha1:
-               ctx->sinfo->sig->hash_algo = "sha1";
-               break;
-       case OID_sha256:
-               ctx->sinfo->sig->hash_algo = "sha256";
-               break;
-       case OID_sha384:
-               ctx->sinfo->sig->hash_algo = "sha384";
-               break;
-       case OID_sha512:
-               ctx->sinfo->sig->hash_algo = "sha512";
-               break;
-       case OID_sha224:
-               ctx->sinfo->sig->hash_algo = "sha224";
-               break;
-       case OID_sm3:
-               ctx->sinfo->sig->hash_algo = "sm3";
-               break;
-       case OID_gost2012Digest256:
-               ctx->sinfo->sig->hash_algo = "streebog256";
-               break;
-       case OID_gost2012Digest512:
-               ctx->sinfo->sig->hash_algo = "streebog512";
-               break;
-       case OID_sha3_256:
-               ctx->sinfo->sig->hash_algo = "sha3-256";
-               break;
-       case OID_sha3_384:
-               ctx->sinfo->sig->hash_algo = "sha3-384";
-               break;
-       case OID_sha3_512:
-               ctx->sinfo->sig->hash_algo = "sha3-512";
-               break;
-       default:
-               printk("Unsupported digest algo: %u\n", ctx->last_oid);
+       algo = oid_to_hash(ctx->last_oid);
+       if (!algo) {
+               pr_notice("Unsupported digest algo: %u\n", ctx->last_oid);
                return -ENOPKG;
        }
+
+       ctx->sinfo->sig->hash_algo = algo;
+       return 0;
+}
+
+/*
+ * Note the parameters for the signature.
+ */
+int pkcs7_sig_note_algo_params(void *context, size_t hdrlen,
+                              unsigned char tag,
+                              const void *value, size_t vlen)
+{
+       struct pkcs7_parse_context *ctx = context;
+
+       ctx->algo_params = value - hdrlen;
+       ctx->algo_params_size = vlen + hdrlen;
        return 0;
 }
 
@@ -275,12 +262,16 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
                             const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
+       struct public_key_signature *sig = ctx->sinfo->sig;
+       int err;
 
        switch (ctx->last_oid) {
        case OID_rsaEncryption:
-               ctx->sinfo->sig->pkey_algo = "rsa";
-               ctx->sinfo->sig->encoding = "pkcs1";
+               sig->pkey_algo = "rsa";
+               sig->encoding = "pkcs1";
                break;
+       case OID_id_rsassa_pss:
+               goto rsassa_pss;
        case OID_id_ecdsa_with_sha1:
        case OID_id_ecdsa_with_sha224:
        case OID_id_ecdsa_with_sha256:
@@ -289,34 +280,52 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
        case OID_id_ecdsa_with_sha3_256:
        case OID_id_ecdsa_with_sha3_384:
        case OID_id_ecdsa_with_sha3_512:
-               ctx->sinfo->sig->pkey_algo = "ecdsa";
-               ctx->sinfo->sig->encoding = "x962";
+               sig->pkey_algo = "ecdsa";
+               sig->encoding = "x962";
                break;
        case OID_gost2012PKey256:
        case OID_gost2012PKey512:
-               ctx->sinfo->sig->pkey_algo = "ecrdsa";
-               ctx->sinfo->sig->encoding = "raw";
+               sig->pkey_algo = "ecrdsa";
+               sig->encoding = "raw";
                break;
        case OID_id_ml_dsa_44:
-               ctx->sinfo->sig->pkey_algo = "mldsa44";
-               ctx->sinfo->sig->encoding = "raw";
-               ctx->sinfo->sig->algo_does_hash = true;
+               sig->pkey_algo = "mldsa44";
+               sig->encoding = "raw";
+               sig->algo_does_hash = true;
                break;
        case OID_id_ml_dsa_65:
-               ctx->sinfo->sig->pkey_algo = "mldsa65";
-               ctx->sinfo->sig->encoding = "raw";
-               ctx->sinfo->sig->algo_does_hash = true;
+               sig->pkey_algo = "mldsa65";
+               sig->encoding = "raw";
+               sig->algo_does_hash = true;
                break;
        case OID_id_ml_dsa_87:
-               ctx->sinfo->sig->pkey_algo = "mldsa87";
-               ctx->sinfo->sig->encoding = "raw";
-               ctx->sinfo->sig->algo_does_hash = true;
+               sig->pkey_algo = "mldsa87";
+               sig->encoding = "raw";
+               sig->algo_does_hash = true;
                break;
        default:
-               printk("Unsupported pkey algo: %u\n", ctx->last_oid);
+               pr_notice("Unsupported pkey algo: %u\n", ctx->last_oid);
                return -ENOPKG;
        }
+
+out:
+       ctx->algo_params = NULL;
+       ctx->algo_params_size = 0;
        return 0;
+
+rsassa_pss:
+       if (!ctx->algo_params || !ctx->algo_params_size) {
+               pr_debug("RSASSA-PSS sig algo without parameters\n");
+               return -EBADMSG;
+       }
+
+       err = rsassa_parse_sig_params(sig, ctx->algo_params, 
ctx->algo_params_size);
+       if (err < 0)
+               return err;
+
+       sig->pkey_algo = "rsa";
+       sig->encoding = "emsa-pss";
+       goto out;
 }
 
 /*
diff --git a/crypto/asymmetric_keys/public_key.c 
b/crypto/asymmetric_keys/public_key.c
index 61dc4f626620..13a5616becaa 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -100,6 +100,16 @@ software_key_determine_akcipher(const struct public_key 
*pkey,
                        }
                        return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
                }
+               if (strcmp(encoding, "emsa-pss") == 0) {
+                       if (op != kernel_pkey_sign &&
+                           op != kernel_pkey_verify)
+                               return -EINVAL;
+                       *sig = true;
+                       if (!hash_algo)
+                               hash_algo = "none";
+                       n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, 
"rsassa-pss");
+                       return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
+               }
                if (strcmp(encoding, "raw") != 0)
                        return -EINVAL;
                /*
diff --git a/crypto/asymmetric_keys/rsassa_params.asn1 
b/crypto/asymmetric_keys/rsassa_params.asn1
new file mode 100644
index 000000000000..95a4e5f0dcd5
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_params.asn1
@@ -0,0 +1,25 @@
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Copyright (C) 2009 IETF Trust and the persons identified as authors
+-- of the code
+--
+--
+-- https://datatracker.ietf.org/doc/html/rfc4055 Section 6.
+
+RSASSA-PSS-params ::= SEQUENCE {
+       hashAlgorithm      [0] HashAlgorithm,
+       maskGenAlgorithm   [1] MaskGenAlgorithm,
+       saltLength         [2] INTEGER ({ rsassa_note_salt_length }),
+       trailerField       [3] TrailerField OPTIONAL
+}
+
+TrailerField ::= INTEGER ({ rsassa_note_trailer })
+-- { trailerFieldBC(1) }
+
+HashAlgorithm ::= AlgorithmIdentifier ({ rsassa_note_hash_algo })
+MaskGenAlgorithm ::= AlgorithmIdentifier ({ rsassa_note_maskgen_algo })
+
+AlgorithmIdentifier ::= SEQUENCE {
+       algorithm       OBJECT IDENTIFIER ({ rsassa_note_OID }),
+       parameters      ANY OPTIONAL ({ rsassa_note_params })
+}
diff --git a/crypto/asymmetric_keys/rsassa_parser.c 
b/crypto/asymmetric_keys/rsassa_parser.c
new file mode 100644
index 000000000000..8c598517f785
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_parser.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* RSASSA-PSS ASN.1 parameter parser
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ */
+
+#define pr_fmt(fmt) "RSAPSS: "fmt
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/asn1.h>
+#include <crypto/hash.h>
+#include <crypto/hash_info.h>
+#include <crypto/public_key.h>
+#include "x509_parser.h"
+#include "rsassa_parser.h"
+#include "rsassa_params.asn1.h"
+#include "mgf1_params.asn1.h"
+
+struct rsassa_parse_context {
+       struct rsassa_parameters *rsassa;       /* The parsed parameters */
+       unsigned long   data;                   /* Start of data */
+       const void      *params;                /* Algo parameters */
+       unsigned int    params_len;             /* Length of algo parameters */
+       enum OID        last_oid;               /* Last OID encountered */
+       enum OID        mgf1_last_oid;          /* Last OID encountered in MGF1 
*/
+};
+
+/*
+ * Parse an RSASSA parameter block.
+ */
+struct rsassa_parameters *rsassa_params_parse(const void *data, size_t datalen)
+{
+       struct rsassa_parse_context ctx = {};
+       struct rsassa_parameters *rsassa __free(kfree);
+       long ret;
+
+       rsassa = kzalloc(sizeof(*rsassa), GFP_KERNEL);
+       if (!rsassa)
+               return ERR_PTR(-ENOMEM);
+
+       ctx.rsassa = rsassa;
+       ctx.data = (unsigned long)data;
+
+       /* Attempt to decode the parameters */
+       ret = asn1_ber_decoder(&rsassa_params_decoder, &ctx, data, datalen);
+       if (ret < 0) {
+               pr_debug("RSASSA parse failed %ld\n", ret);
+               return ERR_PTR(ret);
+       }
+
+       return no_free_ptr(rsassa);
+}
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int rsassa_note_OID(void *context, size_t hdrlen, unsigned char tag,
+                   const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+
+       ctx->last_oid = look_up_OID(value, vlen);
+       if (ctx->last_oid == OID__NR) {
+               char buffer[56];
+               sprint_oid(value, vlen, buffer, sizeof(buffer));
+               pr_debug("Unknown OID: %s\n", buffer);
+       }
+       return 0;
+}
+
+/*
+ * Parse trailerField.  We only accept trailerFieldBC.
+*/
+int rsassa_note_trailer(void *context, size_t hdrlen, unsigned char tag,
+                       const void *value, size_t vlen)
+{
+       if (vlen != 1 || *(u8 *)value != 0x01) {
+               pr_debug("Unknown trailerField\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int rsassa_note_hash_algo(void *context, size_t hdrlen, unsigned char tag,
+                         const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+
+       ctx->rsassa->hash_algo = ctx->last_oid;
+       pr_debug("HASH-ALGO %u %u\n", ctx->rsassa->hash_algo, ctx->params_len);
+       ctx->params = NULL;
+       return 0;
+}
+
+int rsassa_note_maskgen_algo(void *context, size_t hdrlen, unsigned char tag,
+                            const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+       int ret;
+
+       ctx->rsassa->maskgen_algo = ctx->last_oid;
+       pr_debug("MGF-ALGO %u %u\n", ctx->rsassa->maskgen_algo, 
ctx->params_len);
+
+       switch (ctx->rsassa->maskgen_algo) {
+       case OID_id_mgf1:
+               if (!vlen) {
+                       pr_debug("MGF1 missing parameters\n");
+                       return -EBADMSG;
+               }
+
+               ret = asn1_ber_decoder(&mgf1_params_decoder, ctx,
+                                      ctx->params, ctx->params_len);
+               if (ret < 0) {
+                       pr_debug("MGF1 parse failed %d\n", ret);
+                       return ret;
+               }
+               ctx->rsassa->maskgen_hash = ctx->mgf1_last_oid;
+               break;
+
+       default:
+               pr_debug("Unsupported MaskGenAlgorithm %d\n", ret);
+               return -ENOPKG;
+       }
+
+       ctx->params = NULL;
+       return 0;
+}
+
+int rsassa_note_salt_length(void *context, size_t hdrlen, unsigned char tag,
+                           const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+       u32 salt_len = 0;
+
+       if (!vlen) {
+               pr_debug("Salt len bad integer\n");
+               return -EBADMSG;
+       }
+       if (vlen > 4) {
+               pr_debug("Salt len too long %zu\n", vlen);
+               return -EBADMSG;
+       }
+       if (((u8 *)value)[0] & 0x80) {
+               pr_debug("Salt len negative\n");
+               return -EBADMSG;
+       }
+
+       for (size_t i = 0; i < vlen; i++) {
+               salt_len <<= 8;
+               salt_len |= ((u8 *)value)[i];
+       }
+
+       ctx->rsassa->salt_len = salt_len;
+       pr_debug("Salt-Len %u\n", salt_len);
+       return 0;
+}
+
+/*
+ * Extract arbitrary parameters.
+ */
+int rsassa_note_params(void *context, size_t hdrlen, unsigned char tag,
+                      const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+
+       ctx->params     = value - hdrlen;
+       ctx->params_len = vlen + hdrlen;
+       return 0;
+}
+
+/*
+ * Note an OID when we find one for later processing when we know how to
+ * interpret it.
+ */
+int mgf1_note_OID(void *context, size_t hdrlen, unsigned char tag,
+                 const void *value, size_t vlen)
+{
+       struct rsassa_parse_context *ctx = context;
+
+       ctx->mgf1_last_oid = look_up_OID(value, vlen);
+       if (ctx->mgf1_last_oid == OID__NR) {
+               char buffer[56];
+               sprint_oid(value, vlen, buffer, sizeof(buffer));
+               pr_debug("Unknown MGF1 OID: %s\n", buffer);
+       }
+       return 0;
+}
+
+/*
+ * Parse the signature parameter block and generate a suitable info string from
+ * it.
+ */
+int rsassa_parse_sig_params(struct public_key_signature *sig,
+                           const u8 *sig_params, unsigned int sig_params_size)
+{
+       struct rsassa_parameters *rsassa __free(rsassa_params_free) = NULL;
+       const char *mf, *mh;
+
+       rsassa = rsassa_params_parse(sig_params, sig_params_size);
+       if (IS_ERR(rsassa))
+               return PTR_ERR(rsassa);
+
+       sig->hash_algo = oid_to_hash(rsassa->hash_algo);
+       if (!sig->hash_algo) {
+               pr_notice("Unsupported hash: %u\n", rsassa->hash_algo);
+               return -ENOPKG;
+       }
+
+       switch (rsassa->maskgen_algo) {
+       case OID_id_mgf1:
+               mf = "mgf1";
+               break;
+       default:
+               pr_notice("Unsupported maskgen algo: %u\n", 
rsassa->maskgen_algo);
+               return -ENOPKG;
+       }
+
+       mh = oid_to_hash(rsassa->maskgen_hash);
+       if (!mh) {
+               pr_notice("Unsupported MGF1 hash: %u\n", rsassa->maskgen_hash);
+               return -ENOPKG;
+       }
+
+       sig->info = kasprintf(GFP_KERNEL, "sighash=%s pss_mask=%s,%s 
pss_salt=%u",
+                             sig->hash_algo, mf, mh, rsassa->salt_len);
+       if (!sig->info)
+               return -ENOMEM;
+       pr_debug("Info string: %s\n", sig->info);
+       return 0;
+}
diff --git a/crypto/asymmetric_keys/rsassa_parser.h 
b/crypto/asymmetric_keys/rsassa_parser.h
new file mode 100644
index 000000000000..b80401a3de8f
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_parser.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RSASSA-PSS parameter parsing context
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ */
+
+#include <linux/oid_registry.h>
+
+struct rsassa_parameters {
+       enum OID        hash_algo;              /* Hash algorithm identifier */
+       enum OID        maskgen_algo;           /* Mask gen algorithm 
identifier */
+       enum OID        maskgen_hash;           /* Mask gen hash algorithm 
identifier */
+       u32             salt_len;
+};
+
+struct rsassa_parameters *rsassa_params_parse(const void *data, size_t 
datalen);
+int rsassa_parse_sig_params(struct public_key_signature *sig,
+                           const u8 *sig_params, unsigned int sig_params_size);
+
+static inline void rsassa_params_free(struct rsassa_parameters *params)
+{
+       kfree(params);
+}
+DEFINE_FREE(rsassa_params_free,  struct rsassa_parameters*, 
rsassa_params_free(_T))
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
index feb9573cacce..453b72eba1fe 100644
--- a/crypto/asymmetric_keys/x509.asn1
+++ b/crypto/asymmetric_keys/x509.asn1
@@ -29,7 +29,7 @@ CertificateSerialNumber ::= INTEGER
 
 AlgorithmIdentifier ::= SEQUENCE {
        algorithm               OBJECT IDENTIFIER ({ x509_note_OID }),
-       parameters              ANY OPTIONAL ({ x509_note_params })
+       parameters              ANY OPTIONAL ({ x509_note_algo_id_params })
 }
 
 Name ::= SEQUENCE OF RelativeDistinguishedName
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c 
b/crypto/asymmetric_keys/x509_cert_parser.c
index 5ab5b4e5f1b4..6c431bf181f2 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -15,28 +15,7 @@
 #include "x509_parser.h"
 #include "x509.asn1.h"
 #include "x509_akid.asn1.h"
-
-struct x509_parse_context {
-       struct x509_certificate *cert;          /* Certificate being 
constructed */
-       unsigned long   data;                   /* Start of data */
-       const void      *key;                   /* Key data */
-       size_t          key_size;               /* Size of key data */
-       const void      *params;                /* Key parameters */
-       size_t          params_size;            /* Size of key parameters */
-       enum OID        key_algo;               /* Algorithm used by the cert's 
key */
-       enum OID        last_oid;               /* Last OID encountered */
-       enum OID        sig_algo;               /* Algorithm used to sign the 
cert */
-       u8              o_size;                 /* Size of organizationName (O) 
*/
-       u8              cn_size;                /* Size of commonName (CN) */
-       u8              email_size;             /* Size of emailAddress */
-       u16             o_offset;               /* Offset of organizationName 
(O) */
-       u16             cn_offset;              /* Offset of commonName (CN) */
-       u16             email_offset;           /* Offset of emailAddress */
-       unsigned        raw_akid_size;
-       const void      *raw_akid;              /* Raw authorityKeyId in ASN.1 
*/
-       const void      *akid_raw_issuer;       /* Raw directoryName in 
authorityKeyId */
-       unsigned        akid_raw_issuer_size;
-};
+#include "rsassa_parser.h"
 
 /*
  * Free an X.509 certificate
@@ -104,15 +83,15 @@ struct x509_certificate *x509_cert_parse(const void *data, 
size_t datalen)
 
        cert->pub->keylen = ctx->key_size;
 
-       cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
+       cert->pub->params = kmemdup(ctx->key_params, ctx->key_params_size, 
GFP_KERNEL);
        if (!cert->pub->params)
                return ERR_PTR(-ENOMEM);
 
-       cert->pub->paramlen = ctx->params_size;
+       cert->pub->paramlen = ctx->key_params_size;
        cert->pub->algo = ctx->key_algo;
 
        /* Grab the signature bits */
-       ret = x509_get_sig_params(cert);
+       ret = x509_get_sig_params(cert, ctx);
        if (ret < 0)
                return ERR_PTR(ret);
 
@@ -146,7 +125,7 @@ int x509_note_OID(void *context, size_t hdrlen,
 
        ctx->last_oid = look_up_OID(value, vlen);
        if (ctx->last_oid == OID__NR) {
-               char buffer[50];
+               char buffer[56];
                sprint_oid(value, vlen, buffer, sizeof(buffer));
                pr_debug("Unknown OID: [%lu] %s\n",
                         (unsigned long)value - ctx->data, buffer);
@@ -179,6 +158,7 @@ int x509_note_sig_algo(void *context, size_t hdrlen, 
unsigned char tag,
                       const void *value, size_t vlen)
 {
        struct x509_parse_context *ctx = context;
+       int err;
 
        pr_debug("PubKey Algo: %u\n", ctx->last_oid);
 
@@ -210,6 +190,9 @@ int x509_note_sig_algo(void *context, size_t hdrlen, 
unsigned char tag,
                ctx->cert->sig->hash_algo = "sha1";
                goto ecdsa;
 
+       case OID_id_rsassa_pss:
+               goto rsassa_pss;
+
        case OID_id_rsassa_pkcs1_v1_5_with_sha3_256:
                ctx->cert->sig->hash_algo = "sha3-256";
                goto rsa_pkcs1;
@@ -268,6 +251,24 @@ int x509_note_sig_algo(void *context, size_t hdrlen, 
unsigned char tag,
                goto ml_dsa;
        }
 
+rsassa_pss:
+       if (!ctx->algo_params || !ctx->algo_params_size) {
+               pr_debug("RSASSA-PSS sig algo without parameters\n");
+               return -EBADMSG;
+       }
+
+       err = rsassa_parse_sig_params(ctx->cert->sig,
+                                     ctx->algo_params, ctx->algo_params_size);
+       if (err < 0)
+               return err;
+
+       ctx->cert->sig->pkey_algo = "rsa";
+       ctx->cert->sig->encoding = "emsa-pss";
+       ctx->sig_algo = ctx->last_oid;
+       ctx->algo_params = NULL;
+       ctx->algo_params_size = 0;
+       return 0;
+
 rsa_pkcs1:
        ctx->cert->sig->pkey_algo = "rsa";
        ctx->cert->sig->encoding = "pkcs1";
@@ -324,8 +325,8 @@ int x509_note_signature(void *context, size_t hdrlen,
                vlen--;
        }
 
-       ctx->cert->raw_sig = value;
-       ctx->cert->raw_sig_size = vlen;
+       ctx->sig = value;
+       ctx->sig_size = vlen;
        return 0;
 }
 
@@ -479,23 +480,16 @@ int x509_note_subject(void *context, size_t hdrlen,
 }
 
 /*
- * Extract the parameters for the public key
+ * Extract the parameters for an AlgorithmIdentifier.
  */
-int x509_note_params(void *context, size_t hdrlen,
-                    unsigned char tag,
-                    const void *value, size_t vlen)
+int x509_note_algo_id_params(void *context, size_t hdrlen,
+                            unsigned char tag,
+                            const void *value, size_t vlen)
 {
        struct x509_parse_context *ctx = context;
 
-       /*
-        * AlgorithmIdentifier is used three times in the x509, we should skip
-        * first and ignore third, using second one which is after subject and
-        * before subjectPublicKey.
-        */
-       if (!ctx->cert->raw_subject || ctx->key)
-               return 0;
-       ctx->params = value - hdrlen;
-       ctx->params_size = vlen + hdrlen;
+       ctx->algo_params = value - hdrlen;
+       ctx->algo_params_size = vlen + hdrlen;
        return 0;
 }
 
@@ -514,12 +508,28 @@ int x509_extract_key_data(void *context, size_t hdrlen,
        case OID_rsaEncryption:
                ctx->cert->pub->pkey_algo = "rsa";
                break;
+       case OID_id_rsassa_pss:
+               /* Parameters are optional for the key itself. */
+               if (ctx->algo_params_size) {
+                       struct rsassa_parameters *params 
__free(rsassa_params_free) = NULL;
+                       ctx->key_params = ctx->algo_params;
+                       ctx->key_params_size = ctx->algo_params_size;
+                       ctx->algo_params = NULL;
+                       ctx->algo_params_size = 0;
+
+                       params = rsassa_params_parse(ctx->key_params, 
ctx->key_params_size);
+                       if (IS_ERR(params))
+                               return PTR_ERR(params);
+                       break;
+               }
+               ctx->cert->pub->pkey_algo = "rsa";
+               break;
        case OID_gost2012PKey256:
        case OID_gost2012PKey512:
                ctx->cert->pub->pkey_algo = "ecrdsa";
                break;
        case OID_id_ecPublicKey:
-               if (parse_OID(ctx->params, ctx->params_size, &oid) != 0)
+               if (parse_OID(ctx->algo_params, ctx->algo_params_size, &oid) != 
0)
                        return -EBADMSG;
 
                switch (oid) {
@@ -557,6 +567,8 @@ int x509_extract_key_data(void *context, size_t hdrlen,
                return -EBADMSG;
        ctx->key = value + 1;
        ctx->key_size = vlen - 1;
+       ctx->algo_params = NULL;
+       ctx->algo_params_size = 0;
        return 0;
 }
 
diff --git a/crypto/asymmetric_keys/x509_parser.h 
b/crypto/asymmetric_keys/x509_parser.h
index 0688c222806b..be2e1f6cb9f5 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -23,8 +23,6 @@ struct x509_certificate {
        time64_t        valid_to;
        const void      *tbs;                   /* Signed data */
        unsigned        tbs_size;               /* Size of signed data */
-       unsigned        raw_sig_size;           /* Size of signature */
-       const void      *raw_sig;               /* Signature data */
        const void      *raw_serial;            /* Raw serial number in ASN.1 */
        unsigned        raw_serial_size;
        unsigned        raw_issuer_size;
@@ -41,6 +39,34 @@ struct x509_certificate {
        bool            blacklisted;
 };
 
+struct x509_parse_context {
+       struct x509_certificate *cert;          /* Certificate being 
constructed */
+       unsigned long   data;                   /* Start of data */
+       const void      *key;                   /* Key data */
+       size_t          key_size;               /* Size of key data */
+       const void      *algo_params;           /* AlgorithmIdentifier: 
parameters */
+       size_t          algo_params_size;       /* AlgorithmIdentifier: 
parameters size */
+       const void      *key_params;            /* Key parameters */
+       size_t          key_params_size;        /* Size of key parameters */
+       const void      *sig_params;            /* Signature parameters */
+       unsigned int    sig_params_size;        /* Size of sig parameters */
+       unsigned int    sig_size;               /* Size of signature */
+       const void      *sig;                   /* Signature data */
+       enum OID        key_algo;               /* Algorithm used by the cert's 
key */
+       enum OID        last_oid;               /* Last OID encountered */
+       enum OID        sig_algo;               /* Algorithm used to sign the 
cert */
+       u8              o_size;                 /* Size of organizationName (O) 
*/
+       u8              cn_size;                /* Size of commonName (CN) */
+       u8              email_size;             /* Size of emailAddress */
+       u16             o_offset;               /* Offset of organizationName 
(O) */
+       u16             cn_offset;              /* Offset of commonName (CN) */
+       u16             email_offset;           /* Offset of emailAddress */
+       unsigned        raw_akid_size;
+       const void      *raw_akid;              /* Raw authorityKeyId in ASN.1 
*/
+       const void      *akid_raw_issuer;       /* Raw directoryName in 
authorityKeyId */
+       unsigned        akid_raw_issuer_size;
+};
+
 /*
  * x509_cert_parser.c
  */
@@ -55,5 +81,6 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
 /*
  * x509_public_key.c
  */
-extern int x509_get_sig_params(struct x509_certificate *cert);
+extern const char *oid_to_hash(enum OID oid);
+extern int x509_get_sig_params(struct x509_certificate *cert, struct 
x509_parse_context *parse);
 extern int x509_check_for_self_signed(struct x509_certificate *cert);
diff --git a/crypto/asymmetric_keys/x509_public_key.c 
b/crypto/asymmetric_keys/x509_public_key.c
index 12e3341e806b..b2f8542accc4 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -17,11 +17,32 @@
 #include "asymmetric_keys.h"
 #include "x509_parser.h"
 
+/*
+ * Translate OIDs to hash algorithm names.
+ */
+const char *oid_to_hash(enum OID oid)
+{
+       switch (oid) {
+       case OID_sha1:                  return "sha1";
+       case OID_sha256:                return "sha256";
+       case OID_sha384:                return "sha384";
+       case OID_sha512:                return "sha512";
+       case OID_sha224:                return "sha224";
+       case OID_sm3:                   return "sm3";
+       case OID_gost2012Digest256:     return "streebog256";
+       case OID_gost2012Digest512:     return "streebog512";
+       case OID_sha3_256:              return "sha3-256";
+       case OID_sha3_384:              return "sha3-384";
+       case OID_sha3_512:              return "sha3-512";
+       default:                        return NULL;
+       }
+}
+
 /*
  * Set up the signature parameters in an X.509 certificate.  This involves
  * digesting the signed data and extracting the signature.
  */
-int x509_get_sig_params(struct x509_certificate *cert)
+int x509_get_sig_params(struct x509_certificate *cert, struct 
x509_parse_context *parse)
 {
        struct public_key_signature *sig = cert->sig;
        struct crypto_shash *tfm;
@@ -31,11 +52,11 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
        pr_devel("==>%s()\n", __func__);
 
-       sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
+       sig->s = kmemdup(parse->sig, parse->sig_size, GFP_KERNEL);
        if (!sig->s)
                return -ENOMEM;
 
-       sig->s_size = cert->raw_sig_size;
+       sig->s_size = parse->sig_size;
 
        /* Allocate the hashing algorithm we're going to need and find out how
         * big the hash operational data will be.
@@ -43,6 +64,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
        tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
        if (IS_ERR(tfm)) {
                if (PTR_ERR(tfm) == -ENOENT) {
+                       pr_debug("Unsupported hash %s\n", sig->hash_algo);
                        cert->unsupported_sig = true;
                        return 0;
                }
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index 30821a6a4f72..d546ea7999b9 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -31,6 +31,8 @@ enum OID {
        /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 
pkcs-1(1)} */
        OID_rsaEncryption,              /* 1.2.840.113549.1.1.1 */
        OID_sha1WithRSAEncryption,      /* 1.2.840.113549.1.1.5 */
+       OID_id_mgf1,                    /* 1.2.840.113549.1.1.8 */
+       OID_id_rsassa_pss,              /* 1.2.840.113549.1.1.10 */
        OID_sha256WithRSAEncryption,    /* 1.2.840.113549.1.1.11 */
        OID_sha384WithRSAEncryption,    /* 1.2.840.113549.1.1.12 */
        OID_sha512WithRSAEncryption,    /* 1.2.840.113549.1.1.13 */


Reply via email to