Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'keys-next-20260206' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull keys update from David Howells:
"This adds support for ML-DSA signatures in X.509 certificates and
PKCS#7/CMS messages, thereby allowing this algorithm to be used for
signing modules, kexec'able binaries, wifi regulatory data, etc..

This requires OpenSSL-3.5 at a minimum and preferably OpenSSL-4 (so
that it can avoid the use of CMS signedAttrs - but that version is not
cut yet). certs/Kconfig does a check to hide the signing options if
OpenSSL does not list the algorithm as being available"

* tag 'keys-next-20260206' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
pkcs7: Change a pr_warn() to pr_warn_once()
pkcs7: Allow authenticatedAttributes for ML-DSA
modsign: Enable ML-DSA module signing
pkcs7, x509: Add ML-DSA support
pkcs7: Allow the signing algo to do whatever digestion it wants itself
pkcs7, x509: Rename ->digest to ->m
x509: Separately calculate sha256 for blacklist
crypto: Add ML-DSA crypto_sig support

+472 -70
+9 -7
Documentation/admin-guide/module-signing.rst
··· 28 28 29 29 This facility uses X.509 ITU-T standard certificates to encode the public keys 30 30 involved. The signatures are not themselves encoded in any industrial standard 31 - type. The built-in facility currently only supports the RSA & NIST P-384 ECDSA 32 - public key signing standard (though it is pluggable and permits others to be 33 - used). The possible hash algorithms that can be used are SHA-2 and SHA-3 of 34 - sizes 256, 384, and 512 (the algorithm is selected by data in the signature). 31 + type. The built-in facility currently only supports the RSA, NIST P-384 ECDSA 32 + and NIST FIPS-204 ML-DSA public key signing standards (though it is pluggable 33 + and permits others to be used). For RSA and ECDSA, the possible hash 34 + algorithms that can be used are SHA-2 and SHA-3 of sizes 256, 384, and 512 (the 35 + algorithm is selected by data in the signature); ML-DSA does its own hashing, 36 + but is allowed to be used with a SHA512 hash for signed attributes. 35 37 36 38 37 39 ========================== ··· 148 146 149 147 file (which is also generated if it does not already exist). 150 148 151 - One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``) and ECDSA 152 - (``MODULE_SIG_KEY_TYPE_ECDSA``) to generate either RSA 4k or NIST 153 - P-384 keypair. 149 + One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``), ECDSA 150 + (``MODULE_SIG_KEY_TYPE_ECDSA``) and ML-DSA (``MODULE_SIG_KEY_TYPE_MLDSA_*``) to 151 + generate an RSA 4k, a NIST P-384 keypair or an ML-DSA 44, 65 or 87 keypair. 154 152 155 153 It is strongly recommended that you provide your own x509.genkey file. 156 154
+40
certs/Kconfig
··· 39 39 Note: Remove all ECDSA signing keys, e.g. certs/signing_key.pem, 40 40 when falling back to building Linux 5.14 and older kernels. 41 41 42 + config MODULE_SIG_KEY_TYPE_MLDSA_44 43 + bool "ML-DSA-44" 44 + select CRYPTO_MLDSA 45 + depends on OPENSSL_SUPPORTS_ML_DSA 46 + help 47 + Use an ML-DSA-44 key (NIST FIPS 204) for module signing. ML-DSA 48 + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With 49 + the latter, the entire module body will be signed; with the former, 50 + signedAttrs will be used as it lacks support for CMS_NOATTR with 51 + ML-DSA. 52 + 53 + config MODULE_SIG_KEY_TYPE_MLDSA_65 54 + bool "ML-DSA-65" 55 + select CRYPTO_MLDSA 56 + depends on OPENSSL_SUPPORTS_ML_DSA 57 + help 58 + Use an ML-DSA-65 key (NIST FIPS 204) for module signing. ML-DSA 59 + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With 60 + the latter, the entire module body will be signed; with the former, 61 + signedAttrs will be used as it lacks support for CMS_NOATTR with 62 + ML-DSA. 63 + 64 + config MODULE_SIG_KEY_TYPE_MLDSA_87 65 + bool "ML-DSA-87" 66 + select CRYPTO_MLDSA 67 + depends on OPENSSL_SUPPORTS_ML_DSA 68 + help 69 + Use an ML-DSA-87 key (NIST FIPS 204) for module signing. ML-DSA 70 + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With 71 + the latter, the entire module body will be signed; with the former, 72 + signedAttrs will be used as it lacks support for CMS_NOATTR with 73 + ML-DSA. 74 + 42 75 endchoice 43 76 44 77 config SYSTEM_TRUSTED_KEYRING ··· 186 153 they are signed and vouched by a certificate from the builtin trusted 187 154 keyring. The PKCS#7 signature of the description is set in the key 188 155 payload. Blacklist keys cannot be removed. 156 + 157 + config OPENSSL_SUPPORTS_ML_DSA 158 + def_bool $(success, openssl list -key-managers | grep -q ML-DSA-87) 159 + help 160 + Support for ML-DSA-44/65/87 was added in openssl-3.5, so as long 161 + as older versions are supported, the key types may only be 162 + set after testing the installed binary for support. 189 163 190 164 endmenu
+3
certs/Makefile
··· 43 43 ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem) 44 44 45 45 keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 46 + keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44) := -newkey ml-dsa-44 47 + keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65) := -newkey ml-dsa-65 48 + keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87) := -newkey ml-dsa-87 46 49 47 50 quiet_cmd_gen_key = GENKEY $@ 48 51 cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+9
crypto/Kconfig
··· 344 344 One of the Russian cryptographic standard algorithms (called GOST 345 345 algorithms). Only signature verification is implemented. 346 346 347 + config CRYPTO_MLDSA 348 + tristate "ML-DSA (Module-Lattice-Based Digital Signature Algorithm)" 349 + select CRYPTO_SIG 350 + select CRYPTO_LIB_MLDSA 351 + help 352 + ML-DSA (Module-Lattice-Based Digital Signature Algorithm) (FIPS-204). 353 + 354 + Only signature verification is implemented. 355 + 347 356 endmenu 348 357 349 358 menu "Block ciphers"
+2
crypto/Makefile
··· 60 60 ecdsa_generic-y += ecdsasignature.asn1.o 61 61 obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o 62 62 63 + obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o 64 + 63 65 crypto_acompress-y := acompress.o 64 66 crypto_acompress-y += scompress.o 65 67 obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
+11
crypto/asymmetric_keys/Kconfig
··· 53 53 This option provides support for parsing PKCS#7 format messages for 54 54 signature data and provides the ability to verify the signature. 55 55 56 + config PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA 57 + bool "Waive rejection of authenticatedAttributes for ML-DSA" 58 + depends on PKCS7_MESSAGE_PARSER 59 + depends on CRYPTO_MLDSA 60 + help 61 + Due to use of CMS_NOATTR with ML-DSA not being supported in 62 + OpenSSL < 4.0 (and thus any released version), enabling this 63 + allows authenticatedAttributes to be used with ML-DSA for 64 + module signing. Use of authenticatedAttributes in this 65 + context is normally rejected. 66 + 56 67 config PKCS7_TEST_KEY 57 68 tristate "PKCS#7 testing key type" 58 69 depends on SYSTEM_DATA_VERIFICATION
+2 -2
crypto/asymmetric_keys/asymmetric_type.c
··· 593 593 { 594 594 struct public_key_signature sig = { 595 595 .s_size = params->in2_len, 596 - .digest_size = params->in_len, 596 + .m_size = params->in_len, 597 597 .encoding = params->encoding, 598 598 .hash_algo = params->hash_algo, 599 - .digest = (void *)in, 599 + .m = (void *)in, 600 600 .s = (void *)in2, 601 601 }; 602 602
+33 -3
crypto/asymmetric_keys/pkcs7_parser.c
··· 92 92 if (!sinfo) 93 93 goto inconsistent; 94 94 95 + #ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA 96 + msg->authattrs_rej_waivable = true; 97 + #endif 98 + 95 99 if (sinfo->authattrs) { 96 100 want = true; 97 101 msg->have_authattrs = true; 102 + #ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA 103 + if (strncmp(sinfo->sig->pkey_algo, "mldsa", 5) != 0) 104 + msg->authattrs_rej_waivable = false; 105 + #endif 106 + } else if (sinfo->sig->algo_takes_data) { 107 + sinfo->sig->hash_algo = "none"; 98 108 } 99 109 100 - for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) 110 + for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) { 101 111 if (!!sinfo->authattrs != want) 102 112 goto inconsistent; 113 + 114 + if (!sinfo->authattrs && 115 + sinfo->sig->algo_takes_data) 116 + sinfo->sig->hash_algo = "none"; 117 + } 103 118 return 0; 104 119 105 120 inconsistent: ··· 311 296 case OID_gost2012PKey512: 312 297 ctx->sinfo->sig->pkey_algo = "ecrdsa"; 313 298 ctx->sinfo->sig->encoding = "raw"; 299 + break; 300 + case OID_id_ml_dsa_44: 301 + ctx->sinfo->sig->pkey_algo = "mldsa44"; 302 + ctx->sinfo->sig->encoding = "raw"; 303 + ctx->sinfo->sig->algo_takes_data = true; 304 + break; 305 + case OID_id_ml_dsa_65: 306 + ctx->sinfo->sig->pkey_algo = "mldsa65"; 307 + ctx->sinfo->sig->encoding = "raw"; 308 + ctx->sinfo->sig->algo_takes_data = true; 309 + break; 310 + case OID_id_ml_dsa_87: 311 + ctx->sinfo->sig->pkey_algo = "mldsa87"; 312 + ctx->sinfo->sig->encoding = "raw"; 313 + ctx->sinfo->sig->algo_takes_data = true; 314 314 break; 315 315 default: 316 316 printk("Unsupported pkey algo: %u\n", ctx->last_oid); ··· 629 599 } 630 600 631 601 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ 632 - sinfo->authattrs = value - (hdrlen - 1); 633 - sinfo->authattrs_len = vlen + (hdrlen - 1); 602 + sinfo->authattrs = value - hdrlen; 603 + sinfo->authattrs_len = vlen + hdrlen; 634 604 return 0; 635 605 } 636 606
+3
crypto/asymmetric_keys/pkcs7_parser.h
··· 55 55 struct pkcs7_signed_info *signed_infos; 56 56 u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ 57 57 bool have_authattrs; /* T if have authattrs */ 58 + #ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA 59 + bool authattrs_rej_waivable; /* T if authatts rejection can be waived */ 60 + #endif 58 61 59 62 /* Content Data (or NULL) */ 60 63 enum OID data_type; /* Type of Data */
+50 -26
crypto/asymmetric_keys/pkcs7_verify.c
··· 30 30 31 31 kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); 32 32 33 + if (!sinfo->authattrs && sig->algo_takes_data) { 34 + /* There's no intermediate digest and the signature algo 35 + * doesn't want the data prehashing. 36 + */ 37 + sig->m = (void *)pkcs7->data; 38 + sig->m_size = pkcs7->data_len; 39 + sig->m_free = false; 40 + return 0; 41 + } 42 + 33 43 /* The digest was calculated already. */ 34 - if (sig->digest) 44 + if (sig->m) 35 45 return 0; 36 46 37 47 if (!sinfo->sig->hash_algo) ··· 55 45 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); 56 46 57 47 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 58 - sig->digest_size = crypto_shash_digestsize(tfm); 48 + sig->m_size = crypto_shash_digestsize(tfm); 59 49 60 50 ret = -ENOMEM; 61 - sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); 62 - if (!sig->digest) 51 + sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL); 52 + if (!sig->m) 63 53 goto error_no_desc; 54 + sig->m_free = true; 64 55 65 56 desc = kzalloc(desc_size, GFP_KERNEL); 66 57 if (!desc) ··· 70 59 desc->tfm = tfm; 71 60 72 61 /* Digest the message [RFC2315 9.3] */ 73 - ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, 74 - sig->digest); 62 + ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m); 75 63 if (ret < 0) 76 64 goto error; 77 - pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest); 65 + pr_devel("MsgDigest = [%*ph]\n", 8, sig->m); 78 66 79 67 /* However, if there are authenticated attributes, there must be a 80 68 * message digest attribute amongst them which corresponds to the 81 69 * digest we just calculated. 82 70 */ 83 71 if (sinfo->authattrs) { 84 - u8 tag; 85 - 86 72 if (!sinfo->msgdigest) { 87 73 pr_warn("Sig %u: No messageDigest\n", sinfo->index); 88 74 ret = -EKEYREJECTED; 89 75 goto error; 90 76 } 91 77 92 - if (sinfo->msgdigest_len != sig->digest_size) { 78 + if (sinfo->msgdigest_len != sig->m_size) { 93 79 pr_warn("Sig %u: Invalid digest size (%u)\n", 94 80 sinfo->index, sinfo->msgdigest_len); 95 81 ret = -EBADMSG; 96 82 goto error; 97 83 } 98 84 99 - if (memcmp(sig->digest, sinfo->msgdigest, 85 + if (memcmp(sig->m, sinfo->msgdigest, 100 86 sinfo->msgdigest_len) != 0) { 101 87 pr_warn("Sig %u: Message digest doesn't match\n", 102 88 sinfo->index); ··· 105 97 * as the contents of the digest instead. Note that we need to 106 98 * convert the attributes from a CONT.0 into a SET before we 107 99 * hash it. 100 + * 101 + * However, for certain algorithms, such as ML-DSA, the digest 102 + * is integrated into the signing algorithm. In such a case, 103 + * we copy the authattrs, modifying the tag type, and set that 104 + * as the digest. 108 105 */ 109 - memset(sig->digest, 0, sig->digest_size); 106 + memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len); 107 + sig->m[0] = ASN1_CONS_BIT | ASN1_SET; 110 108 111 - ret = crypto_shash_init(desc); 112 - if (ret < 0) 113 - goto error; 114 - tag = ASN1_CONS_BIT | ASN1_SET; 115 - ret = crypto_shash_update(desc, &tag, 1); 116 - if (ret < 0) 117 - goto error; 118 - ret = crypto_shash_finup(desc, sinfo->authattrs, 119 - sinfo->authattrs_len, sig->digest); 120 - if (ret < 0) 121 - goto error; 122 - pr_devel("AADigest = [%*ph]\n", 8, sig->digest); 109 + if (sig->algo_takes_data) { 110 + sig->m_size = sinfo->authattrs_len; 111 + ret = 0; 112 + } else { 113 + ret = crypto_shash_digest(desc, sig->m, 114 + sinfo->authattrs_len, 115 + sig->m); 116 + if (ret < 0) 117 + goto error; 118 + } 119 + pr_devel("AADigest = [%*ph]\n", 8, sig->m); 123 120 } 124 121 125 122 error: ··· 150 137 ret = pkcs7_digest(pkcs7, sinfo); 151 138 if (ret) 152 139 return ret; 140 + if (!sinfo->sig->m_free) { 141 + pr_notice_once("%s: No digest available\n", __func__); 142 + return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an 143 + * intermediate digest. */ 144 + } 153 145 154 - *buf = sinfo->sig->digest; 155 - *len = sinfo->sig->digest_size; 146 + *buf = sinfo->sig->m; 147 + *len = sinfo->sig->m_size; 156 148 157 149 i = match_string(hash_algo_name, HASH_ALGO__LAST, 158 150 sinfo->sig->hash_algo); ··· 425 407 return -EKEYREJECTED; 426 408 } 427 409 if (pkcs7->have_authattrs) { 410 + #ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA 411 + if (pkcs7->authattrs_rej_waivable) { 412 + pr_warn_once("Waived invalid module sig (has authattrs)\n"); 413 + break; 414 + } 415 + #endif 428 416 pr_warn("Invalid module sig (has authattrs)\n"); 429 417 return -EKEYREJECTED; 430 418 }
+11 -2
crypto/asymmetric_keys/public_key.c
··· 142 142 if (strcmp(hash_algo, "streebog256") != 0 && 143 143 strcmp(hash_algo, "streebog512") != 0) 144 144 return -EINVAL; 145 + } else if (strcmp(pkey->pkey_algo, "mldsa44") == 0 || 146 + strcmp(pkey->pkey_algo, "mldsa65") == 0 || 147 + strcmp(pkey->pkey_algo, "mldsa87") == 0) { 148 + if (strcmp(encoding, "raw") != 0) 149 + return -EINVAL; 150 + if (!hash_algo) 151 + return -EINVAL; 152 + if (strcmp(hash_algo, "none") != 0 && 153 + strcmp(hash_algo, "sha512") != 0) 154 + return -EINVAL; 145 155 } else { 146 156 /* Unknown public key algorithm */ 147 157 return -ENOPKG; ··· 435 425 if (ret) 436 426 goto error_free_key; 437 427 438 - ret = crypto_sig_verify(tfm, sig->s, sig->s_size, 439 - sig->digest, sig->digest_size); 428 + ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size); 440 429 441 430 error_free_key: 442 431 kfree_sensitive(key);
+2 -1
crypto/asymmetric_keys/signature.c
··· 28 28 for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++) 29 29 kfree(sig->auth_ids[i]); 30 30 kfree(sig->s); 31 - kfree(sig->digest); 31 + if (sig->m_free) 32 + kfree(sig->m); 32 33 kfree(sig); 33 34 } 34 35 }
+26 -1
crypto/asymmetric_keys/x509_cert_parser.c
··· 257 257 case OID_gost2012Signature512: 258 258 ctx->cert->sig->hash_algo = "streebog512"; 259 259 goto ecrdsa; 260 + case OID_id_ml_dsa_44: 261 + ctx->cert->sig->pkey_algo = "mldsa44"; 262 + goto ml_dsa; 263 + case OID_id_ml_dsa_65: 264 + ctx->cert->sig->pkey_algo = "mldsa65"; 265 + goto ml_dsa; 266 + case OID_id_ml_dsa_87: 267 + ctx->cert->sig->pkey_algo = "mldsa87"; 268 + goto ml_dsa; 260 269 } 261 270 262 271 rsa_pkcs1: ··· 281 272 ecdsa: 282 273 ctx->cert->sig->pkey_algo = "ecdsa"; 283 274 ctx->cert->sig->encoding = "x962"; 275 + ctx->sig_algo = ctx->last_oid; 276 + return 0; 277 + ml_dsa: 278 + ctx->cert->sig->algo_takes_data = true; 279 + ctx->cert->sig->hash_algo = "none"; 280 + ctx->cert->sig->encoding = "raw"; 284 281 ctx->sig_algo = ctx->last_oid; 285 282 return 0; 286 283 } ··· 315 300 316 301 if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || 317 302 strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || 318 - strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) { 303 + strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 || 304 + strncmp(ctx->cert->sig->pkey_algo, "mldsa", 5) == 0) { 319 305 /* Discard the BIT STRING metadata */ 320 306 if (vlen < 1 || *(const u8 *)value != 0) 321 307 return -EBADMSG; ··· 539 523 default: 540 524 return -ENOPKG; 541 525 } 526 + break; 527 + case OID_id_ml_dsa_44: 528 + ctx->cert->pub->pkey_algo = "mldsa44"; 529 + break; 530 + case OID_id_ml_dsa_65: 531 + ctx->cert->pub->pkey_algo = "mldsa65"; 532 + break; 533 + case OID_id_ml_dsa_87: 534 + ctx->cert->pub->pkey_algo = "mldsa87"; 542 535 break; 543 536 default: 544 537 return -ENOPKG;
+2
crypto/asymmetric_keys/x509_parser.h
··· 9 9 #include <linux/time.h> 10 10 #include <crypto/public_key.h> 11 11 #include <keys/asymmetric-type.h> 12 + #include <crypto/sha2.h> 12 13 13 14 struct x509_certificate { 14 15 struct x509_certificate *next; 15 16 struct x509_certificate *signer; /* Certificate that signed this one */ 16 17 struct public_key *pub; /* Public key details */ 17 18 struct public_key_signature *sig; /* Signature parameters */ 19 + u8 sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */ 18 20 char *issuer; /* Name of certificate issuer */ 19 21 char *subject; /* Name of certificate subject */ 20 22 struct asymmetric_key_id *id; /* Issuer + Serial number */
+27 -15
crypto/asymmetric_keys/x509_public_key.c
··· 31 31 32 32 pr_devel("==>%s()\n", __func__); 33 33 34 + /* Calculate a SHA256 hash of the TBS and check it against the 35 + * blacklist. 36 + */ 37 + sha256(cert->tbs, cert->tbs_size, cert->sha256); 38 + ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256), 39 + BLACKLIST_HASH_X509_TBS); 40 + if (ret == -EKEYREJECTED) { 41 + pr_err("Cert %*phN is blacklisted\n", 42 + (int)sizeof(cert->sha256), cert->sha256); 43 + cert->blacklisted = true; 44 + ret = 0; 45 + } 46 + 34 47 sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); 35 48 if (!sig->s) 36 49 return -ENOMEM; 37 50 38 51 sig->s_size = cert->raw_sig_size; 52 + 53 + if (sig->algo_takes_data) { 54 + /* The signature algorithm does whatever passes for hashing. */ 55 + sig->m = (u8 *)cert->tbs; 56 + sig->m_size = cert->tbs_size; 57 + sig->m_free = false; 58 + goto out; 59 + } 39 60 40 61 /* Allocate the hashing algorithm we're going to need and find out how 41 62 * big the hash operational data will be. ··· 71 50 } 72 51 73 52 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 74 - sig->digest_size = crypto_shash_digestsize(tfm); 53 + sig->m_size = crypto_shash_digestsize(tfm); 75 54 76 55 ret = -ENOMEM; 77 - sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); 78 - if (!sig->digest) 56 + sig->m = kmalloc(sig->m_size, GFP_KERNEL); 57 + if (!sig->m) 79 58 goto error; 59 + sig->m_free = true; 80 60 81 61 desc = kzalloc(desc_size, GFP_KERNEL); 82 62 if (!desc) ··· 85 63 86 64 desc->tfm = tfm; 87 65 88 - ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, 89 - sig->digest); 90 - 66 + ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m); 91 67 if (ret < 0) 92 68 goto error_2; 93 - 94 - ret = is_hash_blacklisted(sig->digest, sig->digest_size, 95 - BLACKLIST_HASH_X509_TBS); 96 - if (ret == -EKEYREJECTED) { 97 - pr_err("Cert %*phN is blacklisted\n", 98 - sig->digest_size, sig->digest); 99 - cert->blacklisted = true; 100 - ret = 0; 101 - } 102 69 103 70 error_2: 104 71 kfree(desc); 105 72 error: 106 73 crypto_free_shash(tfm); 74 + out: 107 75 pr_devel("<==%s() = %d\n", __func__, ret); 108 76 return ret; 109 77 }
+201
crypto/mldsa.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * crypto_sig wrapper around ML-DSA library. 4 + */ 5 + #include <linux/init.h> 6 + #include <linux/module.h> 7 + #include <crypto/internal/sig.h> 8 + #include <crypto/mldsa.h> 9 + 10 + struct crypto_mldsa_ctx { 11 + u8 pk[MAX(MAX(MLDSA44_PUBLIC_KEY_SIZE, 12 + MLDSA65_PUBLIC_KEY_SIZE), 13 + MLDSA87_PUBLIC_KEY_SIZE)]; 14 + unsigned int pk_len; 15 + enum mldsa_alg strength; 16 + bool key_set; 17 + }; 18 + 19 + static int crypto_mldsa_sign(struct crypto_sig *tfm, 20 + const void *msg, unsigned int msg_len, 21 + void *sig, unsigned int sig_len) 22 + { 23 + return -EOPNOTSUPP; 24 + } 25 + 26 + static int crypto_mldsa_verify(struct crypto_sig *tfm, 27 + const void *sig, unsigned int sig_len, 28 + const void *msg, unsigned int msg_len) 29 + { 30 + const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 31 + 32 + if (unlikely(!ctx->key_set)) 33 + return -EINVAL; 34 + 35 + return mldsa_verify(ctx->strength, sig, sig_len, msg, msg_len, 36 + ctx->pk, ctx->pk_len); 37 + } 38 + 39 + static unsigned int crypto_mldsa_key_size(struct crypto_sig *tfm) 40 + { 41 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 42 + 43 + switch (ctx->strength) { 44 + case MLDSA44: 45 + return MLDSA44_PUBLIC_KEY_SIZE; 46 + case MLDSA65: 47 + return MLDSA65_PUBLIC_KEY_SIZE; 48 + case MLDSA87: 49 + return MLDSA87_PUBLIC_KEY_SIZE; 50 + default: 51 + WARN_ON_ONCE(1); 52 + return 0; 53 + } 54 + } 55 + 56 + static int crypto_mldsa_set_pub_key(struct crypto_sig *tfm, 57 + const void *key, unsigned int keylen) 58 + { 59 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 60 + unsigned int expected_len = crypto_mldsa_key_size(tfm); 61 + 62 + if (keylen != expected_len) 63 + return -EINVAL; 64 + 65 + ctx->pk_len = keylen; 66 + memcpy(ctx->pk, key, keylen); 67 + ctx->key_set = true; 68 + return 0; 69 + } 70 + 71 + static int crypto_mldsa_set_priv_key(struct crypto_sig *tfm, 72 + const void *key, unsigned int keylen) 73 + { 74 + return -EOPNOTSUPP; 75 + } 76 + 77 + static unsigned int crypto_mldsa_max_size(struct crypto_sig *tfm) 78 + { 79 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 80 + 81 + switch (ctx->strength) { 82 + case MLDSA44: 83 + return MLDSA44_SIGNATURE_SIZE; 84 + case MLDSA65: 85 + return MLDSA65_SIGNATURE_SIZE; 86 + case MLDSA87: 87 + return MLDSA87_SIGNATURE_SIZE; 88 + default: 89 + WARN_ON_ONCE(1); 90 + return 0; 91 + } 92 + } 93 + 94 + static int crypto_mldsa44_alg_init(struct crypto_sig *tfm) 95 + { 96 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 97 + 98 + ctx->strength = MLDSA44; 99 + ctx->key_set = false; 100 + return 0; 101 + } 102 + 103 + static int crypto_mldsa65_alg_init(struct crypto_sig *tfm) 104 + { 105 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 106 + 107 + ctx->strength = MLDSA65; 108 + ctx->key_set = false; 109 + return 0; 110 + } 111 + 112 + static int crypto_mldsa87_alg_init(struct crypto_sig *tfm) 113 + { 114 + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); 115 + 116 + ctx->strength = MLDSA87; 117 + ctx->key_set = false; 118 + return 0; 119 + } 120 + 121 + static void crypto_mldsa_alg_exit(struct crypto_sig *tfm) 122 + { 123 + } 124 + 125 + static struct sig_alg crypto_mldsa_algs[] = { 126 + { 127 + .sign = crypto_mldsa_sign, 128 + .verify = crypto_mldsa_verify, 129 + .set_pub_key = crypto_mldsa_set_pub_key, 130 + .set_priv_key = crypto_mldsa_set_priv_key, 131 + .key_size = crypto_mldsa_key_size, 132 + .max_size = crypto_mldsa_max_size, 133 + .init = crypto_mldsa44_alg_init, 134 + .exit = crypto_mldsa_alg_exit, 135 + .base.cra_name = "mldsa44", 136 + .base.cra_driver_name = "mldsa44-lib", 137 + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), 138 + .base.cra_module = THIS_MODULE, 139 + .base.cra_priority = 5000, 140 + }, { 141 + .sign = crypto_mldsa_sign, 142 + .verify = crypto_mldsa_verify, 143 + .set_pub_key = crypto_mldsa_set_pub_key, 144 + .set_priv_key = crypto_mldsa_set_priv_key, 145 + .key_size = crypto_mldsa_key_size, 146 + .max_size = crypto_mldsa_max_size, 147 + .init = crypto_mldsa65_alg_init, 148 + .exit = crypto_mldsa_alg_exit, 149 + .base.cra_name = "mldsa65", 150 + .base.cra_driver_name = "mldsa65-lib", 151 + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), 152 + .base.cra_module = THIS_MODULE, 153 + .base.cra_priority = 5000, 154 + }, { 155 + .sign = crypto_mldsa_sign, 156 + .verify = crypto_mldsa_verify, 157 + .set_pub_key = crypto_mldsa_set_pub_key, 158 + .set_priv_key = crypto_mldsa_set_priv_key, 159 + .key_size = crypto_mldsa_key_size, 160 + .max_size = crypto_mldsa_max_size, 161 + .init = crypto_mldsa87_alg_init, 162 + .exit = crypto_mldsa_alg_exit, 163 + .base.cra_name = "mldsa87", 164 + .base.cra_driver_name = "mldsa87-lib", 165 + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), 166 + .base.cra_module = THIS_MODULE, 167 + .base.cra_priority = 5000, 168 + }, 169 + }; 170 + 171 + static int __init mldsa_init(void) 172 + { 173 + int ret, i; 174 + 175 + for (i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) { 176 + ret = crypto_register_sig(&crypto_mldsa_algs[i]); 177 + if (ret < 0) 178 + goto error; 179 + } 180 + return 0; 181 + 182 + error: 183 + pr_err("Failed to register (%d)\n", ret); 184 + for (i--; i >= 0; i--) 185 + crypto_unregister_sig(&crypto_mldsa_algs[i]); 186 + return ret; 187 + } 188 + module_init(mldsa_init); 189 + 190 + static void mldsa_exit(void) 191 + { 192 + for (int i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) 193 + crypto_unregister_sig(&crypto_mldsa_algs[i]); 194 + } 195 + module_exit(mldsa_exit); 196 + 197 + MODULE_LICENSE("GPL"); 198 + MODULE_DESCRIPTION("Crypto API support for ML-DSA signature verification"); 199 + MODULE_ALIAS_CRYPTO("mldsa44"); 200 + MODULE_ALIAS_CRYPTO("mldsa65"); 201 + MODULE_ALIAS_CRYPTO("mldsa87");
+4 -2
include/crypto/public_key.h
··· 43 43 struct public_key_signature { 44 44 struct asymmetric_key_id *auth_ids[3]; 45 45 u8 *s; /* Signature */ 46 - u8 *digest; 46 + u8 *m; /* Message data to pass to verifier */ 47 47 u32 s_size; /* Number of bytes in signature */ 48 - u32 digest_size; /* Number of bytes in digest */ 48 + u32 m_size; /* Number of bytes in ->m */ 49 + bool m_free; /* T if ->m needs freeing */ 50 + bool algo_takes_data; /* T if public key algo operates on data, not a hash */ 49 51 const char *pkey_algo; 50 52 const char *hash_algo; 51 53 const char *encoding;
+5
include/linux/oid_registry.h
··· 145 145 OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */ 146 146 OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */ 147 147 148 + /* NIST FIPS-204 ML-DSA */ 149 + OID_id_ml_dsa_44, /* 2.16.840.1.101.3.4.3.17 */ 150 + OID_id_ml_dsa_65, /* 2.16.840.1.101.3.4.3.18 */ 151 + OID_id_ml_dsa_87, /* 2.16.840.1.101.3.4.3.19 */ 152 + 148 153 OID__NR 149 154 }; 150 155
+30 -9
scripts/sign-file.c
··· 27 27 #include <openssl/evp.h> 28 28 #include <openssl/pem.h> 29 29 #include <openssl/err.h> 30 - #if OPENSSL_VERSION_MAJOR >= 3 30 + #if OPENSSL_VERSION_NUMBER >= 0x30000000L 31 31 # define USE_PKCS11_PROVIDER 32 32 # include <openssl/provider.h> 33 33 # include <openssl/store.h> ··· 315 315 ERR(!digest_algo, "EVP_get_digestbyname"); 316 316 317 317 #ifndef USE_PKCS7 318 + 319 + unsigned int flags = 320 + CMS_NOCERTS | 321 + CMS_PARTIAL | 322 + CMS_BINARY | 323 + CMS_DETACHED | 324 + CMS_STREAM | 325 + CMS_NOSMIMECAP | 326 + #ifdef CMS_NO_SIGNING_TIME 327 + CMS_NO_SIGNING_TIME | 328 + #endif 329 + use_keyid; 330 + 331 + #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L 332 + if (EVP_PKEY_is_a(private_key, "ML-DSA-44") || 333 + EVP_PKEY_is_a(private_key, "ML-DSA-65") || 334 + EVP_PKEY_is_a(private_key, "ML-DSA-87")) { 335 + /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5 336 + * and before. 337 + */ 338 + use_signed_attrs = 0; 339 + } 340 + #endif 341 + 342 + flags |= use_signed_attrs; 343 + 318 344 /* Load the signature message from the digest buffer. */ 319 - cms = CMS_sign(NULL, NULL, NULL, NULL, 320 - CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | 321 - CMS_DETACHED | CMS_STREAM); 345 + cms = CMS_sign(NULL, NULL, NULL, NULL, flags); 322 346 ERR(!cms, "CMS_sign"); 323 347 324 - ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, 325 - CMS_NOCERTS | CMS_BINARY | 326 - CMS_NOSMIMECAP | use_keyid | 327 - use_signed_attrs), 348 + ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags), 328 349 "CMS_add1_signer"); 329 - ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1, 350 + ERR(CMS_final(cms, bm, NULL, flags) != 1, 330 351 "CMS_final"); 331 352 332 353 #else
+2 -2
security/integrity/digsig_asymmetric.c
··· 121 121 goto out; 122 122 } 123 123 124 - pks.digest = (u8 *)data; 125 - pks.digest_size = datalen; 124 + pks.m = (u8 *)data; 125 + pks.m_size = datalen; 126 126 pks.s = hdr->sig; 127 127 pks.s_size = siglen; 128 128 ret = verify_signature(key, &pks);