diff --git a/Documentation/ABI/testing/sysfs-devices-spdm b/Documentation/ABI/testing/sysfs-devices-spdm new file mode 100644 index 00000000000000..ae645052578fe8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-spdm @@ -0,0 +1,247 @@ +What: /sys/devices/.../authenticated +Date: June 2024 +Contact: Lukas Wunner +Description: + This file contains 1 if the device authenticated successfully + with SPDM (Security Protocol and Data Model). It contains 0 if + the device failed authentication (and may thus be malicious). + + Writing "re" to this file causes reauthentication. + That may be opportune after updating the device keyring. + The device keyring of the PCI bus is named ".cma" + (Component Measurement and Authentication). + + Reauthentication may also be necessary after device identity + has mutated, e.g. after downloading firmware to an FPGA device. + + The file is not visible if authentication is unsupported + by the device. + + If the kernel could not determine whether authentication is + supported because memory was low or communication with the + device was not working, the file is visible but accessing it + fails with error code ENOTTY. + + This prevents downgrade attacks where an attacker consumes + memory or disturbs communication in order to create the + appearance that a device does not support authentication. + + The reason why authentication support could not be determined + is apparent from "dmesg". To re-probe authentication support + of PCI devices, exercise the "remove" and "rescan" attributes. + + +What: /sys/devices/.../certificates/ +What: /sys/devices/.../certificates/slot[0-7] +Date: June 2024 +Contact: Lukas Wunner +Description: + The "certificates" directory provides access to the certificate + chains contained in the up to 8 slots of a device. + + A certificate chain is the concatenation of one or more ASN.1 + DER-encoded X.509 v3 certificates (SPDM 1.0.0 sec 4.9.2.1). + It can be examined as follows:: + + # openssl storeutl -text certificates/slot0 + + A common use case is to add the first certificate in a chain + to the keyring of trusted root certificates (".cma" in this + example) after comparing its fingerprint to the one provided + by the device manufacturer:: + + # openssl x509 -in certificates/slot0 -fingerprint -nocert + # keyctl padd asymmetric "" %:.cma < certificates/slot0 + # echo re > authenticated + + The file size of each slot is always 65535 bytes (the maximum + size of a certificate chain per SPDM 1.0.0 table 18), even if + the certificate chain in the slot is actually smaller. + + Unprovisioned slots are represented as empty files. + + Unsupported slots (introduced by SPDM 1.3 margin no 366) are + not visible. If the device only supports SPDM version 1.2 or + earlier, all 8 slots are assumed to be supported and therefore + visible. + + The kernel learns which slots are supported when authenticating + the device for the first time. Hence, no slots are visible + until at least one authentication attempt has been performed. + + SPDM doesn't support on-demand retrieval of certificate chains, + so the kernel caches them when (re-)authenticating the device. + SPDM allows provisioning slots behind the kernel's back by + sending a SET_CERTIFICATE request through a different transport + (e.g. via MCTP from a Baseboard Management Controller). + SPDM does not specify how to notify the kernel of such events, + so unless reauthentication is manually initiated to update the + kernel's cache, the "slot[0-7]" files may contain stale data. + + +What: /sys/devices/.../signatures/ +What: /sys/devices/.../signatures/[0-9]*_signature +What: /sys/devices/.../signatures/[0-9]*_transcript +What: /sys/devices/.../signatures/[0-9]*_hash_algorithm +What: /sys/devices/.../signatures/[0-9]*_combined_spdm_prefix +What: /sys/devices/.../signatures/[0-9]*_certificate_chain +Date: June 2024 +Contact: Lukas Wunner +Description: + The "signatures" directory contains a log of signatures + received from the device to allow for their re-verification. + It is meant for remote attestation services which do not trust + the kernel to have verified the signatures correctly or which + want to apply policy constraints of their own. + + Each signature is exposed as a separate file. The filename + is prefixed with a monotonically increasing, unsigned, 32 bit + number, starting at 0. + + The signature is computed over the "transcript" file, which is + a concatenation of all SPDM messages exchanged with the device. + SPDM 1.2 and newer hash the transcript with "hash_algorithm" + and prepend the "combined_spdm_prefix" before computing the + signature (SPDM 1.2.0 sec 15). For SPDM 1.0 and 1.1, that step + is omitted and "combined_spdm_prefix" is an empty file. + + The signature is verified against the leaf certificate in the + "certificate_chain". To save memory, "certificate_chain" is + a symbolic link to the slot used for signature generation. + If the slot has since been provisioned with a different + certificate chain, verification of the signature will fail. + + In bash syntax, the signature is verified as follows:: + + # number of signature to verify + num=0 + + # split certificate chain into individual certificates + openssl storeutl -text ${num}_certificate_chain | \ + csplit -z -f /tmp/cert - '/^[0-9]*: Certificate$/' '{*}' + + # extract public key from leaf certificate + leaf_cert=$(\ls /tmp/cert?? | tail -1) + openssl x509 -pubkey -in ${leaf_cert} -out ${leaf_cert}.pub + + # verify signature + if [ \! -s ${num}_combined_spdm_prefix ] ; then + # SPDM 1.0 and 1.1 + openssl dgst -$(cat ${num}_hash_algorithm) \ + -signature ${num}_signature -verify ${leaf_cert}.pub \ + ${num}_transcript + else + # SPDM 1.2 and newer + openssl dgst -$(cat ${num}_hash_algorithm) \ + -binary -out /tmp/transcript_hashed ${num}_transcript + openssl dgst -$(cat ${num}_hash_algorithm) \ + -signature ${num}_signature -verify ${leaf_cert}.pub \ + ${num}_combined_spdm_prefix /tmp/transcript_hashed + fi + + Note: The above works for RSA signatures, but not for ECDSA. + SPDM encodes ECDSA signatures in P1363 format (concatenation of + two raw integers), whereas openssl only supports X9.62 format + (ASN.1 DER sequence of two integers). There is no command line + utility to convert between the two formats, but most popular + crypto libraries offer conversion routines: + + | https://github.com/java-crypto/cross_platform_crypto/blob/main/docs/ecdsa_signature_conversion.md + + The "transcript" file can be fed to a protocol dissector to + examine the SPDM messages it contains: + + | https://github.com/th-duvanel/spdm-wid + | https://github.com/jyao1/wireshark-spdm + | https://github.com/DMTF/spdm-dump + + Note: To ease signature verification, the "transcript" file + does not contain the trailing signature. However the signature + is part of the final CHALLENGE_AUTH or MEASUREMENT message, + so the protocol dissector needs to be fed the concatenation of + "transcript" and "signature". + + Signatures are added to the log even if the kernel was unable + to verify them (e.g. due to a missing trusted root certificate + or forged signature). Thereby, remote attestation services + may make up their own mind on the signature's validity. + + Because the number prefixed to the filenames is 32 bit, it + wraps around to 0 after 4,294,967,295 signatures. The kernel + avoids filename collisions on wraparound by purging old files, + subject to the limit set by "sysctl spdm.max_signatures_size" + (which defaults to 16 MiB). It is advisable to regularly save + backups on non-volatile storage to retain access to signatures + that have been purged (or across reboots):: + + # tar -u -h -f /path/to/signatures.tar signatures/ + + The ctime of each file is the reception time of the signature. + However if the signature was received before the device became + registered in sysfs, the ctime is the registration time of the + device. + + +What: /sys/devices/.../signatures/[0-9]*_type +Date: June 2024 +Contact: Lukas Wunner +Description: + This file contains the type of event that led to signature + generation. It is one of (sans quotes): + + "responder-challenge_auth signing" + "responder-measurements signing" + + +What: /sys/devices/.../signatures/[0-9]*_requester_nonce +What: /sys/devices/.../signatures/[0-9]*_responder_nonce +Date: June 2024 +Contact: Lukas Wunner +Description: + These files contain the 32 byte nonce chosen by requester and + responder. They allow remote attestation services to verify + freshness (uniqueness) of the nonces. Nonces used more than + once can be identified with:: + + # hexdump -e '32/1 "%02x" "\n"' [0-9]*_nonce | sort | \ + uniq -c | grep -v '^ 1' + + Remote attestation services may also want to verify that the + entropy of the nonces is acceptable:: + + # ent 0_requester_nonce + + Note: The nonces are also contained in the "transcript", but + their offsets within the transcript are variable. It would be + necessary to parse the SPDM messages in the transcript to find + and extract the nonces, which is cumbersome. That's why they + are exposed as separate files. + + +What: /sys/devices/.../signatures/next_requester_nonce +Date: June 2024 +Contact: Lukas Wunner +Description: + If you do not trust the kernel to always use a fresh nonce, + write 32 bytes to this file to set the requester nonce used + in the next SPDM authentication or measurement sequence. + + Meant for remote attestation services. You are responsible + for providing a nonce with sufficient entropy. The kernel + only uses the nonce once, so provide a new one every time + you reauthenticate or measure the device. If you do not + provide a nonce, the kernel generates a random one. + + After the nonce has been consumed, it becomes readable as + the newest [0-9]*_requester_nonce, which proves its usage:: + + # dd if=/dev/random bs=32 count=1 | \ + tee signatures/next_requester_nonce | hexdump + 0000000 e0 77 91 54 bd 56 99 c2 ea 4f 0b 1a 7f ba 6e 59 + 0000010 8f ee f6 b2 26 82 58 34 9e e5 8c 8a 31 58 29 7e + + # echo re > authenticated + + # hexdump $(\ls -t signatures/[0-9]*_requester_nonce | head -1) + 0000000 e0 77 91 54 bd 56 99 c2 ea 4f 0b 1a 7f ba 6e 59 + 0000010 8f ee f6 b2 26 82 58 34 9e e5 8c 8a 31 58 29 7e diff --git a/Documentation/admin-guide/sysctl/index.rst b/Documentation/admin-guide/sysctl/index.rst index 03346f98c7b96e..3b48f0039069b9 100644 --- a/Documentation/admin-guide/sysctl/index.rst +++ b/Documentation/admin-guide/sysctl/index.rst @@ -76,6 +76,7 @@ kernel/ global kernel info / tuning net/ networking stuff, for documentation look in: proc/ +spdm/ Security Protocol and Data Model (SPDM) sunrpc/ SUN Remote Procedure Call (NFS) vm/ memory management tuning buffer and cache management @@ -93,6 +94,7 @@ really like to hear about it :-) fs kernel net + spdm sunrpc user vm diff --git a/Documentation/admin-guide/sysctl/spdm.rst b/Documentation/admin-guide/sysctl/spdm.rst new file mode 100644 index 00000000000000..c6552f0290125d --- /dev/null +++ b/Documentation/admin-guide/sysctl/spdm.rst @@ -0,0 +1,33 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +Documentation for /proc/sys/spdm/ +================================= + +Copyright (C) 2024 Intel Corporation + +This directory allows tuning Security Protocol and Data Model (SPDM) +parameters. SPDM enables device authentication, measurement, key +exchange and encrypted sessions. + +max_signatures_size +=================== + +Maximum amount of memory occupied by the log of signatures (per device, +in bytes, 16 MiB by default). + +The log is meant for re-verification of signatures by remote attestation +services which do not trust the kernel to have verified the signatures +correctly or which want to apply policy constraints of their own. +A signature is computed over the transcript (a concatenation of all +SPDM messages exchanged with the device during an authentication or +measurement sequence). The transcript can be a few kBytes or up to +several MBytes in size, hence this parameter prevents the log from +consuming too much memory. + +The kernel always stores the most recent signature in the log even if it +exceeds ``max_signatures_size``. Additionally as many older signatures +are kept in the log as this limit allows. + +If you reduce the limit, signatures are purged immediately to free up +memory. diff --git a/Documentation/crypto/api-akcipher.rst b/Documentation/crypto/api-akcipher.rst index 40aa8746e2a1f2..6f47cc70eca032 100644 --- a/Documentation/crypto/api-akcipher.rst +++ b/Documentation/crypto/api-akcipher.rst @@ -11,7 +11,7 @@ Asymmetric Cipher API :doc: Generic Public Key API .. kernel-doc:: include/crypto/akcipher.h - :functions: crypto_alloc_akcipher crypto_free_akcipher crypto_akcipher_set_pub_key crypto_akcipher_set_priv_key crypto_akcipher_maxsize crypto_akcipher_encrypt crypto_akcipher_decrypt crypto_akcipher_sign crypto_akcipher_verify + :functions: crypto_alloc_akcipher crypto_free_akcipher crypto_akcipher_set_pub_key crypto_akcipher_set_priv_key crypto_akcipher_maxsize crypto_akcipher_encrypt crypto_akcipher_decrypt Asymmetric Cipher Request Handle -------------------------------- diff --git a/Documentation/crypto/api-sig.rst b/Documentation/crypto/api-sig.rst new file mode 100644 index 00000000000000..aaec18e26d545f --- /dev/null +++ b/Documentation/crypto/api-sig.rst @@ -0,0 +1,15 @@ +Asymmetric Signature Algorithm Definitions +------------------------------------------ + +.. kernel-doc:: include/crypto/sig.h + :functions: sig_alg + +Asymmetric Signature API +------------------------ + +.. kernel-doc:: include/crypto/sig.h + :doc: Generic Public Key Signature API + +.. kernel-doc:: include/crypto/sig.h + :functions: crypto_alloc_sig crypto_free_sig crypto_sig_set_pubkey crypto_sig_set_privkey crypto_sig_keysize crypto_sig_maxsize crypto_sig_digestsize crypto_sig_sign crypto_sig_verify + diff --git a/Documentation/crypto/api.rst b/Documentation/crypto/api.rst index ff31c30561d4f6..8b2a905218862d 100644 --- a/Documentation/crypto/api.rst +++ b/Documentation/crypto/api.rst @@ -10,4 +10,5 @@ Programming Interface api-digest api-rng api-akcipher + api-sig api-kpp diff --git a/Documentation/crypto/architecture.rst b/Documentation/crypto/architecture.rst index 646c3380a7edc4..15dcd62fd22f26 100644 --- a/Documentation/crypto/architecture.rst +++ b/Documentation/crypto/architecture.rst @@ -214,6 +214,8 @@ the aforementioned cipher types: - CRYPTO_ALG_TYPE_AKCIPHER Asymmetric cipher +- CRYPTO_ALG_TYPE_SIG Asymmetric signature + - CRYPTO_ALG_TYPE_PCOMPRESS Enhanced version of CRYPTO_ALG_TYPE_COMPRESS allowing for segmented compression / decompression instead of performing the operation on one segment diff --git a/MAINTAINERS b/MAINTAINERS index c27f3190737f8b..165d4d246c01f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20836,6 +20836,20 @@ M: Security Officers S: Supported F: Documentation/process/security-bugs.rst +SECURITY PROTOCOL AND DATA MODEL (SPDM) +M: Jonathan Cameron +M: Lukas Wunner +L: linux-coco@lists.linux.dev +L: linux-cxl@vger.kernel.org +L: linux-pci@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/devsec/spdm.git +F: Documentation/ABI/testing/sysfs-devices-spdm +F: Documentation/admin-guide/sysctl/spdm.rst +F: drivers/pci/cma* +F: include/linux/spdm.h +F: lib/spdm/ + SECURITY SUBSYSTEM M: Paul Moore M: James Morris diff --git a/certs/blacklist.c b/certs/blacklist.c index 675dd7a8f07abc..34185415d45197 100644 --- a/certs/blacklist.c +++ b/certs/blacklist.c @@ -311,7 +311,7 @@ static int restrict_link_for_blacklist(struct key *dest_keyring, * Initialise the blacklist * * The blacklist_init() function is registered as an initcall via - * device_initcall(). As a result if the blacklist_init() function fails for + * arch_initcall(). As a result if the blacklist_init() function fails for * any reason the kernel continues to execute. While cleanly returning -ENODEV * could be acceptable for some non-critical kernel parts, if the blacklist * keyring fails to load it defeats the certificate/key based deny list for @@ -356,7 +356,7 @@ static int __init blacklist_init(void) /* * Must be initialised before we try and load the keys into the keyring. */ -device_initcall(blacklist_init); +arch_initcall(blacklist_init); #ifdef CONFIG_SYSTEM_REVOCATION_LIST /* diff --git a/crypto/Kconfig b/crypto/Kconfig index a779cab668c24c..6b0bfbccac08b8 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -250,6 +250,7 @@ config CRYPTO_RSA tristate "RSA (Rivest-Shamir-Adleman)" select CRYPTO_AKCIPHER select CRYPTO_MANAGER + select CRYPTO_SIG select MPILIB select ASN1 help @@ -290,19 +291,19 @@ config CRYPTO_ECDH config CRYPTO_ECDSA tristate "ECDSA (Elliptic Curve Digital Signature Algorithm)" select CRYPTO_ECC - select CRYPTO_AKCIPHER + select CRYPTO_SIG select ASN1 help ECDSA (Elliptic Curve Digital Signature Algorithm) (FIPS 186, ISO/IEC 14888-3) - using curves P-192, P-256, and P-384 + using curves P-192, P-256, P-384 and P-521 Only signature verification is implemented. config CRYPTO_ECRDSA tristate "EC-RDSA (Elliptic Curve Russian Digital Signature Algorithm)" select CRYPTO_ECC - select CRYPTO_AKCIPHER + select CRYPTO_SIG select CRYPTO_STREEBOG select OID_REGISTRY select ASN1 diff --git a/crypto/Makefile b/crypto/Makefile index 4c99e5d376f687..81be78d39c2d72 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -48,11 +48,14 @@ rsa_generic-y += rsaprivkey.asn1.o rsa_generic-y += rsa.o rsa_generic-y += rsa_helper.o rsa_generic-y += rsa-pkcs1pad.o +rsa_generic-y += rsassa-pkcs1.o obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h -$(obj)/ecdsa.o: $(obj)/ecdsasignature.asn1.h +$(obj)/ecdsa-x962.o: $(obj)/ecdsasignature.asn1.h ecdsa_generic-y += ecdsa.o +ecdsa_generic-y += ecdsa-x962.o +ecdsa_generic-y += ecdsa-p1363.o ecdsa_generic-y += ecdsasignature.asn1.o obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o diff --git a/crypto/akcipher.c b/crypto/akcipher.c index e0ff5f4dda6d62..72c82d9aa07789 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -20,6 +20,19 @@ #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e +struct crypto_akcipher_sync_data { + struct crypto_akcipher *tfm; + const void *src; + void *dst; + unsigned int slen; + unsigned int dlen; + + struct akcipher_request *req; + struct crypto_wait cwait; + struct scatterlist sg; + u8 *buf; +}; + static int __maybe_unused crypto_akcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { @@ -126,10 +139,6 @@ int crypto_register_akcipher(struct akcipher_alg *alg) { struct crypto_alg *base = &alg->base; - if (!alg->sign) - alg->sign = akcipher_default_op; - if (!alg->verify) - alg->verify = akcipher_default_op; if (!alg->encrypt) alg->encrypt = akcipher_default_op; if (!alg->decrypt) @@ -158,7 +167,7 @@ int akcipher_register_instance(struct crypto_template *tmpl, } EXPORT_SYMBOL_GPL(akcipher_register_instance); -int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) +static int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) { unsigned int reqsize = crypto_akcipher_reqsize(data->tfm); struct akcipher_request *req; @@ -167,10 +176,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) unsigned int len; u8 *buf; - if (data->dst) - mlen = max(data->slen, data->dlen); - else - mlen = data->slen + data->dlen; + mlen = max(data->slen, data->dlen); len = sizeof(*req) + reqsize + mlen; if (len < mlen) @@ -189,8 +195,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) sg = &data->sg; sg_init_one(sg, buf, mlen); - akcipher_request_set_crypt(req, sg, data->dst ? sg : NULL, - data->slen, data->dlen); + akcipher_request_set_crypt(req, sg, sg, data->slen, data->dlen); crypto_init_wait(&data->cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, @@ -198,18 +203,16 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) return 0; } -EXPORT_SYMBOL_GPL(crypto_akcipher_sync_prep); -int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err) +static int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, + int err) { err = crypto_wait_req(err, &data->cwait); - if (data->dst) - memcpy(data->dst, data->buf, data->dlen); + memcpy(data->dst, data->buf, data->dlen); data->dlen = data->req->dst_len; kfree_sensitive(data->req); return err; } -EXPORT_SYMBOL_GPL(crypto_akcipher_sync_post); int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm, const void *src, unsigned int slen, @@ -248,34 +251,5 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, } EXPORT_SYMBOL_GPL(crypto_akcipher_sync_decrypt); -static void crypto_exit_akcipher_ops_sig(struct crypto_tfm *tfm) -{ - struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); - - crypto_free_akcipher(*ctx); -} - -int crypto_init_akcipher_ops_sig(struct crypto_tfm *tfm) -{ - struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); - struct crypto_alg *calg = tfm->__crt_alg; - struct crypto_akcipher *akcipher; - - if (!crypto_mod_get(calg)) - return -EAGAIN; - - akcipher = crypto_create_tfm(calg, &crypto_akcipher_type); - if (IS_ERR(akcipher)) { - crypto_mod_put(calg); - return PTR_ERR(akcipher); - } - - *ctx = akcipher; - tfm->exit = crypto_exit_akcipher_ops_sig; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_init_akcipher_ops_sig); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 422940a6706a7f..c98c1588802b4f 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -83,13 +83,19 @@ software_key_determine_akcipher(const struct public_key *pkey, if (strcmp(encoding, "pkcs1") == 0) { *sig = op == kernel_pkey_sign || 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, "pkcs1pad(%s)", pkey->pkey_algo); } else { + if (!hash_algo) + return -EINVAL; n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s,%s)", + "pkcs1(%s,%s)", pkey->pkey_algo, hash_algo); } return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; @@ -104,7 +110,8 @@ software_key_determine_akcipher(const struct public_key *pkey, return -EINVAL; *sig = false; } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { - if (strcmp(encoding, "x962") != 0) + if (strcmp(encoding, "x962") != 0 && + strcmp(encoding, "p1363") != 0) return -EINVAL; /* * ECDSA signatures are taken over a raw hash, so they don't @@ -124,6 +131,9 @@ software_key_determine_akcipher(const struct public_key *pkey, strcmp(hash_algo, "sha3-384") != 0 && strcmp(hash_algo, "sha3-512") != 0) return -EINVAL; + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", + encoding, pkey->pkey_algo); + return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) { if (strcmp(encoding, "raw") != 0) return -EINVAL; @@ -192,7 +202,9 @@ static int software_key_query(const struct kernel_pkey_params *params, if (ret < 0) goto error_free_tfm; - len = crypto_sig_maxsize(sig); + len = crypto_sig_keysize(sig); + info->max_sig_size = crypto_sig_maxsize(sig); + info->max_data_size = crypto_sig_digestsize(sig); info->supported_ops = KEYCTL_SUPPORTS_VERIFY; if (pkey->key_is_private) @@ -218,6 +230,8 @@ static int software_key_query(const struct kernel_pkey_params *params, goto error_free_tfm; len = crypto_akcipher_maxsize(tfm); + info->max_sig_size = len; + info->max_data_size = len; info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT; if (pkey->key_is_private) @@ -225,40 +239,6 @@ static int software_key_query(const struct kernel_pkey_params *params, } info->key_size = len * 8; - - if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { - int slen = len; - /* - * ECDSA key sizes are much smaller than RSA, and thus could - * operate on (hashed) inputs that are larger than key size. - * For example SHA384-hashed input used with secp256r1 - * based keys. Set max_data_size to be at least as large as - * the largest supported hash size (SHA512) - */ - info->max_data_size = 64; - - /* - * Verify takes ECDSA-Sig (described in RFC 5480) as input, - * which is actually 2 'key_size'-bit integers encoded in - * ASN.1. Account for the ASN.1 encoding overhead here. - * - * NIST P192/256/384 may prepend a '0' to a coordinate to - * indicate a positive integer. NIST P521 never needs it. - */ - if (strcmp(pkey->pkey_algo, "ecdsa-nist-p521") != 0) - slen += 1; - /* Length of encoding the x & y coordinates */ - slen = 2 * (slen + 2); - /* - * If coordinate encoding takes at least 128 bytes then an - * additional byte for length encoding is needed. - */ - info->max_sig_size = 1 + (slen >= 128) + 1 + slen; - } else { - info->max_data_size = len; - info->max_sig_size = len; - } - info->max_enc_size = len; info->max_dec_size = len; @@ -323,7 +303,7 @@ static int software_key_eds_op(struct kernel_pkey_params *params, if (ret) goto error_free_tfm; - ksz = crypto_sig_maxsize(sig); + ksz = crypto_sig_keysize(sig); } else { tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) { diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index ee2fdab42334f1..ff1db59d403772 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -572,6 +572,15 @@ int x509_process_extension(void *context, size_t hdrlen, return 0; } + if (ctx->last_oid == OID_subjectAltName) { + if (ctx->cert->raw_san) + return -EBADMSG; + + ctx->cert->raw_san = v; + ctx->cert->raw_san_size = vlen; + return 0; + } + if (ctx->last_oid == OID_keyUsage) { /* * Get hold of the keyUsage bit string diff --git a/crypto/asymmetric_keys/x509_loader.c b/crypto/asymmetric_keys/x509_loader.c index a417413269989f..25ff027fad1d39 100644 --- a/crypto/asymmetric_keys/x509_loader.c +++ b/crypto/asymmetric_keys/x509_loader.c @@ -4,28 +4,42 @@ #include #include +ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen) +{ + ssize_t plen; + + /* Each cert begins with an ASN.1 SEQUENCE tag and must be more + * than 256 bytes in size. + */ + if (buflen < 4) + return -EINVAL; + + if (p[0] != 0x30 && + p[1] != 0x82) + return -EINVAL; + + plen = (p[2] << 8) | p[3]; + plen += 4; + if (plen > buflen) + return -EINVAL; + + return plen; +} +EXPORT_SYMBOL_GPL(x509_get_certificate_length); + int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size, const struct key *keyring) { key_ref_t key; const u8 *p, *end; - size_t plen; + ssize_t plen; p = cert_list; end = p + list_size; while (p < end) { - /* Each cert begins with an ASN.1 SEQUENCE tag and must be more - * than 256 bytes in size. - */ - if (end - p < 4) - goto dodgy_cert; - if (p[0] != 0x30 && - p[1] != 0x82) - goto dodgy_cert; - plen = (p[2] << 8) | p[3]; - plen += 4; - if (plen > end - p) + plen = x509_get_certificate_length(p, end - p); + if (plen < 0) goto dodgy_cert; key = key_create_or_update(make_key_ref(keyring, 1), diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 0688c222806b01..39f1521b773dd2 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h @@ -5,49 +5,11 @@ * Written by David Howells (dhowells@redhat.com) */ -#include -#include -#include -#include - -struct x509_certificate { - struct x509_certificate *next; - struct x509_certificate *signer; /* Certificate that signed this one */ - struct public_key *pub; /* Public key details */ - struct public_key_signature *sig; /* Signature parameters */ - char *issuer; /* Name of certificate issuer */ - char *subject; /* Name of certificate subject */ - struct asymmetric_key_id *id; /* Issuer + Serial number */ - struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ - time64_t valid_from; - 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; - const void *raw_issuer; /* Raw issuer name in ASN.1 */ - const void *raw_subject; /* Raw subject name in ASN.1 */ - unsigned raw_subject_size; - unsigned raw_skid_size; - const void *raw_skid; /* Raw subjectKeyId in ASN.1 */ - unsigned index; - bool seen; /* Infinite recursion prevention */ - bool verified; - bool self_signed; /* T if self-signed (check unsupported_sig too) */ - bool unsupported_sig; /* T if signature uses unsupported crypto */ - bool blacklisted; -}; +#include /* * x509_cert_parser.c */ -extern void x509_free_certificate(struct x509_certificate *cert); -DEFINE_FREE(x509_free_certificate, struct x509_certificate *, - if (!IS_ERR(_T)) x509_free_certificate(_T)) -extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); extern int x509_decode_time(time64_t *_t, size_t hdrlen, unsigned char tag, const unsigned char *value, size_t vlen); diff --git a/crypto/ecdsa-p1363.c b/crypto/ecdsa-p1363.c new file mode 100644 index 00000000000000..eaae7214d69bca --- /dev/null +++ b/crypto/ecdsa-p1363.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ECDSA P1363 signature encoding + * + * Copyright (c) 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include + +struct ecdsa_p1363_ctx { + struct crypto_sig *child; +}; + +static int ecdsa_p1363_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int keylen = crypto_sig_keysize(ctx->child); + unsigned int ndigits = DIV_ROUND_UP(keylen, sizeof(u64)); + struct ecdsa_raw_sig sig; + + if (slen != 2 * keylen) + return -EINVAL; + + ecc_digits_from_bytes(src, keylen, sig.r, ndigits); + ecc_digits_from_bytes(src + keylen, keylen, sig.s, ndigits); + + return crypto_sig_verify(ctx->child, &sig, sizeof(sig), digest, dlen); +} + +static unsigned int ecdsa_p1363_key_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_p1363_max_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return 2 * crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_p1363_digest_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_digestsize(ctx->child); +} + +static int ecdsa_p1363_set_pub_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_set_pubkey(ctx->child, key, keylen); +} + +static int ecdsa_p1363_init_tfm(struct crypto_sig *tfm) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + struct crypto_sig *child_tfm; + + child_tfm = crypto_spawn_sig(spawn); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void ecdsa_p1363_exit_tfm(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + crypto_free_sig(ctx->child); +} + +static void ecdsa_p1363_free(struct sig_instance *inst) +{ + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + + crypto_drop_sig(spawn); + kfree(inst); +} + +static int ecdsa_p1363_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct crypto_sig_spawn *spawn; + struct sig_instance *inst; + struct sig_alg *ecdsa_alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + spawn = sig_instance_ctx(inst); + + err = crypto_grab_sig(spawn, sig_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + + ecdsa_alg = crypto_spawn_sig_alg(spawn); + + err = -EINVAL; + if (strncmp(ecdsa_alg->base.cra_name, "ecdsa", 5) != 0) + goto err_free_inst; + + err = crypto_inst_setname(sig_crypto_instance(inst), tmpl->name, + &ecdsa_alg->base); + if (err) + goto err_free_inst; + + inst->alg.base.cra_priority = ecdsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct ecdsa_p1363_ctx); + + inst->alg.init = ecdsa_p1363_init_tfm; + inst->alg.exit = ecdsa_p1363_exit_tfm; + + inst->alg.verify = ecdsa_p1363_verify; + inst->alg.key_size = ecdsa_p1363_key_size; + inst->alg.max_size = ecdsa_p1363_max_size; + inst->alg.digest_size = ecdsa_p1363_digest_size; + inst->alg.set_pub_key = ecdsa_p1363_set_pub_key; + + inst->free = ecdsa_p1363_free; + + err = sig_register_instance(tmpl, inst); + if (err) { +err_free_inst: + ecdsa_p1363_free(inst); + } + return err; +} + +struct crypto_template ecdsa_p1363_tmpl = { + .name = "p1363", + .create = ecdsa_p1363_create, + .module = THIS_MODULE, +}; + +MODULE_ALIAS_CRYPTO("p1363"); diff --git a/crypto/ecdsa-x962.c b/crypto/ecdsa-x962.c new file mode 100644 index 00000000000000..6a77c13e192b1a --- /dev/null +++ b/crypto/ecdsa-x962.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ECDSA X9.62 signature encoding + * + * Copyright (c) 2021 IBM Corporation + * Copyright (c) 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ecdsasignature.asn1.h" + +struct ecdsa_x962_ctx { + struct crypto_sig *child; +}; + +struct ecdsa_x962_signature_ctx { + struct ecdsa_raw_sig sig; + unsigned int ndigits; +}; + +/* Get the r and s components of a signature from the X.509 certificate. */ +static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen, + unsigned int ndigits) +{ + size_t bufsize = ndigits * sizeof(u64); + const char *d = value; + + if (!value || !vlen || vlen > bufsize + 1) + return -EINVAL; + + /* + * vlen may be 1 byte larger than bufsize due to a leading zero byte + * (necessary if the most significant bit of the integer is set). + */ + if (vlen > bufsize) { + /* skip over leading zeros that make 'value' a positive int */ + if (*d == 0) { + vlen -= 1; + d++; + } else { + return -EINVAL; + } + } + + ecc_digits_from_bytes(d, vlen, dest, ndigits); + + return 0; +} + +int ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_x962_signature_ctx *sig_ctx = context; + + return ecdsa_get_signature_rs(sig_ctx->sig.r, hdrlen, tag, value, vlen, + sig_ctx->ndigits); +} + +int ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_x962_signature_ctx *sig_ctx = context; + + return ecdsa_get_signature_rs(sig_ctx->sig.s, hdrlen, tag, value, vlen, + sig_ctx->ndigits); +} + +static int ecdsa_x962_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct ecdsa_x962_signature_ctx sig_ctx; + int err; + + sig_ctx.ndigits = DIV_ROUND_UP(crypto_sig_keysize(ctx->child), + sizeof(u64)); + + err = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, src, slen); + if (err < 0) + return err; + + return crypto_sig_verify(ctx->child, &sig_ctx.sig, sizeof(sig_ctx.sig), + digest, dlen); +} + +static unsigned int ecdsa_x962_key_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_x962_max_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct sig_alg *alg = crypto_sig_alg(ctx->child); + int slen = crypto_sig_keysize(ctx->child); + + /* + * Verify takes ECDSA-Sig-Value (described in RFC 5480) as input, + * which is actually 2 'key_size'-bit integers encoded in ASN.1. + * Account for the ASN.1 encoding overhead here. + * + * NIST P192/256/384 may prepend a '0' to a coordinate to indicate + * a positive integer. NIST P521 never needs it. + */ + if (strcmp(alg->base.cra_name, "ecdsa-nist-p521") != 0) + slen += 1; + + /* Length of encoding the x & y coordinates */ + slen = 2 * (slen + 2); + + /* + * If coordinate encoding takes at least 128 bytes then an + * additional byte for length encoding is needed. + */ + return 1 + (slen >= 128) + 1 + slen; +} + +static unsigned int ecdsa_x962_digest_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_digestsize(ctx->child); +} + +static int ecdsa_x962_set_pub_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_set_pubkey(ctx->child, key, keylen); +} + +static int ecdsa_x962_init_tfm(struct crypto_sig *tfm) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct crypto_sig *child_tfm; + + child_tfm = crypto_spawn_sig(spawn); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void ecdsa_x962_exit_tfm(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + crypto_free_sig(ctx->child); +} + +static void ecdsa_x962_free(struct sig_instance *inst) +{ + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + + crypto_drop_sig(spawn); + kfree(inst); +} + +static int ecdsa_x962_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct crypto_sig_spawn *spawn; + struct sig_instance *inst; + struct sig_alg *ecdsa_alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + spawn = sig_instance_ctx(inst); + + err = crypto_grab_sig(spawn, sig_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + + ecdsa_alg = crypto_spawn_sig_alg(spawn); + + err = -EINVAL; + if (strncmp(ecdsa_alg->base.cra_name, "ecdsa", 5) != 0) + goto err_free_inst; + + err = crypto_inst_setname(sig_crypto_instance(inst), tmpl->name, + &ecdsa_alg->base); + if (err) + goto err_free_inst; + + inst->alg.base.cra_priority = ecdsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct ecdsa_x962_ctx); + + inst->alg.init = ecdsa_x962_init_tfm; + inst->alg.exit = ecdsa_x962_exit_tfm; + + inst->alg.verify = ecdsa_x962_verify; + inst->alg.key_size = ecdsa_x962_key_size; + inst->alg.max_size = ecdsa_x962_max_size; + inst->alg.digest_size = ecdsa_x962_digest_size; + inst->alg.set_pub_key = ecdsa_x962_set_pub_key; + + inst->free = ecdsa_x962_free; + + err = sig_register_instance(tmpl, inst); + if (err) { +err_free_inst: + ecdsa_x962_free(inst); + } + return err; +} + +struct crypto_template ecdsa_x962_tmpl = { + .name = "x962", + .create = ecdsa_x962_create, + .module = THIS_MODULE, +}; + +MODULE_ALIAS_CRYPTO("x962"); diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c index d5a10959ec281c..117526d15ddebf 100644 --- a/crypto/ecdsa.c +++ b/crypto/ecdsa.c @@ -4,14 +4,11 @@ */ #include -#include #include -#include +#include #include -#include -#include - -#include "ecdsasignature.asn1.h" +#include +#include struct ecc_ctx { unsigned int curve_id; @@ -23,66 +20,6 @@ struct ecc_ctx { struct ecc_point pub_key; }; -struct ecdsa_signature_ctx { - const struct ecc_curve *curve; - u64 r[ECC_MAX_DIGITS]; - u64 s[ECC_MAX_DIGITS]; -}; - -/* - * Get the r and s components of a signature from the X509 certificate. - */ -static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen, unsigned int ndigits) -{ - size_t bufsize = ndigits * sizeof(u64); - ssize_t diff = vlen - bufsize; - const char *d = value; - - if (!value || !vlen) - return -EINVAL; - - /* diff = 0: 'value' has exacly the right size - * diff > 0: 'value' has too many bytes; one leading zero is allowed that - * makes the value a positive integer; error on more - * diff < 0: 'value' is missing leading zeros - */ - if (diff > 0) { - /* skip over leading zeros that make 'value' a positive int */ - if (*d == 0) { - vlen -= 1; - diff--; - d++; - } - if (diff) - return -EINVAL; - } - if (-diff >= bufsize) - return -EINVAL; - - ecc_digits_from_bytes(d, vlen, dest, ndigits); - - return 0; -} - -int ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen) -{ - struct ecdsa_signature_ctx *sig = context; - - return ecdsa_get_signature_rs(sig->r, hdrlen, tag, value, vlen, - sig->curve->g.ndigits); -} - -int ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen) -{ - struct ecdsa_signature_ctx *sig = context; - - return ecdsa_get_signature_rs(sig->s, hdrlen, tag, value, vlen, - sig->curve->g.ndigits); -} - static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, const u64 *s) { const struct ecc_curve *curve = ctx->curve; @@ -126,46 +63,27 @@ static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, con /* * Verify an ECDSA signature. */ -static int ecdsa_verify(struct akcipher_request *req) +static int ecdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) { - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); size_t bufsize = ctx->curve->g.ndigits * sizeof(u64); - struct ecdsa_signature_ctx sig_ctx = { - .curve = ctx->curve, - }; + const struct ecdsa_raw_sig *sig = src; u64 hash[ECC_MAX_DIGITS]; - unsigned char *buffer; - int ret; if (unlikely(!ctx->pub_key_set)) return -EINVAL; - buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - sg_pcopy_to_buffer(req->src, - sg_nents_for_len(req->src, req->src_len + req->dst_len), - buffer, req->src_len + req->dst_len, 0); - - ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, - buffer, req->src_len); - if (ret < 0) - goto error; - - if (bufsize > req->dst_len) - bufsize = req->dst_len; - - ecc_digits_from_bytes(buffer + req->src_len, bufsize, - hash, ctx->curve->g.ndigits); + if (slen != sizeof(*sig)) + return -EINVAL; - ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); + if (bufsize > dlen) + bufsize = dlen; -error: - kfree(buffer); + ecc_digits_from_bytes(digest, bufsize, hash, ctx->curve->g.ndigits); - return ret; + return _ecdsa_verify(ctx, hash, sig->r, sig->s); } static int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id) @@ -201,9 +119,10 @@ static int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx) * Set the public ECC key as defined by RFC5480 section 2.2 "Subject Public * Key". Only the uncompressed format is supported. */ -static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +static int ecdsa_set_pub_key(struct crypto_sig *tfm, const void *key, + unsigned int keylen) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); unsigned int digitlen, ndigits; const unsigned char *d = key; int ret; @@ -237,31 +156,43 @@ static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsig return ret; } -static void ecdsa_exit_tfm(struct crypto_akcipher *tfm) +static void ecdsa_exit_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); ecdsa_ecc_ctx_deinit(ctx); } -static unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) +static unsigned int ecdsa_key_size(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return DIV_ROUND_UP(ctx->curve->nbits, 8); } -static int ecdsa_nist_p521_init_tfm(struct crypto_akcipher *tfm) +static unsigned int ecdsa_digest_size(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + /* + * ECDSA key sizes are much smaller than RSA, and thus could + * operate on (hashed) inputs that are larger than the key size. + * E.g. SHA384-hashed input used with secp256r1 based keys. + * Return the largest supported hash size (SHA512). + */ + return SHA512_DIGEST_SIZE; +} + +static int ecdsa_nist_p521_init_tfm(struct crypto_sig *tfm) +{ + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P521); } -static struct akcipher_alg ecdsa_nist_p521 = { +static struct sig_alg ecdsa_nist_p521 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p521_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -273,17 +204,18 @@ static struct akcipher_alg ecdsa_nist_p521 = { }, }; -static int ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p384_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); } -static struct akcipher_alg ecdsa_nist_p384 = { +static struct sig_alg ecdsa_nist_p384 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p384_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -295,17 +227,18 @@ static struct akcipher_alg ecdsa_nist_p384 = { }, }; -static int ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p256_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); } -static struct akcipher_alg ecdsa_nist_p256 = { +static struct sig_alg ecdsa_nist_p256 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p256_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -317,17 +250,18 @@ static struct akcipher_alg ecdsa_nist_p256 = { }, }; -static int ecdsa_nist_p192_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p192_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P192); } -static struct akcipher_alg ecdsa_nist_p192 = { +static struct sig_alg ecdsa_nist_p192 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p192_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -345,42 +279,59 @@ static int __init ecdsa_init(void) int ret; /* NIST p192 may not be available in FIPS mode */ - ret = crypto_register_akcipher(&ecdsa_nist_p192); + ret = crypto_register_sig(&ecdsa_nist_p192); ecdsa_nist_p192_registered = ret == 0; - ret = crypto_register_akcipher(&ecdsa_nist_p256); + ret = crypto_register_sig(&ecdsa_nist_p256); if (ret) goto nist_p256_error; - ret = crypto_register_akcipher(&ecdsa_nist_p384); + ret = crypto_register_sig(&ecdsa_nist_p384); if (ret) goto nist_p384_error; - ret = crypto_register_akcipher(&ecdsa_nist_p521); + ret = crypto_register_sig(&ecdsa_nist_p521); if (ret) goto nist_p521_error; + ret = crypto_register_template(&ecdsa_x962_tmpl); + if (ret) + goto x962_tmpl_error; + + ret = crypto_register_template(&ecdsa_p1363_tmpl); + if (ret) + goto p1363_tmpl_error; + return 0; +p1363_tmpl_error: + crypto_unregister_template(&ecdsa_x962_tmpl); + +x962_tmpl_error: + crypto_unregister_sig(&ecdsa_nist_p521); + nist_p521_error: - crypto_unregister_akcipher(&ecdsa_nist_p384); + crypto_unregister_sig(&ecdsa_nist_p384); nist_p384_error: - crypto_unregister_akcipher(&ecdsa_nist_p256); + crypto_unregister_sig(&ecdsa_nist_p256); nist_p256_error: if (ecdsa_nist_p192_registered) - crypto_unregister_akcipher(&ecdsa_nist_p192); + crypto_unregister_sig(&ecdsa_nist_p192); return ret; } static void __exit ecdsa_exit(void) { + crypto_unregister_template(&ecdsa_x962_tmpl); + crypto_unregister_template(&ecdsa_p1363_tmpl); + if (ecdsa_nist_p192_registered) - crypto_unregister_akcipher(&ecdsa_nist_p192); - crypto_unregister_akcipher(&ecdsa_nist_p256); - crypto_unregister_akcipher(&ecdsa_nist_p384); - crypto_unregister_akcipher(&ecdsa_nist_p521); + crypto_unregister_sig(&ecdsa_nist_p192); + crypto_unregister_sig(&ecdsa_nist_p256); + crypto_unregister_sig(&ecdsa_nist_p384); + crypto_unregister_sig(&ecdsa_nist_p521); } subsys_initcall(ecdsa_init); diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c index 3811f3805b5d88..b3dd8a3ddeb796 100644 --- a/crypto/ecrdsa.c +++ b/crypto/ecrdsa.c @@ -18,12 +18,11 @@ #include #include +#include #include -#include #include -#include +#include #include -#include #include "ecrdsa_params.asn1.h" #include "ecrdsa_pub_key.asn1.h" #include "ecrdsa_defs.h" @@ -68,13 +67,12 @@ static const struct ecc_curve *get_curve_by_oid(enum OID oid) } } -static int ecrdsa_verify(struct akcipher_request *req) +static int ecrdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) { - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); - unsigned char sig[ECRDSA_MAX_SIG_SIZE]; - unsigned char digest[STREEBOG512_DIGEST_SIZE]; - unsigned int ndigits = req->dst_len / sizeof(u64); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int ndigits = dlen / sizeof(u64); u64 r[ECRDSA_MAX_DIGITS]; /* witness (r) */ u64 _r[ECRDSA_MAX_DIGITS]; /* -r */ u64 s[ECRDSA_MAX_DIGITS]; /* second part of sig (s) */ @@ -91,25 +89,19 @@ static int ecrdsa_verify(struct akcipher_request *req) */ if (!ctx->curve || !ctx->digest || - !req->src || + !src || + !digest || !ctx->pub_key.x || - req->dst_len != ctx->digest_len || - req->dst_len != ctx->curve->g.ndigits * sizeof(u64) || + dlen != ctx->digest_len || + dlen != ctx->curve->g.ndigits * sizeof(u64) || ctx->pub_key.ndigits != ctx->curve->g.ndigits || - req->dst_len * 2 != req->src_len || - WARN_ON(req->src_len > sizeof(sig)) || - WARN_ON(req->dst_len > sizeof(digest))) + dlen * 2 != slen || + WARN_ON(slen > ECRDSA_MAX_SIG_SIZE) || + WARN_ON(dlen > STREEBOG512_DIGEST_SIZE)) return -EBADMSG; - sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len), - sig, req->src_len); - sg_pcopy_to_buffer(req->src, - sg_nents_for_len(req->src, - req->src_len + req->dst_len), - digest, req->dst_len, req->src_len); - - vli_from_be64(s, sig, ndigits); - vli_from_be64(r, sig + ndigits * sizeof(u64), ndigits); + vli_from_be64(s, src, ndigits); + vli_from_be64(r, src + ndigits * sizeof(u64), ndigits); /* Step 1: verify that 0 < r < q, 0 < s < q */ if (vli_is_zero(r, ndigits) || @@ -188,10 +180,10 @@ static u8 *ecrdsa_unpack_u32(u32 *dst, void *src) } /* Parse BER encoded subjectPublicKey. */ -static int ecrdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, +static int ecrdsa_set_pub_key(struct crypto_sig *tfm, const void *key, unsigned int keylen) { - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); unsigned int ndigits; u32 algo, paramlen; u8 *params; @@ -249,9 +241,9 @@ static int ecrdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, return 0; } -static unsigned int ecrdsa_max_size(struct crypto_akcipher *tfm) +static unsigned int ecrdsa_key_size(struct crypto_sig *tfm) { - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); /* * Verify doesn't need any output, so it's just informational @@ -260,13 +252,21 @@ static unsigned int ecrdsa_max_size(struct crypto_akcipher *tfm) return ctx->pub_key.ndigits * sizeof(u64); } -static void ecrdsa_exit_tfm(struct crypto_akcipher *tfm) +static unsigned int ecrdsa_max_size(struct crypto_sig *tfm) +{ + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); + + return 2 * ctx->pub_key.ndigits * sizeof(u64); +} + +static void ecrdsa_exit_tfm(struct crypto_sig *tfm) { } -static struct akcipher_alg ecrdsa_alg = { +static struct sig_alg ecrdsa_alg = { .verify = ecrdsa_verify, .set_pub_key = ecrdsa_set_pub_key, + .key_size = ecrdsa_key_size, .max_size = ecrdsa_max_size, .exit = ecrdsa_exit_tfm, .base = { @@ -280,12 +280,12 @@ static struct akcipher_alg ecrdsa_alg = { static int __init ecrdsa_mod_init(void) { - return crypto_register_akcipher(&ecrdsa_alg); + return crypto_register_sig(&ecrdsa_alg); } static void __exit ecrdsa_mod_fini(void) { - crypto_unregister_akcipher(&ecrdsa_alg); + crypto_unregister_sig(&ecrdsa_alg); } module_init(ecrdsa_mod_init); diff --git a/crypto/internal.h b/crypto/internal.h index 711a6a5bfa2b56..46b661be0f90fe 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -22,8 +22,6 @@ #include #include -struct akcipher_request; -struct crypto_akcipher; struct crypto_instance; struct crypto_template; @@ -35,19 +33,6 @@ struct crypto_larval { bool test_started; }; -struct crypto_akcipher_sync_data { - struct crypto_akcipher *tfm; - const void *src; - void *dst; - unsigned int slen; - unsigned int dlen; - - struct akcipher_request *req; - struct crypto_wait cwait; - struct scatterlist sg; - u8 *buf; -}; - enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, @@ -129,10 +114,6 @@ void *crypto_create_tfm_node(struct crypto_alg *alg, void *crypto_clone_tfm(const struct crypto_type *frontend, struct crypto_tfm *otfm); -int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data); -int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err); -int crypto_init_akcipher_ops_sig(struct crypto_tfm *tfm); - static inline void *crypto_create_tfm(struct crypto_alg *alg, const struct crypto_type *frontend) { diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index cd501195f34a1a..50bdb18e7b4837 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -16,101 +16,6 @@ #include #include -/* - * 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 crypto_akcipher *child; unsigned int key_size; @@ -118,7 +23,6 @@ struct pkcs1pad_ctx { struct pkcs1pad_inst_ctx { struct crypto_akcipher_spawn spawn; - const struct rsa_asn1_template *digest_info; }; struct pkcs1pad_request { @@ -131,42 +35,16 @@ static int pkcs1pad_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - int err; - - ctx->key_size = 0; - - err = crypto_akcipher_set_pub_key(ctx->child, key, keylen); - if (err) - return err; - - /* Find out new modulus size from rsa implementation */ - err = crypto_akcipher_maxsize(ctx->child); - if (err > PAGE_SIZE) - return -ENOTSUPP; - ctx->key_size = err; - return 0; + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen); } static int pkcs1pad_set_priv_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - int err; - - ctx->key_size = 0; - - err = crypto_akcipher_set_priv_key(ctx->child, key, keylen); - if (err) - return err; - /* Find out new modulus size from rsa implementation */ - err = crypto_akcipher_maxsize(ctx->child); - if (err > PAGE_SIZE) - return -ENOTSUPP; - - ctx->key_size = err; - return 0; + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen); } static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm) @@ -174,9 +52,9 @@ static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *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 - * decrypt/verify. + * decrypt. */ return ctx->key_size; @@ -194,7 +72,7 @@ static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len, 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 pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); @@ -233,14 +111,14 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int 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; if (err == -EINPROGRESS) goto out; - err = pkcs1pad_encrypt_sign_complete(req, err); + err = pkcs1pad_encrypt_complete(req, err); out: akcipher_request_complete(req, err); @@ -281,7 +159,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req) 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); + pkcs1pad_encrypt_complete_cb, req); /* Reuse output buffer */ akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg, @@ -289,7 +167,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req) err = crypto_akcipher_encrypt(&req_ctx->child_req); if (err != -EINPROGRESS && err != -EBUSY) - return pkcs1pad_encrypt_sign_complete(req, err); + return pkcs1pad_encrypt_complete(req, err); return err; } @@ -394,195 +272,6 @@ static int pkcs1pad_decrypt(struct akcipher_request *req) 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) { struct akcipher_instance *inst = akcipher_alg_instance(tfm); @@ -624,7 +313,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) struct akcipher_instance *inst; struct pkcs1pad_inst_ctx *ctx; struct akcipher_alg *rsa_alg; - const char *hash_name; int err; err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask); @@ -650,36 +338,15 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) } err = -ENAMETOOLONG; - hash_name = crypto_attr_alg_name(tb[2]); - if (IS_ERR(hash_name)) { - if (snprintf(inst->alg.base.cra_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - - if (snprintf(inst->alg.base.cra_driver_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_driver_name) >= - CRYPTO_MAX_ALG_NAME) - 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; - } + if (snprintf(inst->alg.base.cra_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + if (snprintf(inst->alg.base.cra_driver_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_driver_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 pkcs1pad_ctx); @@ -689,8 +356,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.encrypt = pkcs1pad_encrypt; 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_priv_key = pkcs1pad_set_priv_key; inst->alg.max_size = pkcs1pad_get_max_size; diff --git a/crypto/rsa.c b/crypto/rsa.c index 78b28d14ced397..b7d21529c55229 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -407,16 +407,25 @@ static int __init rsa_init(void) return err; err = crypto_register_template(&rsa_pkcs1pad_tmpl); - if (err) { - crypto_unregister_akcipher(&rsa); - return err; - } + if (err) + goto err_unregister_rsa; + + err = crypto_register_template(&rsassa_pkcs1_tmpl); + if (err) + goto err_unregister_rsa_pkcs1pad; 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) { + crypto_unregister_template(&rsassa_pkcs1_tmpl); crypto_unregister_template(&rsa_pkcs1pad_tmpl); crypto_unregister_akcipher(&rsa); } diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c new file mode 100644 index 00000000000000..9c28f1c628264a --- /dev/null +++ b/crypto/rsassa-pkcs1.c @@ -0,0 +1,442 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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, /* , */ + 0x05, 0x00, 0x04, 0x10 /* NULL), OCTET STRING ) */ +}; + +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; +} + +static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p) +{ + /* + * The final byte of the Full Hash Prefix encodes the hash length. + * + * This needs to be revisited should hash algorithms with more than + * 1016 bits (127 bytes * 8) ever be added. The length would then + * be encoded into more than one byte by ASN.1. + */ + static_assert(HASH_MAX_DIGESTSIZE <= 127); + + return p->data[p->size - 1]; +} + +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[3], 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 != rsassa_pkcs1_hash_len(hash_prefix)) + return -EINVAL; + + if (slen + hash_prefix->size > ctx->key_size - 11) + return -EOVERFLOW; + + pad_len = ctx->key_size - slen - hash_prefix->size - 1; + + child_req = kmalloc(sizeof(*child_req) + child_reqsize + pad_len, + 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 = pad_len - 1; + in_buf[0] = 0x01; + memset(in_buf + 1, 0xff, ps_end - 1); + in_buf[ps_end] = 0x00; + + /* RFC 8017 sec 8.2.1 step 2 - RSA signature */ + crypto_init_wait(&cwait); + sg_init_table(in_sg, 3); + sg_set_buf(&in_sg[0], in_buf, pad_len); + sg_set_buf(&in_sg[1], hash_prefix->data, hash_prefix->size); + sg_set_buf(&in_sg[2], 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 != rsassa_pkcs1_hash_len(hash_prefix)) + 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_key_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.key_size = rsassa_pkcs1_key_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"); diff --git a/crypto/sig.c b/crypto/sig.c index 7645bedf3a1fd4..be5ac0e5938421 100644 --- a/crypto/sig.c +++ b/crypto/sig.c @@ -5,12 +5,10 @@ * Copyright (c) 2023 Herbert Xu */ -#include #include #include #include #include -#include #include #include #include @@ -19,16 +17,35 @@ #define CRYPTO_ALG_TYPE_SIG_MASK 0x0000000e -static const struct crypto_type crypto_sig_type; +static void crypto_sig_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_sig *sig = __crypto_sig_tfm(tfm); + struct sig_alg *alg = crypto_sig_alg(sig); + + alg->exit(sig); +} static int crypto_sig_init_tfm(struct crypto_tfm *tfm) { - if (tfm->__crt_alg->cra_type != &crypto_sig_type) - return crypto_init_akcipher_ops_sig(tfm); + struct crypto_sig *sig = __crypto_sig_tfm(tfm); + struct sig_alg *alg = crypto_sig_alg(sig); + + if (alg->exit) + sig->base.exit = crypto_sig_exit_tfm; + + if (alg->init) + return alg->init(sig); return 0; } +static void crypto_sig_free_instance(struct crypto_instance *inst) +{ + struct sig_instance *sig = sig_instance(inst); + + sig->free(sig); +} + static void __maybe_unused crypto_sig_show(struct seq_file *m, struct crypto_alg *alg) { @@ -38,16 +55,17 @@ static void __maybe_unused crypto_sig_show(struct seq_file *m, static int __maybe_unused crypto_sig_report(struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_akcipher rsig = {}; + struct crypto_report_sig rsig = {}; strscpy(rsig.type, "sig", sizeof(rsig.type)); - return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rsig), &rsig); + return nla_put(skb, CRYPTOCFGA_REPORT_SIG, sizeof(rsig), &rsig); } static const struct crypto_type crypto_sig_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_sig_init_tfm, + .free = crypto_sig_free_instance, #ifdef CONFIG_PROC_FS .show = crypto_sig_show, #endif @@ -66,74 +84,83 @@ struct crypto_sig *crypto_alloc_sig(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_alloc_sig); -int crypto_sig_maxsize(struct crypto_sig *tfm) +static void sig_prepare_alg(struct sig_alg *alg) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); + struct crypto_alg *base = &alg->base; + + base->cra_type = &crypto_sig_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_SIG; +} - return crypto_akcipher_maxsize(*ctx); +static int sig_default_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + return -ENOSYS; } -EXPORT_SYMBOL_GPL(crypto_sig_maxsize); -int crypto_sig_sign(struct crypto_sig *tfm, - const void *src, unsigned int slen, - void *dst, unsigned int dlen) +static int sig_default_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *dst, unsigned int dlen) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); - struct crypto_akcipher_sync_data data = { - .tfm = *ctx, - .src = src, - .dst = dst, - .slen = slen, - .dlen = dlen, - }; - - return crypto_akcipher_sync_prep(&data) ?: - crypto_akcipher_sync_post(&data, - crypto_akcipher_sign(data.req)); + return -ENOSYS; } -EXPORT_SYMBOL_GPL(crypto_sig_sign); -int crypto_sig_verify(struct crypto_sig *tfm, - const void *src, unsigned int slen, - const void *digest, unsigned int dlen) +static int sig_default_set_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); - struct crypto_akcipher_sync_data data = { - .tfm = *ctx, - .src = src, - .slen = slen, - .dlen = dlen, - }; - int err; - - err = crypto_akcipher_sync_prep(&data); - if (err) - return err; - - memcpy(data.buf + slen, digest, dlen); - - return crypto_akcipher_sync_post(&data, - crypto_akcipher_verify(data.req)); + return -ENOSYS; } -EXPORT_SYMBOL_GPL(crypto_sig_verify); -int crypto_sig_set_pubkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen) +int crypto_register_sig(struct sig_alg *alg) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); + struct crypto_alg *base = &alg->base; + + if (!alg->sign) + alg->sign = sig_default_sign; + if (!alg->verify) + alg->verify = sig_default_verify; + if (!alg->set_priv_key) + alg->set_priv_key = sig_default_set_key; + if (!alg->set_pub_key) + return -EINVAL; + if (!alg->key_size) + return -EINVAL; + if (!alg->max_size) + alg->max_size = alg->key_size; + if (!alg->digest_size) + alg->digest_size = alg->key_size; + + sig_prepare_alg(alg); + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_sig); - return crypto_akcipher_set_pub_key(*ctx, key, keylen); +void crypto_unregister_sig(struct sig_alg *alg) +{ + crypto_unregister_alg(&alg->base); } -EXPORT_SYMBOL_GPL(crypto_sig_set_pubkey); +EXPORT_SYMBOL_GPL(crypto_unregister_sig); -int crypto_sig_set_privkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen) +int sig_register_instance(struct crypto_template *tmpl, + struct sig_instance *inst) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); + if (WARN_ON(!inst->free)) + return -EINVAL; + sig_prepare_alg(&inst->alg); + return crypto_register_instance(tmpl, sig_crypto_instance(inst)); +} +EXPORT_SYMBOL_GPL(sig_register_instance); - return crypto_akcipher_set_priv_key(*ctx, key, keylen); +int crypto_grab_sig(struct crypto_sig_spawn *spawn, + struct crypto_instance *inst, + const char *name, u32 type, u32 mask) +{ + spawn->base.frontend = &crypto_sig_type; + return crypto_grab_spawn(&spawn->base, inst, name, type, mask); } -EXPORT_SYMBOL_GPL(crypto_sig_set_privkey); +EXPORT_SYMBOL_GPL(crypto_grab_sig); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Public Key Signature Algorithms"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index ee8da628e9da46..7d768f0ed81f54 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -131,6 +132,11 @@ struct akcipher_test_suite { unsigned int count; }; +struct sig_test_suite { + const struct sig_testvec *vecs; + unsigned int count; +}; + struct kpp_test_suite { const struct kpp_testvec *vecs; unsigned int count; @@ -151,6 +157,7 @@ struct alg_test_desc { struct cprng_test_suite cprng; struct drbg_test_suite drbg; struct akcipher_test_suite akcipher; + struct sig_test_suite sig; struct kpp_test_suite kpp; } suite; }; @@ -4124,11 +4131,9 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, struct crypto_wait wait; unsigned int out_len_max, out_len = 0; int err = -ENOMEM; - struct scatterlist src, dst, src_tab[3]; - const char *m, *c; - unsigned int m_size, c_size; - const char *op; - u8 *key, *ptr; + struct scatterlist src, dst, src_tab[2]; + const char *c; + unsigned int c_size; if (testmgr_alloc_buf(xbuf)) return err; @@ -4139,92 +4144,53 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, crypto_init_wait(&wait); - key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len, - GFP_KERNEL); - if (!key) - goto free_req; - memcpy(key, vecs->key, vecs->key_len); - ptr = key + vecs->key_len; - ptr = test_pack_u32(ptr, vecs->algo); - ptr = test_pack_u32(ptr, vecs->param_len); - memcpy(ptr, vecs->params, vecs->param_len); - if (vecs->public_key_vec) - err = crypto_akcipher_set_pub_key(tfm, key, vecs->key_len); + err = crypto_akcipher_set_pub_key(tfm, vecs->key, + vecs->key_len); else - err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len); + err = crypto_akcipher_set_priv_key(tfm, vecs->key, + vecs->key_len); if (err) - goto free_key; + goto free_req; - /* - * First run test which do not require a private key, such as - * encrypt or verify. - */ + /* First run encrypt test which does not require a private key */ err = -ENOMEM; out_len_max = crypto_akcipher_maxsize(tfm); outbuf_enc = kzalloc(out_len_max, GFP_KERNEL); if (!outbuf_enc) - goto free_key; - - if (!vecs->siggen_sigver_test) { - m = vecs->m; - m_size = vecs->m_size; - c = vecs->c; - c_size = vecs->c_size; - op = "encrypt"; - } else { - /* Swap args so we could keep plaintext (digest) - * in vecs->m, and cooked signature in vecs->c. - */ - m = vecs->c; /* signature */ - m_size = vecs->c_size; - c = vecs->m; /* digest */ - c_size = vecs->m_size; - op = "verify"; - } + goto free_req; + + c = vecs->c; + c_size = vecs->c_size; err = -E2BIG; - if (WARN_ON(m_size > PAGE_SIZE)) + if (WARN_ON(vecs->m_size > PAGE_SIZE)) goto free_all; - memcpy(xbuf[0], m, m_size); + memcpy(xbuf[0], vecs->m, vecs->m_size); - sg_init_table(src_tab, 3); + sg_init_table(src_tab, 2); sg_set_buf(&src_tab[0], xbuf[0], 8); - sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); - if (vecs->siggen_sigver_test) { - if (WARN_ON(c_size > PAGE_SIZE)) - goto free_all; - memcpy(xbuf[1], c, c_size); - sg_set_buf(&src_tab[2], xbuf[1], c_size); - akcipher_request_set_crypt(req, src_tab, NULL, m_size, c_size); - } else { - sg_init_one(&dst, outbuf_enc, out_len_max); - akcipher_request_set_crypt(req, src_tab, &dst, m_size, - out_len_max); - } + sg_set_buf(&src_tab[1], xbuf[0] + 8, vecs->m_size - 8); + sg_init_one(&dst, outbuf_enc, out_len_max); + akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size, + out_len_max); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &wait); - err = crypto_wait_req(vecs->siggen_sigver_test ? - /* Run asymmetric signature verification */ - crypto_akcipher_verify(req) : - /* Run asymmetric encrypt */ - crypto_akcipher_encrypt(req), &wait); + err = crypto_wait_req(crypto_akcipher_encrypt(req), &wait); if (err) { - pr_err("alg: akcipher: %s test failed. err %d\n", op, err); + pr_err("alg: akcipher: encrypt test failed. err %d\n", err); goto free_all; } - if (!vecs->siggen_sigver_test && c) { + if (c) { if (req->dst_len != c_size) { - pr_err("alg: akcipher: %s test failed. Invalid output len\n", - op); + pr_err("alg: akcipher: encrypt test failed. Invalid output len\n"); err = -EINVAL; goto free_all; } /* verify that encrypted message is equal to expected */ if (memcmp(c, outbuf_enc, c_size) != 0) { - pr_err("alg: akcipher: %s test failed. Invalid output\n", - op); + pr_err("alg: akcipher: encrypt test failed. Invalid output\n"); hexdump(outbuf_enc, c_size); err = -EINVAL; goto free_all; @@ -4232,7 +4198,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, } /* - * Don't invoke (decrypt or sign) test which require a private key + * Don't invoke decrypt test which requires a private key * for vectors with only a public key. */ if (vecs->public_key_vec) { @@ -4245,13 +4211,12 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, goto free_all; } - if (!vecs->siggen_sigver_test && !c) { + if (!c) { c = outbuf_enc; c_size = req->dst_len; } err = -E2BIG; - op = vecs->siggen_sigver_test ? "sign" : "decrypt"; if (WARN_ON(c_size > PAGE_SIZE)) goto free_all; memcpy(xbuf[0], c, c_size); @@ -4261,34 +4226,29 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, crypto_init_wait(&wait); akcipher_request_set_crypt(req, &src, &dst, c_size, out_len_max); - err = crypto_wait_req(vecs->siggen_sigver_test ? - /* Run asymmetric signature generation */ - crypto_akcipher_sign(req) : - /* Run asymmetric decrypt */ - crypto_akcipher_decrypt(req), &wait); + err = crypto_wait_req(crypto_akcipher_decrypt(req), &wait); if (err) { - pr_err("alg: akcipher: %s test failed. err %d\n", op, err); + pr_err("alg: akcipher: decrypt test failed. err %d\n", err); goto free_all; } out_len = req->dst_len; - if (out_len < m_size) { - pr_err("alg: akcipher: %s test failed. Invalid output len %u\n", - op, out_len); + if (out_len < vecs->m_size) { + pr_err("alg: akcipher: decrypt test failed. Invalid output len %u\n", + out_len); err = -EINVAL; goto free_all; } /* verify that decrypted message is equal to the original msg */ - if (memchr_inv(outbuf_dec, 0, out_len - m_size) || - memcmp(m, outbuf_dec + out_len - m_size, m_size)) { - pr_err("alg: akcipher: %s test failed. Invalid output\n", op); + if (memchr_inv(outbuf_dec, 0, out_len - vecs->m_size) || + memcmp(vecs->m, outbuf_dec + out_len - vecs->m_size, + vecs->m_size)) { + pr_err("alg: akcipher: decrypt test failed. Invalid output\n"); hexdump(outbuf_dec, out_len); err = -EINVAL; } free_all: kfree(outbuf_dec); kfree(outbuf_enc); -free_key: - kfree(key); free_req: akcipher_request_free(req); free_xbuf: @@ -4338,6 +4298,113 @@ static int alg_test_akcipher(const struct alg_test_desc *desc, return err; } +static int test_sig_one(struct crypto_sig *tfm, const struct sig_testvec *vecs) +{ + u8 *ptr, *key __free(kfree); + int err, sig_size; + + key = kmalloc(vecs->key_len + 2 * sizeof(u32) + vecs->param_len, + GFP_KERNEL); + if (!key) + return -ENOMEM; + + /* ecrdsa expects additional parameters appended to the key */ + memcpy(key, vecs->key, vecs->key_len); + ptr = key + vecs->key_len; + ptr = test_pack_u32(ptr, vecs->algo); + ptr = test_pack_u32(ptr, vecs->param_len); + memcpy(ptr, vecs->params, vecs->param_len); + + if (vecs->public_key_vec) + err = crypto_sig_set_pubkey(tfm, key, vecs->key_len); + else + err = crypto_sig_set_privkey(tfm, key, vecs->key_len); + if (err) + return err; + + /* + * Run asymmetric signature verification first + * (which does not require a private key) + */ + err = crypto_sig_verify(tfm, vecs->c, vecs->c_size, + vecs->m, vecs->m_size); + if (err) { + pr_err("alg: sig: verify test failed: err %d\n", err); + return err; + } + + /* + * Don't invoke sign test (which requires a private key) + * for vectors with only a public key. + */ + if (vecs->public_key_vec) + return 0; + + sig_size = crypto_sig_keysize(tfm); + if (sig_size < vecs->c_size) { + pr_err("alg: sig: invalid maxsize %u\n", sig_size); + return -EINVAL; + } + + u8 *sig __free(kfree) = kzalloc(sig_size, GFP_KERNEL); + if (!sig) + return -ENOMEM; + + /* Run asymmetric signature generation */ + err = crypto_sig_sign(tfm, vecs->m, vecs->m_size, sig, sig_size); + if (err) { + pr_err("alg: sig: sign test failed: err %d\n", err); + return err; + } + + /* Verify that generated signature equals cooked signature */ + if (memcmp(sig, vecs->c, vecs->c_size) || + memchr_inv(sig + vecs->c_size, 0, sig_size - vecs->c_size)) { + pr_err("alg: sig: sign test failed: invalid output\n"); + hexdump(sig, sig_size); + return -EINVAL; + } + + return 0; +} + +static int test_sig(struct crypto_sig *tfm, const char *alg, + const struct sig_testvec *vecs, unsigned int tcount) +{ + const char *algo = crypto_tfm_alg_driver_name(crypto_sig_tfm(tfm)); + int ret, i; + + for (i = 0; i < tcount; i++) { + ret = test_sig_one(tfm, vecs++); + if (ret) { + pr_err("alg: sig: test %d failed for %s: err %d\n", + i + 1, algo, ret); + return ret; + } + } + return 0; +} + +static int alg_test_sig(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) +{ + struct crypto_sig *tfm; + int err = 0; + + tfm = crypto_alloc_sig(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: sig: Failed to load tfm for %s: %ld\n", + driver, PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + if (desc->suite.sig.vecs) + err = test_sig(tfm, desc->alg, desc->suite.sig.vecs, + desc->suite.sig.count); + + crypto_free_sig(tfm); + return err; +} + static int alg_test_null(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { @@ -5127,36 +5194,36 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { .alg = "ecdsa-nist-p192", - .test = alg_test_akcipher, + .test = alg_test_sig, .suite = { - .akcipher = __VECS(ecdsa_nist_p192_tv_template) + .sig = __VECS(ecdsa_nist_p192_tv_template) } }, { .alg = "ecdsa-nist-p256", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p256_tv_template) + .sig = __VECS(ecdsa_nist_p256_tv_template) } }, { .alg = "ecdsa-nist-p384", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p384_tv_template) + .sig = __VECS(ecdsa_nist_p384_tv_template) } }, { .alg = "ecdsa-nist-p521", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p521_tv_template) + .sig = __VECS(ecdsa_nist_p521_tv_template) } }, { .alg = "ecrdsa", - .test = alg_test_akcipher, + .test = alg_test_sig, .suite = { - .akcipher = __VECS(ecrdsa_tv_template) + .sig = __VECS(ecrdsa_tv_template) } }, { .alg = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)", @@ -5448,6 +5515,24 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(nhpoly1305_tv_template) } + }, { + .alg = "p1363(ecdsa-nist-p192)", + .test = alg_test_null, + }, { + .alg = "p1363(ecdsa-nist-p256)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(p1363_ecdsa_nist_p256_tv_template) + } + }, { + .alg = "p1363(ecdsa-nist-p384)", + .test = alg_test_null, + .fips_allowed = 1, + }, { + .alg = "p1363(ecdsa-nist-p521)", + .test = alg_test_null, + .fips_allowed = 1, }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, @@ -5455,34 +5540,38 @@ static const struct alg_test_desc alg_test_descs[] = { .cipher = __VECS(fcrypt_pcbc_tv_template) } }, { - .alg = "pkcs1pad(rsa,sha224)", + .alg = "pkcs1(rsa,sha224)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha256)", - .test = alg_test_akcipher, + .alg = "pkcs1(rsa,sha256)", + .test = alg_test_sig, .fips_allowed = 1, .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, + .fips_allowed = 1, + }, { + .alg = "pkcs1(rsa,sha3-384)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha3-384)", + .alg = "pkcs1(rsa,sha3-512)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha3-512)", + .alg = "pkcs1(rsa,sha384)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha384)", + .alg = "pkcs1(rsa,sha512)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha512)", + .alg = "pkcs1pad(rsa)", .test = alg_test_null, .fips_allowed = 1, }, { @@ -5679,6 +5768,33 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(wp512_tv_template) } + }, { + .alg = "x962(ecdsa-nist-p192)", + .test = alg_test_sig, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p192_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p256)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p256_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p384)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p384_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p521)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p521_tv_template) + } }, { .alg = "xcbc(aes)", .test = alg_test_hash, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 9b38501a17b2a0..55aae1859d2c5d 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -21,6 +21,7 @@ #define _CRYPTO_TESTMGR_H #include +#include #define MAX_IVLEN 32 @@ -149,6 +150,16 @@ struct drbg_testvec { }; struct akcipher_testvec { + const unsigned char *key; + const unsigned char *m; + const unsigned char *c; + unsigned int key_len; + unsigned int m_size; + unsigned int c_size; + bool public_key_vec; +}; + +struct sig_testvec { const unsigned char *key; const unsigned char *params; const unsigned char *m; @@ -158,7 +169,6 @@ struct akcipher_testvec { unsigned int m_size; unsigned int c_size; bool public_key_vec; - bool siggen_sigver_test; enum OID algo; }; @@ -647,26 +657,713 @@ static const struct akcipher_testvec rsa_tv_template[] = { } }; +#ifdef CONFIG_CPU_BIG_ENDIAN +#define be64_to_cpua(b1, b2, b3, b4, b5, b6, b7, b8) \ + 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8 +#else +#define be64_to_cpua(b1, b2, b3, b4, b5, b6, b7, b8) \ + 0x##b8, 0x##b7, 0x##b6, 0x##b5, 0x##b4, 0x##b3, 0x##b2, 0x##b1 +#endif + /* * ECDSA test vectors. */ -static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { +static const struct sig_testvec ecdsa_nist_p192_tv_template[] = { { - .key = + .key = /* secp192r1(sha1) */ + "\x04\xf7\x46\xf8\x2f\x15\xf6\x22\x8e\xd7\x57\x4f\xcc\xe7\xbb\xc1" + "\xd4\x09\x73\xcf\xea\xd0\x15\x07\x3d\xa5\x8a\x8a\x95\x43\xe4\x68" + "\xea\xc6\x25\xc1\xc1\x01\x25\x4c\x7e\xc3\x3c\xa6\x04\x0a\xe7\x08" + "\x98", + .key_len = 49, + .m = + "\xcd\xb9\xd2\x1c\xb7\x6f\xcd\x44\xb3\xfd\x63\xea\xa3\x66\x7f\xae" + "\x63\x85\xe7\x82", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ad, 59, ad, 88, 27, d6, 92, 6b), + be64_to_cpua(a0, 27, 91, c6, f6, 7f, c3, 09), + be64_to_cpua(ba, e5, 93, 83, 6e, b6, 3b, 63), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(86, 80, 6f, a5, 79, 77, da, d0), + be64_to_cpua(ef, 95, 52, 7b, a0, 0f, e4, 18), + be64_to_cpua(10, 68, 01, 9d, ba, ce, 83, 08), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha224) */ + "\x04\xb6\x4b\xb1\xd1\xac\xba\x24\x8f\x65\xb2\x60\x00\x90\xbf\xbd" + "\x78\x05\x73\xe9\x79\x1d\x6f\x7c\x0b\xd2\xc3\x93\xa7\x28\xe1\x75" + "\xf7\xd5\x95\x1d\x28\x10\xc0\x75\x50\x5c\x1a\x4f\x3f\x8f\xa5\xee" + "\xa3", + .key_len = 49, + .m = + "\x8d\xd6\xb8\x3e\xe5\xff\x23\xf6\x25\xa2\x43\x42\x74\x45\xa7\x40" + "\x3a\xff\x2f\xe1\xd3\xf6\x9f\xe8\x33\xcb\x12\x11", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(83, 7b, 12, e6, b6, 5b, cb, d4), + be64_to_cpua(14, f8, 11, 2b, 55, dc, ae, 37), + be64_to_cpua(5a, 8b, 82, 69, 7e, 8a, 0a, 09), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(a3, e3, 5c, 99, db, 92, 5b, 36), + be64_to_cpua(eb, c3, 92, 0f, 1e, 72, ee, c4), + be64_to_cpua(6a, 14, 4f, 53, 75, c8, 02, 48), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha256) */ + "\x04\xe2\x51\x24\x9b\xf7\xb6\x32\x82\x39\x66\x3d\x5b\xec\x3b\xae" + "\x0c\xd5\xf2\x67\xd1\xc7\xe1\x02\xe4\xbf\x90\x62\xb8\x55\x75\x56" + "\x69\x20\x5e\xcb\x4e\xca\x33\xd6\xcb\x62\x6b\x94\xa9\xa2\xe9\x58" + "\x91", + .key_len = 49, + .m = + "\x35\xec\xa1\xa0\x9e\x14\xde\x33\x03\xb6\xf6\xbd\x0c\x2f\xb2\xfd" + "\x1f\x27\x82\xa5\xd7\x70\x3f\xef\xa0\x82\x69\x8e\x73\x31\x8e\xd7", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(01, 48, fb, 5f, 72, 2a, d4, 8f), + be64_to_cpua(6b, 1a, 58, 56, f1, 8f, f7, fd), + be64_to_cpua(3f, 72, 3f, 1f, 42, d2, 3f, 1d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(7d, 3a, 97, d9, cd, 1a, 6a, 49), + be64_to_cpua(32, dd, 41, 74, 6a, 51, c7, d9), + be64_to_cpua(b3, 69, 43, fd, 48, 19, 86, cf), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha384) */ + "\x04\x5a\x13\xfe\x68\x86\x4d\xf4\x17\xc7\xa4\xe5\x8c\x65\x57\xb7" + "\x03\x73\x26\x57\xfb\xe5\x58\x40\xd8\xfd\x49\x05\xab\xf1\x66\x1f" + "\xe2\x9d\x93\x9e\xc2\x22\x5a\x8b\x4f\xf3\x77\x22\x59\x7e\xa6\x4e" + "\x8b", + .key_len = 49, + .m = + "\x9d\x2e\x1a\x8f\xed\x6c\x4b\x61\xae\xac\xd5\x19\x79\xce\x67\xf9" + "\xa0\x34\xeb\xb0\x81\xf9\xd9\xdc\x6e\xb3\x5c\xa8\x69\xfc\x8a\x61" + "\x39\x81\xfb\xfd\x5c\x30\x6b\xa8\xee\xed\x89\xaf\xa3\x05\xe4\x78", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(dd, 15, bb, d6, 8c, a7, 03, 78), + be64_to_cpua(cf, 7f, 34, b4, b4, e5, c5, 00), + be64_to_cpua(f0, a3, 38, ce, 2b, f8, 9d, 1a), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(93, 12, 3b, 3b, 28, fb, 6d, e1), + be64_to_cpua(d1, 01, 77, 44, 5d, 53, a4, 7c), + be64_to_cpua(64, bc, 5a, 1f, 82, 96, 61, d7), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha512) */ + "\x04\xd5\xf2\x6e\xc3\x94\x5c\x52\xbc\xdf\x86\x6c\x14\xd1\xca\xea" + "\xcc\x72\x3a\x8a\xf6\x7a\x3a\x56\x36\x3b\xca\xc6\x94\x0e\x17\x1d" + "\x9e\xa0\x58\x28\xf9\x4b\xe6\xd1\xa5\x44\x91\x35\x0d\xe7\xf5\x11" + "\x57", + .key_len = 49, + .m = + "\xd5\x4b\xe9\x36\xda\xd8\x6e\xc0\x50\x03\xbe\x00\x43\xff\xf0\x23" + "\xac\xa2\x42\xe7\x37\x77\x79\x52\x8f\x3e\xc0\x16\xc1\xfc\x8c\x67" + "\x16\xbc\x8a\x5d\x3b\xd3\x13\xbb\xb6\xc0\x26\x1b\xeb\x33\xcc\x70" + "\x4a\xf2\x11\x37\xe8\x1b\xba\x55\xac\x69\xe1\x74\x62\x7c\x6e\xb5", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(2b, 11, 2d, 1c, b6, 06, c9, 6c), + be64_to_cpua(dd, 3f, 07, 87, 12, a0, d4, ac), + be64_to_cpua(88, 5b, 8f, 59, 43, bf, cf, c6), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(28, 6a, df, 97, fd, 82, 76, 24), + be64_to_cpua(a9, 14, 2a, 5e, f5, e5, fb, 72), + be64_to_cpua(73, b4, 22, 9a, 98, 73, 3c, 83), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p256_tv_template[] = { + { + .key = /* secp256r1(sha1) */ + "\x04\xb9\x7b\xbb\xd7\x17\x64\xd2\x7e\xfc\x81\x5d\x87\x06\x83\x41" + "\x22\xd6\x9a\xaa\x87\x17\xec\x4f\x63\x55\x2f\x94\xba\xdd\x83\xe9" + "\x34\x4b\xf3\xe9\x91\x13\x50\xb6\xcb\xca\x62\x08\xe7\x3b\x09\xdc" + "\xc3\x63\x4b\x2d\xb9\x73\x53\xe4\x45\xe6\x7c\xad\xe7\x6b\xb0\xe8" + "\xaf", + .key_len = 65, + .m = + "\xc2\x2b\x5f\x91\x78\x34\x26\x09\x42\x8d\x6f\x51\xb2\xc5\xaf\x4c" + "\x0b\xde\x6a\x42", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ee, ca, 6a, 52, 0e, 48, 4d, cc), + be64_to_cpua(f7, d4, ad, 8d, 94, 5a, 69, 89), + be64_to_cpua(cf, d4, e7, b7, f0, 82, 56, 41), + be64_to_cpua(f9, 25, ce, 9f, 3a, a6, 35, 81), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(fb, 9d, 8b, de, d4, 8d, 6f, ad), + be64_to_cpua(f1, 03, 03, f3, 3b, e2, 73, f7), + be64_to_cpua(8a, fa, 54, 93, 29, a7, 70, 86), + be64_to_cpua(d7, e4, ef, 52, 66, d3, 5b, 9d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha224) */ + "\x04\x8b\x6d\xc0\x33\x8e\x2d\x8b\x67\xf5\xeb\xc4\x7f\xa0\xf5\xd9" + "\x7b\x03\xa5\x78\x9a\xb5\xea\x14\xe4\x23\xd0\xaf\xd7\x0e\x2e\xa0" + "\xc9\x8b\xdb\x95\xf8\xb3\xaf\xac\x00\x2c\x2c\x1f\x7a\xfd\x95\x88" + "\x43\x13\xbf\xf3\x1c\x05\x1a\x14\x18\x09\x3f\xd6\x28\x3e\xc5\xa0" + "\xd4", + .key_len = 65, + .m = + "\x1a\x15\xbc\xa3\xe4\xed\x3a\xb8\x23\x67\xc6\xc4\x34\xf8\x6c\x41" + "\x04\x0b\xda\xc5\x77\xfa\x1c\x2d\xe6\x2c\x3b\xe0", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(7d, 25, d8, 25, f5, 81, d2, 1e), + be64_to_cpua(34, 62, 79, cb, 6a, 91, 67, 2e), + be64_to_cpua(ae, ce, 77, 59, 1a, db, 59, d5), + be64_to_cpua(20, 43, fa, c0, 9f, 9d, 7b, e7), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(ce, d5, 2e, 8b, de, 5a, 04, 0e), + be64_to_cpua(bf, 50, 05, 58, 39, 0e, 26, 92), + be64_to_cpua(76, 20, 4a, 77, 22, ec, c8, 66), + be64_to_cpua(5f, f8, 74, f8, 57, d0, 5e, 54), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha256) */ + "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" + "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" + "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" + "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" + "\xb8", + .key_len = 65, + .m = + "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" + "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(91, dc, 02, 67, dc, 0c, d0, 82), + be64_to_cpua(ac, 44, c3, e8, 24, 11, 2d, a4), + be64_to_cpua(09, dc, 29, 63, a8, 1a, ad, fc), + be64_to_cpua(08, 31, fa, 74, 0d, 1d, 21, 5d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(4f, 2a, 65, 35, 23, e3, 1d, fa), + be64_to_cpua(0a, 6e, 1b, c4, af, e1, 83, c3), + be64_to_cpua(f9, a9, 81, ac, 4a, 50, d0, 91), + be64_to_cpua(bd, ff, ce, ee, 42, c3, 97, ff), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha384) */ + "\x04\xc5\xc6\xea\x60\xc9\xce\xad\x02\x8d\xf5\x3e\x24\xe3\x52\x1d" + "\x28\x47\x3b\xc3\x6b\xa4\x99\x35\x99\x11\x88\x88\xc8\xf4\xee\x7e" + "\x8c\x33\x8f\x41\x03\x24\x46\x2b\x1a\x82\xf9\x9f\xe1\x97\x1b\x00" + "\xda\x3b\x24\x41\xf7\x66\x33\x58\x3d\x3a\x81\xad\xcf\x16\xe9\xe2" + "\x7c", + .key_len = 65, + .m = + "\x3e\x78\x70\xfb\xcd\x66\xba\x91\xa1\x79\xff\x1e\x1c\x6b\x78\xe6" + "\xc0\x81\x3a\x65\x97\x14\x84\x36\x14\x1a\x9a\xb7\xc5\xab\x84\x94" + "\x5e\xbb\x1b\x34\x71\xcb\x41\xe1\xf6\xfc\x92\x7b\x34\xbb\x86\xbb", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(f2, e4, 6c, c7, 94, b1, d5, fe), + be64_to_cpua(08, b2, 6b, 24, 94, 48, 46, 5e), + be64_to_cpua(d0, 2e, 95, 54, d1, 95, 64, 93), + be64_to_cpua(8e, f3, 6f, dc, f8, 69, a6, 2e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(c0, 60, 11, 92, dc, 17, 89, 12), + be64_to_cpua(69, f4, 3b, 4f, 47, cf, 9b, 16), + be64_to_cpua(19, fb, 5f, 92, f4, c9, 23, 37), + be64_to_cpua(eb, a7, 80, 26, dc, f9, 3a, 44), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha512) */ + "\x04\xd7\x27\x46\x49\xf6\x26\x85\x12\x40\x76\x8e\xe2\xe6\x2a\x7a" + "\x83\xb1\x4e\x7a\xeb\x3b\x5c\x67\x4a\xb5\xa4\x92\x8c\x69\xff\x38" + "\xee\xd9\x4e\x13\x29\x59\xad\xde\x6b\xbb\x45\x31\xee\xfd\xd1\x1b" + "\x64\xd3\xb5\xfc\xaf\x9b\x4b\x88\x3b\x0e\xb7\xd6\xdf\xf1\xd5\x92" + "\xbf", + .key_len = 65, + .m = + "\x57\xb7\x9e\xe9\x05\x0a\x8c\x1b\xc9\x13\xe5\x4a\x24\xc7\xe2\xe9" + "\x43\xc3\xd1\x76\x62\xf4\x98\x1a\x9c\x13\xb0\x20\x1b\xe5\x39\xca" + "\x4f\xd9\x85\x34\x95\xa2\x31\xbc\xbb\xde\xdd\x76\xbb\x61\xe3\xcf" + "\x9d\xc0\x49\x7a\xf3\x7a\xc4\x7d\xa8\x04\x4b\x8d\xb4\x4d\x5b\xd6", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(76, f6, 04, 99, 09, 37, 4d, fa), + be64_to_cpua(ed, 8c, 73, 30, 6c, 22, b3, 97), + be64_to_cpua(40, ea, 44, 81, 00, 4e, 29, 08), + be64_to_cpua(b8, 6d, 87, 81, 43, df, fb, 9f), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(76, 31, 79, 4a, e9, 81, 6a, ee), + be64_to_cpua(5c, ad, c3, 78, 1c, c2, c1, 19), + be64_to_cpua(f8, 00, dd, ab, d4, c0, 2b, e6), + be64_to_cpua(1e, b9, 75, 31, f6, 04, a5, 4d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p384_tv_template[] = { + { + .key = /* secp384r1(sha1) */ + "\x04\x89\x25\xf3\x97\x88\xcb\xb0\x78\xc5\x72\x9a\x14\x6e\x7a\xb1" + "\x5a\xa5\x24\xf1\x95\x06\x9e\x28\xfb\xc4\xb9\xbe\x5a\x0d\xd9\x9f" + "\xf3\xd1\x4d\x2d\x07\x99\xbd\xda\xa7\x66\xec\xbb\xea\xba\x79\x42" + "\xc9\x34\x89\x6a\xe7\x0b\xc3\xf2\xfe\x32\x30\xbe\xba\xf9\xdf\x7e" + "\x4b\x6a\x07\x8e\x26\x66\x3f\x1d\xec\xa2\x57\x91\x51\xdd\x17\x0e" + "\x0b\x25\xd6\x80\x5c\x3b\xe6\x1a\x98\x48\x91\x45\x7a\x73\xb0\xc3" + "\xf1", + .key_len = 97, + .m = + "\x12\x55\x28\xf0\x77\xd5\xb6\x21\x71\x32\x48\xcd\x28\xa8\x25\x22" + "\x3a\x69\xc1\x93", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ec, 7c, 7e, d0, 87, d7, d7, 6e), + be64_to_cpua(78, f1, 4c, 26, e6, 5b, 86, cf), + be64_to_cpua(3a, c6, f1, 32, 3c, ce, 70, 2b), + be64_to_cpua(8d, 26, 8e, ae, 63, 3f, bc, 20), + be64_to_cpua(57, 55, 07, 20, 43, 30, de, a0), + be64_to_cpua(f5, 0f, 24, 4c, 07, 93, 6f, 21), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(79, 12, 2a, b7, c5, 15, 92, c5), + be64_to_cpua(4a, a1, 59, f1, 1c, a4, 58, 26), + be64_to_cpua(74, a0, 0f, bf, af, c3, 36, 76), + be64_to_cpua(df, 28, 8c, 1b, fa, f9, 95, 88), + be64_to_cpua(5f, 63, b1, be, 5e, 4c, 0e, a1), + be64_to_cpua(cd, bb, 7e, 81, 5d, 8f, 63, c0), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha224) */ + "\x04\x69\x6c\xcf\x62\xee\xd0\x0d\xe5\xb5\x2f\x70\x54\xcf\x26\xa0" + "\xd9\x98\x8d\x92\x2a\xab\x9b\x11\xcb\x48\x18\xa1\xa9\x0d\xd5\x18" + "\x3e\xe8\x29\x6e\xf6\xe4\xb5\x8e\xc7\x4a\xc2\x5f\x37\x13\x99\x05" + "\xb6\xa4\x9d\xf9\xfb\x79\x41\xe7\xd7\x96\x9f\x73\x3b\x39\x43\xdc" + "\xda\xf4\x06\xb9\xa5\x29\x01\x9d\x3b\xe1\xd8\x68\x77\x2a\xf4\x50" + "\x6b\x93\x99\x6c\x66\x4c\x42\x3f\x65\x60\x6c\x1c\x0b\x93\x9b\x9d" + "\xe0", + .key_len = 97, + .m = + "\x12\x80\xb6\xeb\x25\xe2\x3d\xf0\x21\x32\x96\x17\x3a\x38\x39\xfd" + "\x1f\x05\x34\x7b\xb8\xf9\x71\x66\x03\x4f\xd5\xe5", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(3f, dd, 15, 1b, 68, 2b, 9d, 8b), + be64_to_cpua(c9, 9c, 11, b8, 10, 01, c5, 41), + be64_to_cpua(c5, da, b4, e3, 93, 07, e0, 99), + be64_to_cpua(97, f1, c8, 72, 26, cf, 5a, 5e), + be64_to_cpua(ec, cb, e4, 89, 47, b2, f7, bc), + be64_to_cpua(8a, 51, 84, ce, 13, 1e, d2, dc), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(88, 2b, 82, 26, 5e, 1c, da, fb), + be64_to_cpua(9f, 19, d0, 42, 8b, 93, c2, 11), + be64_to_cpua(4d, d0, c6, 6e, b0, e9, fc, 14), + be64_to_cpua(df, d8, 68, a2, 64, 42, 65, f3), + be64_to_cpua(4b, 00, 08, 31, 6c, f5, d5, f6), + be64_to_cpua(8b, 03, 2c, fc, 1f, d1, a9, a4), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha256) */ + "\x04\xee\xd6\xda\x3e\x94\x90\x00\x27\xed\xf8\x64\x55\xd6\x51\x9a" + "\x1f\x52\x00\x63\x78\xf1\xa9\xfd\x75\x4c\x9e\xb2\x20\x1a\x91\x5a" + "\xba\x7a\xa3\xe5\x6c\xb6\x25\x68\x4b\xe8\x13\xa6\x54\x87\x2c\x0e" + "\xd0\x83\x95\xbc\xbf\xc5\x28\x4f\x77\x1c\x46\xa6\xf0\xbc\xd4\xa4" + "\x8d\xc2\x8f\xb3\x32\x37\x40\xd6\xca\xf8\xae\x07\x34\x52\x39\x52" + "\x17\xc3\x34\x29\xd6\x40\xea\x5c\xb9\x3f\xfb\x32\x2e\x12\x33\xbc" + "\xab", + .key_len = 97, + .m = + "\xaa\xe7\xfd\x03\x26\xcb\x94\x71\xe4\xce\x0f\xc5\xff\xa6\x29\xa3" + "\xe1\xcc\x4c\x35\x4e\xde\xca\x80\xab\x26\x0c\x25\xe6\x68\x11\xc2", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(c8, 8d, 2c, 79, 3a, 8e, 32, c4), + be64_to_cpua(b6, c6, fc, 70, 2e, 66, 3c, 77), + be64_to_cpua(af, 06, 3f, 84, 04, e2, f9, 67), + be64_to_cpua(cc, 47, 53, 87, bc, bd, 83, 3f), + be64_to_cpua(8e, 3f, 7e, ce, 0a, 9b, aa, 59), + be64_to_cpua(08, 09, 12, 9d, 6e, 96, 64, a6), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(10, 0e, f4, 1f, 39, ca, 4d, 43), + be64_to_cpua(4f, 8d, de, 1e, 93, 8d, 95, bb), + be64_to_cpua(15, 68, c0, 75, 3e, 23, 5e, 36), + be64_to_cpua(dd, ce, bc, b2, 97, f4, 9c, f3), + be64_to_cpua(26, a2, b0, 89, 42, 0a, da, d9), + be64_to_cpua(40, 34, b8, 90, a9, 80, ab, 47), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha384) */ + "\x04\x3a\x2f\x62\xe7\x1a\xcf\x24\xd0\x0b\x7c\xe0\xed\x46\x0a\x4f" + "\x74\x16\x43\xe9\x1a\x25\x7c\x55\xff\xf0\x29\x68\x66\x20\x91\xf9" + "\xdb\x2b\xf6\xb3\x6c\x54\x01\xca\xc7\x6a\x5c\x0d\xeb\x68\xd9\x3c" + "\xf1\x01\x74\x1f\xf9\x6c\xe5\x5b\x60\xe9\x7f\x5d\xb3\x12\x80\x2a" + "\xd8\x67\x92\xc9\x0e\x4c\x4c\x6b\xa1\xb2\xa8\x1e\xac\x1c\x97\xd9" + "\x21\x67\xe5\x1b\x5a\x52\x31\x68\xd6\xee\xf0\x19\xb0\x55\xed\x89" + "\x9e", + .key_len = 97, + .m = + "\x8d\xf2\xc0\xe9\xa8\xf3\x8e\x44\xc4\x8c\x1a\xa0\xb8\xd7\x17\xdf" + "\xf2\x37\x1b\xc6\xe3\xf5\x62\xcc\x68\xf5\xd5\x0b\xbf\x73\x2b\xb1" + "\xb0\x4c\x04\x00\x31\xab\xfe\xc8\xd6\x09\xc8\xf2\xea\xd3\x28\xff", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(a2, a4, c8, f2, ea, 9d, 11, 1f), + be64_to_cpua(3b, 1f, 07, 8f, 15, 02, fe, 1d), + be64_to_cpua(29, e6, fb, ca, 8c, d6, b6, b4), + be64_to_cpua(2d, 7a, 91, 5f, 49, 2d, 22, 08), + be64_to_cpua(ee, 2e, 62, 35, 46, fa, 00, d8), + be64_to_cpua(9b, 28, 68, c0, a1, ea, 8c, 50), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(ab, 8d, 4e, de, e6, 6d, 9b, 66), + be64_to_cpua(96, 17, 04, c9, 05, 77, f1, 8e), + be64_to_cpua(44, 92, 8c, 86, 99, 65, b3, 97), + be64_to_cpua(71, cd, 8f, 18, 99, f0, 0f, 13), + be64_to_cpua(bf, e3, 75, 24, 49, ac, fb, c8), + be64_to_cpua(fc, 50, f6, 43, bd, 50, 82, 0e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha512) */ + "\x04\xb4\xe7\xc1\xeb\x64\x25\x22\x46\xc3\x86\x61\x80\xbe\x1e\x46" + "\xcb\xf6\x05\xc2\xee\x73\x83\xbc\xea\x30\x61\x4d\x40\x05\x41\xf4" + "\x8c\xe3\x0e\x5c\xf0\x50\xf2\x07\x19\xe8\x4f\x25\xbe\xee\x0c\x95" + "\x54\x36\x86\xec\xc2\x20\x75\xf3\x89\xb5\x11\xa1\xb7\xf5\xaf\xbe" + "\x81\xe4\xc3\x39\x06\xbd\xe4\xfe\x68\x1c\x6d\x99\x2b\x1b\x63\xfa" + "\xdf\x42\x5c\xc2\x5a\xc7\x0c\xf4\x15\xf7\x1b\xa3\x2e\xd7\x00\xac" + "\xa3", + .key_len = 97, + .m = + "\xe8\xb7\x52\x7d\x1a\x44\x20\x05\x53\x6b\x3a\x68\xf2\xe7\x6c\xa1" + "\xae\x9d\x84\xbb\xba\x52\x43\x3e\x2c\x42\x78\x49\xbf\x78\xb2\x71" + "\xeb\xe1\xe0\xe8\x42\x7b\x11\xad\x2b\x99\x05\x1d\x36\xe6\xac\xfc" + "\x55\x73\xf0\x15\x63\x39\xb8\x6a\x6a\xc5\x91\x5b\xca\x6a\xa8\x0e", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(3e, b3, c7, a8, b3, 17, 77, d1), + be64_to_cpua(dc, 2b, 43, 0e, 6a, b3, 53, 6f), + be64_to_cpua(4c, fc, 6f, 80, e3, af, b3, d9), + be64_to_cpua(9a, 02, de, 93, e8, 83, e4, 84), + be64_to_cpua(4d, c6, ef, da, 02, e7, 0f, 52), + be64_to_cpua(00, 1d, 20, 94, 77, fe, 31, fa), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(4e, 45, cf, 3c, 93, ff, 50, 5d), + be64_to_cpua(34, e4, 8b, 80, a5, b6, da, 2c), + be64_to_cpua(c4, 6a, 03, 5f, 8d, 7a, f9, fb), + be64_to_cpua(ec, 63, e3, 0c, ec, 50, dc, cc), + be64_to_cpua(de, 3a, 3d, 16, af, b4, 52, 6a), + be64_to_cpua(63, f6, f0, 3d, 5f, 5f, 99, 3f), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p521_tv_template[] = { + { + .key = /* secp521r1(sha224) */ + "\x04\x01\x4f\x43\x18\xb6\xa9\xc9\x5d\x68\xd3\xa9\x42\xf8\x98\xc0" + "\xd2\xd1\xa9\x50\x3b\xe8\xc4\x40\xe6\x11\x78\x88\x4b\xbd\x76\xa7" + "\x9a\xe0\xdd\x31\xa4\x67\x78\x45\x33\x9e\x8c\xd1\xc7\x44\xac\x61" + "\x68\xc8\x04\xe7\x5c\x79\xb1\xf1\x41\x0c\x71\xc0\x53\xa8\xbc\xfb" + "\xf5\xca\xd4\x01\x40\xfd\xa3\x45\xda\x08\xe0\xb4\xcb\x28\x3b\x0a" + "\x02\x35\x5f\x02\x9f\x3f\xcd\xef\x08\x22\x40\x97\x74\x65\xb7\x76" + "\x85\xc7\xc0\x5c\xfb\x81\xe1\xa5\xde\x0c\x4e\x8b\x12\x31\xb6\x47" + "\xed\x37\x0f\x99\x3f\x26\xba\xa3\x8e\xff\x79\x34\x7c\x3a\xfe\x1f" + "\x3b\x83\x82\x2f\x14", + .key_len = 133, + .m = + "\xa2\x3a\x6a\x8c\x7b\x3c\xf2\x51\xf8\xbe\x5f\x4f\x3b\x15\x05\xc4" + "\xb5\xbc\x19\xe7\x21\x85\xe9\x23\x06\x33\x62\xfb", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(46, 6b, c7, af, 7a, b9, 19, 0a), + be64_to_cpua(6c, a6, 9b, 89, 8b, 1e, fd, 09), + be64_to_cpua(98, 85, 29, 88, ff, 0b, 94, 94), + be64_to_cpua(18, c6, 37, 8a, cb, a7, d8, 7d), + be64_to_cpua(f8, 3f, 59, 0f, 74, f0, 3f, d8), + be64_to_cpua(e2, ef, 07, 92, ee, 60, 94, 06), + be64_to_cpua(35, f6, dc, 6d, 02, 7b, 22, ac), + be64_to_cpua(d6, 43, e7, ff, 42, b2, ba, 74), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 01), + be64_to_cpua(50, b1, a5, 98, 92, 2a, a5, 52), + be64_to_cpua(1c, ad, 22, da, 82, 00, 35, a3), + be64_to_cpua(0e, 64, cc, c4, e8, 43, d9, 0e), + be64_to_cpua(30, 90, 0f, 1c, 8f, 78, d3, 9f), + be64_to_cpua(26, 0b, 5f, 49, 32, 6b, 91, 99), + be64_to_cpua(0f, f8, 65, 97, 6b, 09, 4d, 22), + be64_to_cpua(5e, f9, 88, f3, d2, 32, 90, 57), + be64_to_cpua(26, 0d, 55, cd, 23, 1e, 7d, a0), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 3a) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha256) */ + "\x04\x01\x05\x3a\x6b\x3b\x5a\x0f\xa7\xb9\xb7\x32\x53\x4e\xe2\xae" + "\x0a\x52\xc5\xda\xdd\x5a\x79\x1c\x30\x2d\x33\x07\x79\xd5\x70\x14" + "\x61\x0c\xec\x26\x4d\xd8\x35\x57\x04\x1d\x88\x33\x4d\xce\x05\x36" + "\xa5\xaf\x56\x84\xfa\x0b\x9e\xff\x7b\x30\x4b\x92\x1d\x06\xf8\x81" + "\x24\x1e\x51\x00\x09\x21\x51\xf7\x46\x0a\x77\xdb\xb5\x0c\xe7\x9c" + "\xff\x27\x3c\x02\x71\xd7\x85\x36\xf1\xaa\x11\x59\xd8\xb8\xdc\x09" + "\xdc\x6d\x5a\x6f\x63\x07\x6c\xe1\xe5\x4d\x6e\x0f\x6e\xfb\x7c\x05" + "\x8a\xe9\x53\xa8\xcf\xce\x43\x0e\x82\x20\x86\xbc\x88\x9c\xb7\xe3" + "\xe6\x77\x1e\x1f\x8a", + .key_len = 133, + .m = + "\xcc\x97\x73\x0c\x73\xa2\x53\x2b\xfa\xd7\x83\x1d\x0c\x72\x1b\x39" + "\x80\x71\x8d\xdd\xc5\x9b\xff\x55\x32\x98\x25\xa2\x58\x2e\xb7\x73", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(de, 7e, d7, 59, 10, e9, d9, d5), + be64_to_cpua(38, 1f, 46, 0b, 04, 64, 34, 79), + be64_to_cpua(ae, ce, 54, 76, 9a, c2, 8f, b8), + be64_to_cpua(95, 35, 6f, 02, 0e, af, e1, 4c), + be64_to_cpua(56, 3c, f6, f0, d8, e1, b7, 5d), + be64_to_cpua(50, 9f, 7d, 1f, ca, 8b, a8, 2d), + be64_to_cpua(06, 0f, fd, 83, fc, 0e, d9, ce), + be64_to_cpua(a5, 5f, 57, 52, 27, 78, 3a, b5), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, cd), + be64_to_cpua(55, 38, b6, f6, 34, 65, c7, bd), + be64_to_cpua(1c, 57, 56, 8f, 12, b7, 1d, 91), + be64_to_cpua(03, 42, 02, 5f, 50, f0, a2, 0d), + be64_to_cpua(fa, 10, dd, 9b, fb, 36, 1a, 31), + be64_to_cpua(e0, 87, 2c, 44, 4b, 5a, ee, af), + be64_to_cpua(a9, 79, 24, b9, 37, 35, dd, a0), + be64_to_cpua(6b, 35, ae, 65, b5, 99, 12, 0a), + be64_to_cpua(50, 85, 38, f9, 15, 83, 18, 04), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, cf) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha384) */ + "\x04\x00\x2e\xd6\x21\x04\x75\xc3\xdc\x7d\xff\x0e\xf3\x70\x25\x2b" + "\xad\x72\xfc\x5a\x91\xf1\xd5\x9c\x64\xf3\x1f\x47\x11\x10\x62\x33" + "\xfd\x2e\xe8\x32\xca\x9e\x6f\x0a\x4c\x5b\x35\x9a\x46\xc5\xe7\xd4" + "\x38\xda\xb2\xf0\xf4\x87\xf3\x86\xf4\xea\x70\xad\x1e\xd4\x78\x8c" + "\x36\x18\x17\x00\xa2\xa0\x34\x1b\x2e\x6a\xdf\x06\xd6\x99\x2d\x47" + "\x50\x92\x1a\x8a\x72\x9c\x23\x44\xfa\xa7\xa9\xed\xa6\xef\x26\x14" + "\xb3\x9d\xfe\x5e\xa3\x8c\xd8\x29\xf8\xdf\xad\xa6\xab\xfc\xdd\x46" + "\x22\x6e\xd7\x35\xc7\x23\xb7\x13\xae\xb6\x34\xff\xd7\x80\xe5\x39" + "\xb3\x3b\x5b\x1b\x94", + .key_len = 133, + .m = + "\x36\x98\xd6\x82\xfa\xad\xed\x3c\xb9\x40\xb6\x4d\x9e\xb7\x04\x26" + "\xad\x72\x34\x44\xd2\x81\xb4\x9b\xbe\x01\x04\x7a\xd8\x50\xf8\x59" + "\xba\xad\x23\x85\x6b\x59\xbe\xfb\xf6\x86\xd4\x67\xa8\x43\x28\x76", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(b8, 6a, dd, fb, e6, 63, 4e, 28), + be64_to_cpua(84, 59, fd, 1a, c4, 40, dd, 43), + be64_to_cpua(32, 76, 06, d0, f9, c0, e4, e6), + be64_to_cpua(e4, df, 9b, 7d, 9e, 47, ca, 33), + be64_to_cpua(7e, 42, 71, 86, 57, 2d, f1, 7d), + be64_to_cpua(f2, 4b, 64, 98, f7, ec, da, c7), + be64_to_cpua(ec, 51, dc, e8, 35, 5e, ae, 16), + be64_to_cpua(96, 76, 3c, 27, ea, aa, 9c, 26), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 93), + be64_to_cpua(c6, 4f, ab, 2b, 62, c1, 42, b1), + be64_to_cpua(e5, 5a, 94, 56, cf, 8f, b4, 22), + be64_to_cpua(6a, c3, f3, 7a, d1, fa, e7, a7), + be64_to_cpua(df, c4, c0, db, 54, db, 8a, 0d), + be64_to_cpua(da, a7, cd, 26, 28, 76, 3b, 52), + be64_to_cpua(e4, 3c, bc, 93, 65, 57, 1c, 30), + be64_to_cpua(55, ce, 37, 97, c9, 05, 51, e5), + be64_to_cpua(c3, 6a, 87, 6e, b5, 13, 1f, 20), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, ff) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha512) */ + "\x04\x00\xc7\x65\xee\x0b\x86\x7d\x8f\x02\xf1\x74\x5b\xb0\x4c\x3f" + "\xa6\x35\x60\x9f\x55\x23\x11\xcc\xdf\xb8\x42\x99\xee\x6c\x96\x6a" + "\x27\xa2\x56\xb2\x2b\x03\xad\x0f\xe7\x97\xde\x09\x5d\xb4\xc5\x5f" + "\xbd\x87\x37\xbf\x5a\x16\x35\x56\x08\xfd\x6f\x06\x1a\x1c\x84\xee" + "\xc3\x64\xb3\x00\x9e\xbd\x6e\x60\x76\xee\x69\xfd\x3a\xb8\xcd\x7e" + "\x91\x68\x53\x57\x44\x13\x2e\x77\x09\x2a\xbe\x48\xbd\x91\xd8\xf6" + "\x21\x16\x53\x99\xd5\xf0\x40\xad\xa6\xf8\x58\x26\xb6\x9a\xf8\x77" + "\xfe\x3a\x05\x1a\xdb\xa9\x0f\xc0\x6c\x76\x30\x8c\xd8\xde\x44\xae" + "\xd0\x17\xdf\x49\x6a", + .key_len = 133, + .m = + "\x5c\xa6\xbc\x79\xb8\xa0\x1e\x11\x83\xf7\xe9\x05\xdf\xba\xf7\x69" + "\x97\x22\x32\xe4\x94\x7c\x65\xbd\x74\xc6\x9a\x8b\xbd\x0d\xdc\xed" + "\xf5\x9c\xeb\xe1\xc5\x68\x40\xf2\xc7\x04\xde\x9e\x0d\x76\xc5\xa3" + "\xf9\x3c\x6c\x98\x08\x31\xbd\x39\xe8\x42\x7f\x80\x39\x6f\xfe\x68", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(28, b5, 04, b0, b6, 33, 1c, 7e), + be64_to_cpua(80, a6, 13, fc, b6, 90, f7, bb), + be64_to_cpua(27, 93, e8, 6c, 49, 7d, 28, fc), + be64_to_cpua(1f, 12, 3e, b7, 7e, 51, ff, 7f), + be64_to_cpua(fb, 62, 1e, 42, 03, 6c, 74, 8a), + be64_to_cpua(63, 0e, 02, cc, 94, a9, 05, b9), + be64_to_cpua(aa, 86, ec, a8, 05, 03, 52, 56), + be64_to_cpua(71, 86, 96, ac, 21, 33, 7e, 4e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, 5c), + be64_to_cpua(46, 1e, 77, 44, 78, e0, d1, 04), + be64_to_cpua(72, 74, 13, 63, 39, a6, e5, 25), + be64_to_cpua(00, 55, bb, 6a, b4, 73, 00, d2), + be64_to_cpua(71, d0, e9, ca, a7, c0, cb, aa), + be64_to_cpua(7a, 76, 37, 51, 47, 49, 98, 12), + be64_to_cpua(88, 05, 3e, 43, 39, 01, bd, b7), + be64_to_cpua(95, 35, 89, 4f, 41, 5f, 9e, 19), + be64_to_cpua(43, 52, 1d, e3, c6, bd, 5a, 40), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, 70) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +/* + * ECDSA X9.62 test vectors. + * + * Identical to ECDSA test vectors, except signature in "c" is X9.62 encoded. + */ +static const struct sig_testvec x962_ecdsa_nist_p192_tv_template[] = { + { + .key = /* secp192r1(sha1) */ "\x04\xf7\x46\xf8\x2f\x15\xf6\x22\x8e\xd7\x57\x4f\xcc\xe7\xbb\xc1" "\xd4\x09\x73\xcf\xea\xd0\x15\x07\x3d\xa5\x8a\x8a\x95\x43\xe4\x68" "\xea\xc6\x25\xc1\xc1\x01\x25\x4c\x7e\xc3\x3c\xa6\x04\x0a\xe7\x08" "\x98", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\xcd\xb9\xd2\x1c\xb7\x6f\xcd\x44\xb3\xfd\x63\xea\xa3\x66\x7f\xae" "\x63\x85\xe7\x82", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x35\x02\x19\x00\xba\xe5\x93\x83\x6e\xb6\x3b\x63\xa0\x27\x91" "\xc6\xf6\x7f\xc3\x09\xad\x59\xad\x88\x27\xd6\x92\x6b\x02\x18\x10" @@ -674,23 +1371,17 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x80\x6f\xa5\x79\x77\xda\xd0", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha224) */ "\x04\xb6\x4b\xb1\xd1\xac\xba\x24\x8f\x65\xb2\x60\x00\x90\xbf\xbd" "\x78\x05\x73\xe9\x79\x1d\x6f\x7c\x0b\xd2\xc3\x93\xa7\x28\xe1\x75" "\xf7\xd5\x95\x1d\x28\x10\xc0\x75\x50\x5c\x1a\x4f\x3f\x8f\xa5\xee" "\xa3", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x8d\xd6\xb8\x3e\xe5\xff\x23\xf6\x25\xa2\x43\x42\x74\x45\xa7\x40" "\x3a\xff\x2f\xe1\xd3\xf6\x9f\xe8\x33\xcb\x12\x11", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x34\x02\x18\x5a\x8b\x82\x69\x7e\x8a\x0a\x09\x14\xf8\x11\x2b" "\x55\xdc\xae\x37\x83\x7b\x12\xe6\xb6\x5b\xcb\xd4\x02\x18\x6a\x14" @@ -698,23 +1389,17 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x5c\x99\xdb\x92\x5b\x36", .c_size = 54, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha256) */ "\x04\xe2\x51\x24\x9b\xf7\xb6\x32\x82\x39\x66\x3d\x5b\xec\x3b\xae" "\x0c\xd5\xf2\x67\xd1\xc7\xe1\x02\xe4\xbf\x90\x62\xb8\x55\x75\x56" "\x69\x20\x5e\xcb\x4e\xca\x33\xd6\xcb\x62\x6b\x94\xa9\xa2\xe9\x58" "\x91", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x35\xec\xa1\xa0\x9e\x14\xde\x33\x03\xb6\xf6\xbd\x0c\x2f\xb2\xfd" "\x1f\x27\x82\xa5\xd7\x70\x3f\xef\xa0\x82\x69\x8e\x73\x31\x8e\xd7", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x35\x02\x18\x3f\x72\x3f\x1f\x42\xd2\x3f\x1d\x6b\x1a\x58\x56" "\xf1\x8f\xf7\xfd\x01\x48\xfb\x5f\x72\x2a\xd4\x8f\x02\x19\x00\xb3" @@ -722,24 +1407,18 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x3a\x97\xd9\xcd\x1a\x6a\x49", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha384) */ "\x04\x5a\x13\xfe\x68\x86\x4d\xf4\x17\xc7\xa4\xe5\x8c\x65\x57\xb7" "\x03\x73\x26\x57\xfb\xe5\x58\x40\xd8\xfd\x49\x05\xab\xf1\x66\x1f" "\xe2\x9d\x93\x9e\xc2\x22\x5a\x8b\x4f\xf3\x77\x22\x59\x7e\xa6\x4e" "\x8b", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x9d\x2e\x1a\x8f\xed\x6c\x4b\x61\xae\xac\xd5\x19\x79\xce\x67\xf9" "\xa0\x34\xeb\xb0\x81\xf9\xd9\xdc\x6e\xb3\x5c\xa8\x69\xfc\x8a\x61" "\x39\x81\xfb\xfd\x5c\x30\x6b\xa8\xee\xed\x89\xaf\xa3\x05\xe4\x78", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x35\x02\x19\x00\xf0\xa3\x38\xce\x2b\xf8\x9d\x1a\xcf\x7f\x34" "\xb4\xb4\xe5\xc5\x00\xdd\x15\xbb\xd6\x8c\xa7\x03\x78\x02\x18\x64" @@ -747,25 +1426,19 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x12\x3b\x3b\x28\xfb\x6d\xe1", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha512) */ "\x04\xd5\xf2\x6e\xc3\x94\x5c\x52\xbc\xdf\x86\x6c\x14\xd1\xca\xea" "\xcc\x72\x3a\x8a\xf6\x7a\x3a\x56\x36\x3b\xca\xc6\x94\x0e\x17\x1d" "\x9e\xa0\x58\x28\xf9\x4b\xe6\xd1\xa5\x44\x91\x35\x0d\xe7\xf5\x11" "\x57", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\xd5\x4b\xe9\x36\xda\xd8\x6e\xc0\x50\x03\xbe\x00\x43\xff\xf0\x23" "\xac\xa2\x42\xe7\x37\x77\x79\x52\x8f\x3e\xc0\x16\xc1\xfc\x8c\x67" "\x16\xbc\x8a\x5d\x3b\xd3\x13\xbb\xb6\xc0\x26\x1b\xeb\x33\xcc\x70" "\x4a\xf2\x11\x37\xe8\x1b\xba\x55\xac\x69\xe1\x74\x62\x7c\x6e\xb5", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x35\x02\x19\x00\x88\x5b\x8f\x59\x43\xbf\xcf\xc6\xdd\x3f\x07" "\x87\x12\xa0\xd4\xac\x2b\x11\x2d\x1c\xb6\x06\xc9\x6c\x02\x18\x73" @@ -773,28 +1446,22 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x6a\xdf\x97\xfd\x82\x76\x24", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p256_tv_template[] = { { - .key = + .key = /* secp256r1(sha1) */ "\x04\xb9\x7b\xbb\xd7\x17\x64\xd2\x7e\xfc\x81\x5d\x87\x06\x83\x41" "\x22\xd6\x9a\xaa\x87\x17\xec\x4f\x63\x55\x2f\x94\xba\xdd\x83\xe9" "\x34\x4b\xf3\xe9\x91\x13\x50\xb6\xcb\xca\x62\x08\xe7\x3b\x09\xdc" "\xc3\x63\x4b\x2d\xb9\x73\x53\xe4\x45\xe6\x7c\xad\xe7\x6b\xb0\xe8" "\xaf", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\xc2\x2b\x5f\x91\x78\x34\x26\x09\x42\x8d\x6f\x51\xb2\xc5\xaf\x4c" "\x0b\xde\x6a\x42", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x46\x02\x21\x00\xf9\x25\xce\x9f\x3a\xa6\x35\x81\xcf\xd4\xe7" "\xb7\xf0\x82\x56\x41\xf7\xd4\xad\x8d\x94\x5a\x69\x89\xee\xca\x6a" @@ -803,24 +1470,18 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\xfb\x9d\x8b\xde\xd4\x8d\x6f\xad", .c_size = 72, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha224) */ "\x04\x8b\x6d\xc0\x33\x8e\x2d\x8b\x67\xf5\xeb\xc4\x7f\xa0\xf5\xd9" "\x7b\x03\xa5\x78\x9a\xb5\xea\x14\xe4\x23\xd0\xaf\xd7\x0e\x2e\xa0" "\xc9\x8b\xdb\x95\xf8\xb3\xaf\xac\x00\x2c\x2c\x1f\x7a\xfd\x95\x88" "\x43\x13\xbf\xf3\x1c\x05\x1a\x14\x18\x09\x3f\xd6\x28\x3e\xc5\xa0" "\xd4", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x1a\x15\xbc\xa3\xe4\xed\x3a\xb8\x23\x67\xc6\xc4\x34\xf8\x6c\x41" "\x04\x0b\xda\xc5\x77\xfa\x1c\x2d\xe6\x2c\x3b\xe0", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x44\x02\x20\x20\x43\xfa\xc0\x9f\x9d\x7b\xe7\xae\xce\x77\x59" "\x1a\xdb\x59\xd5\x34\x62\x79\xcb\x6a\x91\x67\x2e\x7d\x25\xd8\x25" @@ -829,24 +1490,18 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x2e\x8b\xde\x5a\x04\x0e", .c_size = 70, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha256) */ "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" "\xb8", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x45\x02\x20\x08\x31\xfa\x74\x0d\x1d\x21\x5d\x09\xdc\x29\x63" "\xa8\x1a\xad\xfc\xac\x44\xc3\xe8\x24\x11\x2d\xa4\x91\xdc\x02\x67" @@ -855,25 +1510,19 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x2a\x65\x35\x23\xe3\x1d\xfa", .c_size = 71, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha384) */ "\x04\xc5\xc6\xea\x60\xc9\xce\xad\x02\x8d\xf5\x3e\x24\xe3\x52\x1d" "\x28\x47\x3b\xc3\x6b\xa4\x99\x35\x99\x11\x88\x88\xc8\xf4\xee\x7e" "\x8c\x33\x8f\x41\x03\x24\x46\x2b\x1a\x82\xf9\x9f\xe1\x97\x1b\x00" "\xda\x3b\x24\x41\xf7\x66\x33\x58\x3d\x3a\x81\xad\xcf\x16\xe9\xe2" "\x7c", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x3e\x78\x70\xfb\xcd\x66\xba\x91\xa1\x79\xff\x1e\x1c\x6b\x78\xe6" "\xc0\x81\x3a\x65\x97\x14\x84\x36\x14\x1a\x9a\xb7\xc5\xab\x84\x94" "\x5e\xbb\x1b\x34\x71\xcb\x41\xe1\xf6\xfc\x92\x7b\x34\xbb\x86\xbb", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x46\x02\x21\x00\x8e\xf3\x6f\xdc\xf8\x69\xa6\x2e\xd0\x2e\x95" "\x54\xd1\x95\x64\x93\x08\xb2\x6b\x24\x94\x48\x46\x5e\xf2\xe4\x6c" @@ -882,26 +1531,20 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\xc0\x60\x11\x92\xdc\x17\x89\x12", .c_size = 72, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha512) */ "\x04\xd7\x27\x46\x49\xf6\x26\x85\x12\x40\x76\x8e\xe2\xe6\x2a\x7a" "\x83\xb1\x4e\x7a\xeb\x3b\x5c\x67\x4a\xb5\xa4\x92\x8c\x69\xff\x38" "\xee\xd9\x4e\x13\x29\x59\xad\xde\x6b\xbb\x45\x31\xee\xfd\xd1\x1b" "\x64\xd3\xb5\xfc\xaf\x9b\x4b\x88\x3b\x0e\xb7\xd6\xdf\xf1\xd5\x92" "\xbf", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x57\xb7\x9e\xe9\x05\x0a\x8c\x1b\xc9\x13\xe5\x4a\x24\xc7\xe2\xe9" "\x43\xc3\xd1\x76\x62\xf4\x98\x1a\x9c\x13\xb0\x20\x1b\xe5\x39\xca" "\x4f\xd9\x85\x34\x95\xa2\x31\xbc\xbb\xde\xdd\x76\xbb\x61\xe3\xcf" "\x9d\xc0\x49\x7a\xf3\x7a\xc4\x7d\xa8\x04\x4b\x8d\xb4\x4d\x5b\xd6", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x45\x02\x21\x00\xb8\x6d\x87\x81\x43\xdf\xfb\x9f\x40\xea\x44" "\x81\x00\x4e\x29\x08\xed\x8c\x73\x30\x6c\x22\xb3\x97\x76\xf6\x04" @@ -910,11 +1553,10 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x31\x79\x4a\xe9\x81\x6a\xee", .c_size = 71, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p384_tv_template[] = { { .key = /* secp384r1(sha1) */ "\x04\x89\x25\xf3\x97\x88\xcb\xb0\x78\xc5\x72\x9a\x14\x6e\x7a\xb1" @@ -925,15 +1567,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x0b\x25\xd6\x80\x5c\x3b\xe6\x1a\x98\x48\x91\x45\x7a\x73\xb0\xc3" "\xf1", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x12\x55\x28\xf0\x77\xd5\xb6\x21\x71\x32\x48\xcd\x28\xa8\x25\x22" "\x3a\x69\xc1\x93", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x66\x02\x31\x00\xf5\x0f\x24\x4c\x07\x93\x6f\x21\x57\x55\x07" "\x20\x43\x30\xde\xa0\x8d\x26\x8e\xae\x63\x3f\xbc\x20\x3a\xc6\xf1" @@ -944,7 +1581,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x79\x12\x2a\xb7\xc5\x15\x92\xc5", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha224) */ "\x04\x69\x6c\xcf\x62\xee\xd0\x0d\xe5\xb5\x2f\x70\x54\xcf\x26\xa0" @@ -955,15 +1591,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x6b\x93\x99\x6c\x66\x4c\x42\x3f\x65\x60\x6c\x1c\x0b\x93\x9b\x9d" "\xe0", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x12\x80\xb6\xeb\x25\xe2\x3d\xf0\x21\x32\x96\x17\x3a\x38\x39\xfd" "\x1f\x05\x34\x7b\xb8\xf9\x71\x66\x03\x4f\xd5\xe5", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x66\x02\x31\x00\x8a\x51\x84\xce\x13\x1e\xd2\xdc\xec\xcb\xe4" "\x89\x47\xb2\xf7\xbc\x97\xf1\xc8\x72\x26\xcf\x5a\x5e\xc5\xda\xb4" @@ -974,7 +1605,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x88\x2b\x82\x26\x5e\x1c\xda\xfb", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha256) */ "\x04\xee\xd6\xda\x3e\x94\x90\x00\x27\xed\xf8\x64\x55\xd6\x51\x9a" @@ -985,15 +1615,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x17\xc3\x34\x29\xd6\x40\xea\x5c\xb9\x3f\xfb\x32\x2e\x12\x33\xbc" "\xab", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\xaa\xe7\xfd\x03\x26\xcb\x94\x71\xe4\xce\x0f\xc5\xff\xa6\x29\xa3" "\xe1\xcc\x4c\x35\x4e\xde\xca\x80\xab\x26\x0c\x25\xe6\x68\x11\xc2", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x64\x02\x30\x08\x09\x12\x9d\x6e\x96\x64\xa6\x8e\x3f\x7e\xce" "\x0a\x9b\xaa\x59\xcc\x47\x53\x87\xbc\xbd\x83\x3f\xaf\x06\x3f\x84" @@ -1004,7 +1629,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xf4\x1f\x39\xca\x4d\x43", .c_size = 102, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha384) */ "\x04\x3a\x2f\x62\xe7\x1a\xcf\x24\xd0\x0b\x7c\xe0\xed\x46\x0a\x4f" @@ -1015,16 +1639,11 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x21\x67\xe5\x1b\x5a\x52\x31\x68\xd6\xee\xf0\x19\xb0\x55\xed\x89" "\x9e", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x8d\xf2\xc0\xe9\xa8\xf3\x8e\x44\xc4\x8c\x1a\xa0\xb8\xd7\x17\xdf" "\xf2\x37\x1b\xc6\xe3\xf5\x62\xcc\x68\xf5\xd5\x0b\xbf\x73\x2b\xb1" "\xb0\x4c\x04\x00\x31\xab\xfe\xc8\xd6\x09\xc8\xf2\xea\xd3\x28\xff", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x66\x02\x31\x00\x9b\x28\x68\xc0\xa1\xea\x8c\x50\xee\x2e\x62" "\x35\x46\xfa\x00\xd8\x2d\x7a\x91\x5f\x49\x2d\x22\x08\x29\xe6\xfb" @@ -1035,7 +1654,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xab\x8d\x4e\xde\xe6\x6d\x9b\x66", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha512) */ "\x04\xb4\xe7\xc1\xeb\x64\x25\x22\x46\xc3\x86\x61\x80\xbe\x1e\x46" @@ -1046,17 +1664,12 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xdf\x42\x5c\xc2\x5a\xc7\x0c\xf4\x15\xf7\x1b\xa3\x2e\xd7\x00\xac" "\xa3", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\xe8\xb7\x52\x7d\x1a\x44\x20\x05\x53\x6b\x3a\x68\xf2\xe7\x6c\xa1" "\xae\x9d\x84\xbb\xba\x52\x43\x3e\x2c\x42\x78\x49\xbf\x78\xb2\x71" "\xeb\xe1\xe0\xe8\x42\x7b\x11\xad\x2b\x99\x05\x1d\x36\xe6\xac\xfc" "\x55\x73\xf0\x15\x63\x39\xb8\x6a\x6a\xc5\x91\x5b\xca\x6a\xa8\x0e", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x63\x02\x2f\x1d\x20\x94\x77\xfe\x31\xfa\x4d\xc6\xef\xda\x02" "\xe7\x0f\x52\x9a\x02\xde\x93\xe8\x83\xe4\x84\x4c\xfc\x6f\x80\xe3" @@ -1067,11 +1680,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x3c\x93\xff\x50\x5d", .c_size = 101, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p521_tv_template[] = { { .key = /* secp521r1(sha224) */ "\x04\x01\x4f\x43\x18\xb6\xa9\xc9\x5d\x68\xd3\xa9\x42\xf8\x98\xc0" @@ -1084,15 +1696,10 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xed\x37\x0f\x99\x3f\x26\xba\xa3\x8e\xff\x79\x34\x7c\x3a\xfe\x1f" "\x3b\x83\x82\x2f\x14", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\xa2\x3a\x6a\x8c\x7b\x3c\xf2\x51\xf8\xbe\x5f\x4f\x3b\x15\x05\xc4" "\xb5\xbc\x19\xe7\x21\x85\xe9\x23\x06\x33\x62\xfb", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x81\x86\x02\x41\x01\xd6\x43\xe7\xff\x42\xb2\xba\x74\x35\xf6" "\xdc\x6d\x02\x7b\x22\xac\xe2\xef\x07\x92\xee\x60\x94\x06\xf8\x3f" @@ -1105,7 +1712,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xa3\x50\xb1\xa5\x98\x92\x2a\xa5\x52", .c_size = 137, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha256) */ @@ -1119,15 +1725,10 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x8a\xe9\x53\xa8\xcf\xce\x43\x0e\x82\x20\x86\xbc\x88\x9c\xb7\xe3" "\xe6\x77\x1e\x1f\x8a", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\xcc\x97\x73\x0c\x73\xa2\x53\x2b\xfa\xd7\x83\x1d\x0c\x72\x1b\x39" "\x80\x71\x8d\xdd\xc5\x9b\xff\x55\x32\x98\x25\xa2\x58\x2e\xb7\x73", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x81\x88\x02\x42\x00\xcd\xa5\x5f\x57\x52\x27\x78\x3a\xb5\x06" "\x0f\xfd\x83\xfc\x0e\xd9\xce\x50\x9f\x7d\x1f\xca\x8b\xa8\x2d\x56" @@ -1140,7 +1741,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xb7\x1d\x91\x55\x38\xb6\xf6\x34\x65\xc7\xbd", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha384) */ @@ -1154,16 +1754,11 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x22\x6e\xd7\x35\xc7\x23\xb7\x13\xae\xb6\x34\xff\xd7\x80\xe5\x39" "\xb3\x3b\x5b\x1b\x94", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\x36\x98\xd6\x82\xfa\xad\xed\x3c\xb9\x40\xb6\x4d\x9e\xb7\x04\x26" "\xad\x72\x34\x44\xd2\x81\xb4\x9b\xbe\x01\x04\x7a\xd8\x50\xf8\x59" "\xba\xad\x23\x85\x6b\x59\xbe\xfb\xf6\x86\xd4\x67\xa8\x43\x28\x76", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x81\x88\x02\x42\x00\x93\x96\x76\x3c\x27\xea\xaa\x9c\x26\xec" "\x51\xdc\xe8\x35\x5e\xae\x16\xf2\x4b\x64\x98\xf7\xec\xda\xc7\x7e" @@ -1176,7 +1771,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x8f\xb4\x22\xc6\x4f\xab\x2b\x62\xc1\x42\xb1", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha512) */ @@ -1190,17 +1784,12 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xfe\x3a\x05\x1a\xdb\xa9\x0f\xc0\x6c\x76\x30\x8c\xd8\xde\x44\xae" "\xd0\x17\xdf\x49\x6a", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\x5c\xa6\xbc\x79\xb8\xa0\x1e\x11\x83\xf7\xe9\x05\xdf\xba\xf7\x69" "\x97\x22\x32\xe4\x94\x7c\x65\xbd\x74\xc6\x9a\x8b\xbd\x0d\xdc\xed" "\xf5\x9c\xeb\xe1\xc5\x68\x40\xf2\xc7\x04\xde\x9e\x0d\x76\xc5\xa3" "\xf9\x3c\x6c\x98\x08\x31\xbd\x39\xe8\x42\x7f\x80\x39\x6f\xfe\x68", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x81\x88\x02\x42\x01\x5c\x71\x86\x96\xac\x21\x33\x7e\x4e\xaa" "\x86\xec\xa8\x05\x03\x52\x56\x63\x0e\x02\xcc\x94\xa9\x05\xb9\xfb" @@ -1213,14 +1802,41 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xa6\xe5\x25\x46\x1e\x77\x44\x78\xe0\xd1\x04", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, + }, +}; + +/* + * ECDSA P1363 test vectors. + * + * Identical to ECDSA test vectors, except signature in "c" is P1363 encoded. + */ +static const struct sig_testvec p1363_ecdsa_nist_p256_tv_template[] = { + { + .key = /* secp256r1(sha256) */ + "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" + "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" + "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" + "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" + "\xb8", + .key_len = 65, + .m = + "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" + "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", + .m_size = 32, + .c = + "\x08\x31\xfa\x74\x0d\x1d\x21\x5d\x09\xdc\x29\x63\xa8\x1a\xad\xfc" + "\xac\x44\xc3\xe8\x24\x11\x2d\xa4\x91\xdc\x02\x67\xdc\x0c\xd0\x82" + "\xbd\xff\xce\xee\x42\xc3\x97\xff\xf9\xa9\x81\xac\x4a\x50\xd0\x91" + "\x0a\x6e\x1b\xc4\xaf\xe1\x83\xc3\x4f\x2a\x65\x35\x23\xe3\x1d\xfa", + .c_size = 64, + .public_key_vec = true, }, }; /* * EC-RDSA test vectors are generated by gost-engine. */ -static const struct akcipher_testvec ecrdsa_tv_template[] = { +static const struct sig_testvec ecrdsa_tv_template[] = { { .key = "\x04\x40\xd5\xa7\x77\xf9\x26\x2f\x8c\xbd\xcc\xe3\x1f\x01\x94\x05" @@ -1245,7 +1861,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x79\xd2\x76\x64\xa3\xbd\x66\x10\x79\x05\x5a\x06\x42\xec\xb9\xc9", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1271,7 +1886,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x11\x23\x4a\x70\x43\x52\x7a\x68\x11\x65\x45\x37\xbb\x25\xb7\x40", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1297,7 +1911,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x9f\x16\xc6\x1c\xb1\x3f\x84\x41\x69\xec\x34\xfd\xf1\xf9\xa3\x39", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1332,7 +1945,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\xa8\xf6\x80\x01\xb9\x27\xac\xd8\x45\x96\x66\xa1\xee\x48\x08\x3f", .m_size = 64, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1367,14 +1979,13 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x6d\xf4\xd2\x45\xc2\x83\xa0\x42\x95\x05\x9d\x89\x8e\x0a\xca\xcc", .m_size = 64, .public_key_vec = true, - .siggen_sigver_test = true, }, }; /* * 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 = "\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82" @@ -1486,7 +2097,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" "\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2", .c_size = 256, - .siggen_sigver_test = true, } }; diff --git a/drivers/crypto/aspeed/aspeed-acry.c b/drivers/crypto/aspeed/aspeed-acry.c index b4613bd4ad9643..7a1e153733e1b1 100644 --- a/drivers/crypto/aspeed/aspeed-acry.c +++ b/drivers/crypto/aspeed/aspeed-acry.c @@ -601,8 +601,6 @@ static struct aspeed_acry_alg aspeed_acry_akcipher_algs[] = { .akcipher.base = { .encrypt = aspeed_acry_rsa_enc, .decrypt = aspeed_acry_rsa_dec, - .sign = aspeed_acry_rsa_dec, - .verify = aspeed_acry_rsa_enc, .set_pub_key = aspeed_acry_rsa_set_pub_key, .set_priv_key = aspeed_acry_rsa_set_priv_key, .max_size = aspeed_acry_rsa_max_size, diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index c167dbd6c7d623..2a29102612108f 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -2006,8 +2006,6 @@ static void hpre_curve25519_exit_tfm(struct crypto_kpp *tfm) } static struct akcipher_alg rsa = { - .sign = hpre_rsa_dec, - .verify = hpre_rsa_enc, .encrypt = hpre_rsa_enc, .decrypt = hpre_rsa_dec, .set_pub_key = hpre_rsa_setpubkey, diff --git a/drivers/crypto/starfive/jh7110-rsa.c b/drivers/crypto/starfive/jh7110-rsa.c index a778c48460253f..d109c743f076d6 100644 --- a/drivers/crypto/starfive/jh7110-rsa.c +++ b/drivers/crypto/starfive/jh7110-rsa.c @@ -565,8 +565,6 @@ static void starfive_rsa_exit_tfm(struct crypto_akcipher *tfm) static struct akcipher_alg starfive_rsa = { .encrypt = starfive_rsa_enc, .decrypt = starfive_rsa_dec, - .sign = starfive_rsa_dec, - .verify = starfive_rsa_enc, .set_pub_key = starfive_rsa_set_pub_key, .set_priv_key = starfive_rsa_set_priv_key, .max_size = starfive_rsa_max_size, diff --git a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c index cb92b7fa99c6f8..6edcca0d8eb552 100644 --- a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c @@ -21,12 +21,11 @@ #include "virtio_crypto_common.h" struct virtio_crypto_rsa_ctx { - MPI n; + unsigned int keysize; }; struct virtio_crypto_akcipher_ctx { struct virtio_crypto *vcrypto; - struct crypto_akcipher *tfm; bool session_valid; __u64 session_id; union { @@ -36,8 +35,6 @@ struct virtio_crypto_akcipher_ctx { struct virtio_crypto_akcipher_request { struct virtio_crypto_request base; - struct virtio_crypto_akcipher_ctx *akcipher_ctx; - struct akcipher_request *akcipher_req; void *src_buf; void *dst_buf; uint32_t opcode; @@ -69,7 +66,9 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * { struct virtio_crypto_akcipher_request *vc_akcipher_req = container_of(vc_req, struct virtio_crypto_akcipher_request, base); - struct akcipher_request *akcipher_req; + struct akcipher_request *akcipher_req = + container_of((void *)vc_akcipher_req, struct akcipher_request, + __ctx); int error; switch (vc_req->status) { @@ -83,23 +82,15 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * case VIRTIO_CRYPTO_BADMSG: error = -EBADMSG; break; - - case VIRTIO_CRYPTO_KEY_REJECTED: - error = -EKEYREJECTED; - break; - default: error = -EIO; break; } - akcipher_req = vc_akcipher_req->akcipher_req; - if (vc_akcipher_req->opcode != VIRTIO_CRYPTO_AKCIPHER_VERIFY) { - /* actuall length maybe less than dst buffer */ - akcipher_req->dst_len = len - sizeof(vc_req->status); - sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst), - vc_akcipher_req->dst_buf, akcipher_req->dst_len); - } + /* actual length may be less than dst buffer */ + akcipher_req->dst_len = len - sizeof(vc_req->status); + sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst), + vc_akcipher_req->dst_buf, akcipher_req->dst_len); virtio_crypto_akcipher_finalize_req(vc_akcipher_req, akcipher_req, error); } @@ -220,7 +211,8 @@ static int virtio_crypto_alg_akcipher_close_session(struct virtio_crypto_akciphe static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request *vc_akcipher_req, struct akcipher_request *req, struct data_queue *data_vq) { - struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; + struct crypto_akcipher *atfm = crypto_akcipher_reqtfm(req); + struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(atfm); struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; struct virtio_crypto *vcrypto = ctx->vcrypto; struct virtio_crypto_op_data_req *req_data = vc_req->req_data; @@ -230,36 +222,27 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request int node = dev_to_node(&vcrypto->vdev->dev); unsigned long flags; int ret; - bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY; - unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len; /* out header */ sg_init_one(&outhdr_sg, req_data, sizeof(*req_data)); sgs[num_out++] = &outhdr_sg; /* src data */ - src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node); + src_buf = kcalloc_node(req->src_len, 1, GFP_KERNEL, node); if (!src_buf) return -ENOMEM; - if (verify) { - /* for verify operation, both src and dst data work as OUT direction */ - sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); - sg_init_one(&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; - } else { - sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); - sg_init_one(&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; + sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, req->src_len); + sg_init_one(&srcdata_sg, src_buf, req->src_len); + sgs[num_out++] = &srcdata_sg; - /* dst data */ - dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); - if (!dst_buf) - goto free_src; + /* dst data */ + dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); + if (!dst_buf) + goto free_src; - sg_init_one(&dstdata_sg, dst_buf, req->dst_len); - sgs[num_out + num_in++] = &dstdata_sg; - } + sg_init_one(&dstdata_sg, dst_buf, req->dst_len); + sgs[num_out + num_in++] = &dstdata_sg; vc_akcipher_req->src_buf = src_buf; vc_akcipher_req->dst_buf = dst_buf; @@ -289,7 +272,8 @@ static int virtio_crypto_rsa_do_req(struct crypto_engine *engine, void *vreq) struct akcipher_request *req = container_of(vreq, struct akcipher_request, base); struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req); struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; - struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; + struct crypto_akcipher *atfm = crypto_akcipher_reqtfm(req); + struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(atfm); struct virtio_crypto *vcrypto = ctx->vcrypto; struct data_queue *data_vq = vc_req->dataq; struct virtio_crypto_op_header *header; @@ -335,8 +319,6 @@ static int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback; - vc_akcipher_req->akcipher_ctx = ctx; - vc_akcipher_req->akcipher_req = req; vc_akcipher_req->opcode = opcode; return crypto_transfer_akcipher_request_to_engine(data_vq->engine, req); @@ -352,16 +334,6 @@ static int virtio_crypto_rsa_decrypt(struct akcipher_request *req) return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_DECRYPT); } -static int virtio_crypto_rsa_sign(struct akcipher_request *req) -{ - return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_SIGN); -} - -static int virtio_crypto_rsa_verify(struct akcipher_request *req) -{ - return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_VERIFY); -} - static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen, @@ -378,10 +350,7 @@ static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, int node = virtio_crypto_get_current_node(); uint32_t keytype; int ret; - - /* mpi_free will test n, just free it. */ - mpi_free(rsa_ctx->n); - rsa_ctx->n = NULL; + MPI n; if (private) { keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; @@ -394,10 +363,13 @@ static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, if (ret) return ret; - rsa_ctx->n = mpi_read_raw_data(rsa_key.n, rsa_key.n_sz); - if (!rsa_ctx->n) + n = mpi_read_raw_data(rsa_key.n, rsa_key.n_sz); + if (!n) return -ENOMEM; + rsa_ctx->keysize = mpi_get_size(n); + mpi_free(n); + if (!ctx->vcrypto) { vcrypto = virtcrypto_get_dev_node(node, VIRTIO_CRYPTO_SERVICE_AKCIPHER, VIRTIO_CRYPTO_AKCIPHER_RSA); @@ -468,15 +440,11 @@ static unsigned int virtio_crypto_rsa_max_size(struct crypto_akcipher *tfm) struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx; - return mpi_get_size(rsa_ctx->n); + return rsa_ctx->keysize; } static int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm) { - struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); - - ctx->tfm = tfm; - akcipher_set_reqsize(tfm, sizeof(struct virtio_crypto_akcipher_request)); @@ -486,12 +454,9 @@ static int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm) static void virtio_crypto_rsa_exit_tfm(struct crypto_akcipher *tfm) { struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); - struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx; virtio_crypto_alg_akcipher_close_session(ctx); virtcrypto_dev_put(ctx->vcrypto); - mpi_free(rsa_ctx->n); - rsa_ctx->n = NULL; } static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { @@ -524,16 +489,19 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { .algo.base = { .encrypt = virtio_crypto_rsa_encrypt, .decrypt = virtio_crypto_rsa_decrypt, - .sign = virtio_crypto_rsa_sign, - .verify = virtio_crypto_rsa_verify, + /* + * Must specify an arbitrary hash algorithm upon + * set_{pub,priv}_key (even though it's not used + * by encrypt/decrypt) because qemu checks for it. + */ .set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key, .set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key, .max_size = virtio_crypto_rsa_max_size, .init = virtio_crypto_rsa_init_tfm, .exit = virtio_crypto_rsa_exit_tfm, .base = { - .cra_name = "pkcs1pad(rsa,sha1)", - .cra_driver_name = "virtio-pkcs1-rsa-with-sha1", + .cra_name = "pkcs1pad(rsa)", + .cra_driver_name = "virtio-pkcs1-rsa", .cra_priority = 150, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx), diff --git a/drivers/crypto/virtio/virtio_crypto_mgr.c b/drivers/crypto/virtio/virtio_crypto_mgr.c index 70e778aac0f2c9..bddbd8ebfebe62 100644 --- a/drivers/crypto/virtio/virtio_crypto_mgr.c +++ b/drivers/crypto/virtio/virtio_crypto_mgr.c @@ -256,7 +256,7 @@ int virtcrypto_dev_start(struct virtio_crypto *vcrypto) * @vcrypto: Pointer to virtio crypto device. * * Function notifies all the registered services that the virtio crypto device - * is ready to be used. + * shall no longer be used. * To be used by virtio crypto device specific drivers. * * Return: void diff --git a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c index 23c41d87d835ff..1b3fb21a2a7de2 100644 --- a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c @@ -17,7 +17,6 @@ struct virtio_crypto_skcipher_ctx { struct virtio_crypto *vcrypto; - struct crypto_skcipher *tfm; struct virtio_crypto_sym_session_info enc_sess_info; struct virtio_crypto_sym_session_info dec_sess_info; @@ -28,8 +27,6 @@ struct virtio_crypto_sym_request { /* Cipher or aead */ uint32_t type; - struct virtio_crypto_skcipher_ctx *skcipher_ctx; - struct skcipher_request *skcipher_req; uint8_t *iv; /* Encryption? */ bool encrypt; @@ -57,7 +54,9 @@ static void virtio_crypto_dataq_sym_callback { struct virtio_crypto_sym_request *vc_sym_req = container_of(vc_req, struct virtio_crypto_sym_request, base); - struct skcipher_request *ablk_req; + struct skcipher_request *ablk_req = + container_of((void *)vc_sym_req, struct skcipher_request, + __ctx); int error; /* Finish the encrypt or decrypt process */ @@ -77,7 +76,6 @@ static void virtio_crypto_dataq_sym_callback error = -EIO; break; } - ablk_req = vc_sym_req->skcipher_req; virtio_crypto_skcipher_finalize_req(vc_sym_req, ablk_req, error); } @@ -325,7 +323,7 @@ __virtio_crypto_skcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, struct data_queue *data_vq) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct virtio_crypto_skcipher_ctx *ctx = vc_sym_req->skcipher_ctx; + struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); struct virtio_crypto_request *vc_req = &vc_sym_req->base; unsigned int ivsize = crypto_skcipher_ivsize(tfm); struct virtio_crypto *vcrypto = ctx->vcrypto; @@ -481,8 +479,6 @@ static int virtio_crypto_skcipher_encrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_ctx = ctx; - vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = true; return crypto_transfer_skcipher_request_to_engine(data_vq->engine, req); @@ -506,8 +502,6 @@ static int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_ctx = ctx; - vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = false; return crypto_transfer_skcipher_request_to_engine(data_vq->engine, req); @@ -515,10 +509,7 @@ static int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) static int virtio_crypto_skcipher_init(struct crypto_skcipher *tfm) { - struct virtio_crypto_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); - crypto_skcipher_set_reqsize(tfm, sizeof(struct virtio_crypto_sym_request)); - ctx->tfm = tfm; return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0d94e4a967d81d..f1c39a6477a5ed 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -121,6 +121,19 @@ config XEN_PCIDEV_FRONTEND config PCI_ATS bool +config PCI_CMA + bool "Component Measurement and Authentication (CMA-SPDM)" + select CRYPTO_ECDSA + select CRYPTO_RSA + select CRYPTO_SHA256 + select CRYPTO_SHA512 + select PCI_DOE + select SPDM + help + Authenticate devices on enumeration per PCIe r6.2 sec 6.31. + A PCI DOE mailbox is used as transport for DMTF SPDM based + authentication, measurement and secure channel establishment. + config PCI_DOE bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 374c5c06d92f9d..f2ffe7dc7b7212 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -37,6 +37,10 @@ obj-$(CONFIG_PCI_DOE) += doe.o obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o obj-$(CONFIG_PCI_NPEM) += npem.o +obj-$(CONFIG_PCI_CMA) += cma.o cma.asn1.o +$(obj)/cma.o: $(obj)/cma.asn1.h +$(obj)/cma.asn1.o: $(obj)/cma.asn1.c $(obj)/cma.asn1.h + # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/cma.asn1 b/drivers/pci/cma.asn1 new file mode 100644 index 00000000000000..da41421d408567 --- /dev/null +++ b/drivers/pci/cma.asn1 @@ -0,0 +1,41 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Component Measurement and Authentication (CMA-SPDM, PCIe r6.1 sec 6.31.3) +-- X.509 Subject Alternative Name (RFC 5280 sec 4.2.1.6) +-- +-- Copyright (C) 2008 IETF Trust and the persons identified as authors +-- of the code +-- +-- https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 +-- +-- The ASN.1 module in RFC 5280 appendix A.1 uses EXPLICIT TAGS whereas the one +-- in appendix A.2 uses IMPLICIT TAGS. The kernel's simplified asn1_compiler.c +-- always uses EXPLICIT TAGS, hence this ASN.1 module differs from RFC 5280 in +-- that it adds IMPLICIT to definitions from appendix A.2 (such as GeneralName) +-- and omits EXPLICIT in those definitions. + +SubjectAltName ::= GeneralNames + +GeneralNames ::= SEQUENCE OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] IMPLICIT OtherName, + rfc822Name [1] IMPLICIT IA5String, + dNSName [2] IMPLICIT IA5String, + x400Address [3] ANY, + directoryName [4] ANY, + ediPartyName [5] IMPLICIT EDIPartyName, + uniformResourceIdentifier [6] IMPLICIT IA5String, + iPAddress [7] IMPLICIT OCTET STRING, + registeredID [8] IMPLICIT OBJECT IDENTIFIER + } + +OtherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER ({ pci_cma_note_oid }), + value [0] ANY ({ pci_cma_note_san }) + } + +EDIPartyName ::= SEQUENCE { + nameAssigner [0] ANY OPTIONAL, + partyName [1] ANY + } diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c new file mode 100644 index 00000000000000..fc5bccaf32dbdf --- /dev/null +++ b/drivers/pci/cma.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Component Measurement and Authentication (CMA-SPDM, PCIe r6.2 sec 6.31) + * + * Copyright (C) 2021 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#define dev_fmt(fmt) "CMA: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "cma.asn1.h" +#include "pci.h" + +/* Keyring that userspace can poke certs into */ +static struct key *pci_cma_keyring; + +/* + * The spdm_requester.c library calls pci_cma_validate() to check requirements + * for Leaf Certificates per PCIe r6.1 sec 6.31.3. + * + * pci_cma_validate() parses the Subject Alternative Name using the ASN.1 + * module cma.asn1, which calls pci_cma_note_oid() and pci_cma_note_san() + * to compare an OtherName against the expected name. + * + * The expected name is constructed beforehand by pci_cma_construct_san(). + * + * PCIe r6.2 drops the Subject Alternative Name spec language, even though + * it continues to require "the leaf certificate to include the information + * typically used by system software for device driver binding". Use the + * Subject Alternative Name per PCIe r6.1 for lack of a replacement and + * because it is the de facto standard among existing products. + */ +#define CMA_NAME_MAX sizeof("Vendor=1234:Device=1234:CC=123456:" \ + "REV=12:SSVID=1234:SSID=1234:1234567890123456") + +struct pci_cma_x509_context { + struct pci_dev *pdev; + u8 slot; + enum OID last_oid; + char expected_name[CMA_NAME_MAX]; + unsigned int expected_len; + unsigned int found:1; +}; + +int pci_cma_note_oid(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct pci_cma_x509_context *ctx = context; + + ctx->last_oid = look_up_OID(value, vlen); + + return 0; +} + +int pci_cma_note_san(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct pci_cma_x509_context *ctx = context; + + /* These aren't the drOIDs we're looking for. */ + if (ctx->last_oid != OID_CMA) + return 0; + + if (tag != ASN1_UTF8STR || + vlen != ctx->expected_len || + memcmp(value, ctx->expected_name, vlen) != 0) { + pci_err(ctx->pdev, "Leaf certificate of slot %u " + "has invalid Subject Alternative Name\n", ctx->slot); + return -EINVAL; + } + + ctx->found = true; + + return 0; +} + +static unsigned int pci_cma_construct_san(struct pci_dev *pdev, char *name) +{ + unsigned int len; + u64 serial; + + len = snprintf(name, CMA_NAME_MAX, + "Vendor=%04hx:Device=%04hx:CC=%06x:REV=%02hhx", + pdev->vendor, pdev->device, pdev->class, pdev->revision); + + if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) + len += snprintf(name + len, CMA_NAME_MAX - len, + ":SSVID=%04hx:SSID=%04hx", + pdev->subsystem_vendor, pdev->subsystem_device); + + serial = pci_get_dsn(pdev); + if (serial) + len += snprintf(name + len, CMA_NAME_MAX - len, + ":%016llx", serial); + + return len; +} + +static int pci_cma_validate(struct device *dev, u8 slot, + struct x509_certificate *leaf_cert) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_cma_x509_context ctx; + int ret; + + if (!leaf_cert->raw_san) { + pci_err(pdev, "Leaf certificate of slot %u " + "has no Subject Alternative Name\n", slot); + return -EINVAL; + } + + ctx.pdev = pdev; + ctx.slot = slot; + ctx.found = false; + ctx.expected_len = pci_cma_construct_san(pdev, ctx.expected_name); + + ret = asn1_ber_decoder(&cma_decoder, &ctx, leaf_cert->raw_san, + leaf_cert->raw_san_size); + if (ret == -EBADMSG || ret == -EMSGSIZE) + pci_err(pdev, "Leaf certificate of slot %u " + "has malformed Subject Alternative Name\n", slot); + if (ret < 0) + return ret; + + if (!ctx.found) { + pci_err(pdev, "Leaf certificate of slot %u " + "has no OtherName with CMA OID\n", slot); + return -EINVAL; + } + + return 0; +} + +#define PCI_DOE_FEATURE_CMA 1 + +static ssize_t pci_doe_transport(void *priv, struct device *dev, + const void *request, size_t request_sz, + void *response, size_t response_sz) +{ + struct pci_doe_mb *doe = priv; + ssize_t rc; + + /* + * CMA-SPDM operation in non-D0 states is optional (PCIe r6.2 + * sec 6.31.3). The spec does not define a way to determine + * if it's supported, so resume to D0 unconditionally. + */ + rc = pm_runtime_resume_and_get(dev); + if (rc) + return rc; + + rc = pci_doe(doe, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_FEATURE_CMA, + request, request_sz, response, response_sz); + + pm_runtime_put(dev); + + return rc; +} + +void pci_cma_init(struct pci_dev *pdev) +{ + struct pci_doe_mb *doe; + + if (IS_ERR(pci_cma_keyring)) { + pdev->spdm_state = ERR_PTR(-ENOTTY); + return; + } + + if (!pci_is_pcie(pdev)) + return; + + doe = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG, + PCI_DOE_FEATURE_CMA); + if (!doe) + return; + + pdev->spdm_state = spdm_create(&pdev->dev, pci_doe_transport, doe, + PCI_DOE_MAX_PAYLOAD, pci_cma_keyring, + pci_cma_validate); + if (!pdev->spdm_state) { + pdev->spdm_state = ERR_PTR(-ENOTTY); + return; + } + + /* + * Keep spdm_state allocated even if initial authentication fails + * to allow for provisioning of certificates and reauthentication. + */ + spdm_authenticate(pdev->spdm_state); +} + +void pci_cma_publish(struct pci_dev *pdev) +{ + if (!IS_ERR_OR_NULL(pdev->spdm_state)) + spdm_publish_log(pdev->spdm_state); +} + +/** + * pci_cma_reauthenticate() - Perform CMA-SPDM authentication again + * @pdev: Device to reauthenticate + * + * Can be called by drivers after device identity has mutated, + * e.g. after downloading firmware to an FPGA device. + */ +void pci_cma_reauthenticate(struct pci_dev *pdev) +{ + if (IS_ERR_OR_NULL(pdev->spdm_state)) + return; + + if (test_bit(PCI_CMA_OWNED_BY_GUEST, &pdev->priv_flags)) + return; + + spdm_authenticate(pdev->spdm_state); +} + +#if IS_ENABLED(CONFIG_VFIO_PCI_CORE) +/** + * pci_cma_claim_ownership() - Claim exclusive CMA-SPDM control for guest VM + * @pdev: PCI device + * + * Claim exclusive CMA-SPDM control for a guest virtual machine before + * passthrough of @pdev. The host refrains from performing CMA-SPDM + * authentication of the device until passthrough has concluded. + * + * Necessary because the GET_VERSION request resets the SPDM connection + * and DOE r1.0 allows only a single SPDM connection for the entire system. + * So the host could reset the guest's SPDM connection behind the guest's back. + */ +void pci_cma_claim_ownership(struct pci_dev *pdev) +{ + set_bit(PCI_CMA_OWNED_BY_GUEST, &pdev->priv_flags); + + if (!IS_ERR_OR_NULL(pdev->spdm_state)) + spdm_await(pdev->spdm_state); +} +EXPORT_SYMBOL(pci_cma_claim_ownership); + +/** + * pci_cma_return_ownership() - Relinquish CMA-SPDM control to the host + * @pdev: PCI device + * + * Relinquish CMA-SPDM control to the host after passthrough of @pdev to a + * guest virtual machine has concluded. + */ +void pci_cma_return_ownership(struct pci_dev *pdev) +{ + clear_bit(PCI_CMA_OWNED_BY_GUEST, &pdev->priv_flags); + + pci_cma_reauthenticate(pdev); +} +EXPORT_SYMBOL(pci_cma_return_ownership); +#endif + +void pci_cma_destroy(struct pci_dev *pdev) +{ + if (IS_ERR_OR_NULL(pdev->spdm_state)) + return; + + spdm_destroy(pdev->spdm_state); +} + +__init static int pci_cma_keyring_init(void) +{ + pci_cma_keyring = keyring_alloc(".cma", KUIDT_INIT(0), KGIDT_INIT(0), + current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | + KEY_USR_WRITE | KEY_USR_SEARCH, + KEY_ALLOC_NOT_IN_QUOTA | + KEY_ALLOC_SET_KEEP, NULL, NULL); + if (IS_ERR(pci_cma_keyring)) { + pr_err("PCI: Could not allocate .cma keyring\n"); + return PTR_ERR(pci_cma_keyring); + } + + return 0; +} +arch_initcall(pci_cma_keyring_init); diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 652d63df9d22e5..0f94c4ed719eca 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -31,9 +31,6 @@ #define PCI_DOE_FLAG_CANCEL 0 #define PCI_DOE_FLAG_DEAD 1 -/* Max data object length is 2^18 dwords */ -#define PCI_DOE_MAX_LENGTH (1 << 18) - /** * struct pci_doe_mb - State for a single DOE mailbox * @@ -697,6 +694,7 @@ void pci_doe_init(struct pci_dev *pdev) if (IS_ERR(doe_mb)) { pci_err(pdev, "[%x] failed to create mailbox: %ld\n", offset, PTR_ERR(doe_mb)); + pci_cma_disable(pdev); continue; } @@ -705,6 +703,7 @@ void pci_doe_init(struct pci_dev *pdev) pci_err(pdev, "[%x] failed to insert mailbox: %d\n", offset, rc); pci_doe_destroy_mb(doe_mb); + pci_cma_disable(pdev); } } } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 35270172c83318..107af140907cfc 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -566,6 +566,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) pci_pm_power_up_and_verify_state(pci_dev); pci_restore_state(pci_dev); pci_pme_restore(pci_dev); + pci_cma_reauthenticate(pci_dev); } static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5d0f4db1cab786..eab317954666c6 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1666,6 +1666,11 @@ const struct attribute_group *pci_dev_attr_groups[] = { #endif #ifdef CONFIG_PCIEASPM &aspm_ctrl_attr_group, +#endif +#ifdef CONFIG_PCI_CMA + &spdm_attr_group, + &spdm_certificates_group, + &spdm_signatures_group, #endif NULL, }; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7d85c04fbba2ae..c2c456cd4a2154 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5076,8 +5076,16 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe) rc = pci_dev_reset_slot_function(dev, probe); if (rc != -ENOTTY) - return rc; - return pci_parent_bus_reset(dev, probe); + goto done; + + rc = pci_parent_bus_reset(dev, probe); + +done: + /* CMA-SPDM state is lost upon a Conventional Reset */ + if (!probe) + pci_cma_reauthenticate(dev); + + return rc; } static int cxl_reset_bus_function(struct pci_dev *dev, bool probe) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 14d00ce45bfa95..7b259da45323f0 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -416,6 +416,23 @@ static inline void pci_doe_destroy(struct pci_dev *pdev) { } static inline void pci_doe_disconnected(struct pci_dev *pdev) { } #endif +#ifdef CONFIG_PCI_CMA +void pci_cma_init(struct pci_dev *pdev); +void pci_cma_destroy(struct pci_dev *pdev); +void pci_cma_publish(struct pci_dev *pdev); +void pci_cma_reauthenticate(struct pci_dev *pdev); +static inline void pci_cma_disable(struct pci_dev *pdev) +{ + pdev->spdm_state = ERR_PTR(-ENOTTY); +} +#else +static inline void pci_cma_init(struct pci_dev *pdev) { } +static inline void pci_cma_destroy(struct pci_dev *pdev) { } +static inline void pci_cma_publish(struct pci_dev *pdev) { } +static inline void pci_cma_reauthenticate(struct pci_dev *pdev) { } +static inline void pci_cma_disable(struct pci_dev *pdev) { } +#endif + #ifdef CONFIG_PCI_NPEM void pci_npem_create(struct pci_dev *dev); void pci_npem_remove(struct pci_dev *dev); @@ -469,6 +486,7 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DEV_ADDED 0 #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 +#define PCI_CMA_OWNED_BY_GUEST 3 static inline void pci_dev_assign_added(struct pci_dev *dev, bool added) { diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 31090770fffcc9..0028582f05907f 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -133,6 +133,9 @@ static int report_slot_reset(struct pci_dev *dev, void *data) pci_ers_result_t vote, *result = data; const struct pci_error_handlers *err_handler; + /* CMA-SPDM state is lost upon a Conventional Reset */ + pci_cma_reauthenticate(dev); + device_lock(&dev->dev); pdrv = dev->driver; if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->slot_reset) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4f68414c308609..07244aab9f4d01 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2495,6 +2495,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_dpc_init(dev); /* Downstream Port Containment */ pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ + pci_cma_init(dev); /* Component Measurement & Auth */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); @@ -2591,6 +2592,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) ret = device_add(&dev->dev); WARN_ON(ret < 0); + pci_cma_publish(dev); pci_npem_create(dev); } diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index e4ce1145aa3ee0..387db9224cfa39 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -58,6 +58,7 @@ static void pci_destroy_dev(struct pci_dev *dev) list_del(&dev->bus_list); up_write(&pci_bus_sem); + pci_cma_destroy(dev); pci_doe_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 1ab58da9f38a6e..b15366d0a723ac 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -483,10 +483,12 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) if (ret) goto out_power; + pci_cma_claim_ownership(pdev); + /* If reset fails because of the device lock, fail this path entirely */ ret = pci_try_reset_function(pdev); if (ret == -EAGAIN) - goto out_disable_device; + goto out_cma_return; vdev->reset_works = !ret; pci_save_state(pdev); @@ -545,7 +547,8 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) out_free_state: kfree(vdev->pci_saved_state); vdev->pci_saved_state = NULL; -out_disable_device: +out_cma_return: + pci_cma_return_ownership(pdev); pci_disable_device(pdev); out_power: if (!disable_idle_d3) @@ -674,6 +677,8 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) vfio_pci_dev_set_try_reset(vdev->vdev.dev_set); + pci_cma_return_ownership(pdev); + /* Put the pm-runtime usage counter acquired during enable */ if (!disable_idle_d3) pm_runtime_put(&pdev->dev); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d1995e2d6c943a..9268232781b571 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -383,14 +383,14 @@ int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr } EXPORT_SYMBOL_GPL(sysfs_create_files); -/** - * sysfs_add_file_to_group - add an attribute file to a pre-existing group. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - * @group: group name. - */ -int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group) +static const struct bin_attribute *to_bin_attr(const struct attribute *attr) +{ + return container_of(attr, struct bin_attribute, attr); +} + +static int __sysfs_add_file_to_group(struct kobject *kobj, + const struct attribute *attr, + const char *group, bool is_bin_attr) { struct kernfs_node *parent; kuid_t uid; @@ -408,14 +408,49 @@ int sysfs_add_file_to_group(struct kobject *kobj, return -ENOENT; kobject_get_ownership(kobj, &uid, &gid); - error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid, - NULL); + if (is_bin_attr) + error = sysfs_add_bin_file_mode_ns(parent, to_bin_attr(attr), + attr->mode, uid, gid, NULL); + else + error = sysfs_add_file_mode_ns(parent, attr, + attr->mode, uid, gid, NULL); kernfs_put(parent); return error; } + +/** + * sysfs_add_file_to_group - add an attribute file to a pre-existing group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + * + * Returns 0 on success or error code on failure. + */ +int sysfs_add_file_to_group(struct kobject *kobj, + const struct attribute *attr, + const char *group) +{ + return __sysfs_add_file_to_group(kobj, attr, group, false); +} EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); +/** + * sysfs_add_bin_file_to_group - add bin_attribute file to pre-existing group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + * + * Returns 0 on success or error code on failure. + */ +int sysfs_add_bin_file_to_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group) +{ + return __sysfs_add_file_to_group(kobj, &attr->attr, group, true); +} +EXPORT_SYMBOL_GPL(sysfs_add_bin_file_to_group); + /** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. @@ -565,6 +600,20 @@ void sysfs_remove_file_from_group(struct kobject *kobj, } EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); +/** + * sysfs_remove_bin_file_from_group - remove bin_attribute file from group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + */ +void sysfs_remove_bin_file_from_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group) +{ + sysfs_remove_file_from_group(kobj, &attr->attr, group); +} +EXPORT_SYMBOL_GPL(sysfs_remove_bin_file_from_group); + /** * sysfs_create_bin_file - create binary file for object. * @kobj: object. diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index d22ad67a0f3291..0cb52c9b9e1902 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -445,6 +445,39 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, } EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); +/** + * sysfs_add_link_to_sibling_group - add a symlink to a sibling attribute group. + * @kobj: The kobject containing the groups. + * @link_grp: The name of the group in which to create the symlink. + * @link: The name of the symlink to create. + * @target_grp: The name of the target group. + * @target: The name of the target attribute. + * + * Returns 0 on success or error code on failure. + */ +int sysfs_add_link_to_sibling_group(struct kobject *kobj, + const char *link_grp, const char *link, + const char *target_grp, const char *target) +{ + struct kernfs_node *target_grp_kn __free(kernfs_put), + *target_kn __free(kernfs_put) = NULL, + *link_grp_kn __free(kernfs_put) = NULL; + + target_grp_kn = kernfs_find_and_get(kobj->sd, target_grp); + if (!target_grp_kn) + return -ENOENT; + + target_kn = kernfs_find_and_get(target_grp_kn, target); + if (!target_kn) + return -ENOENT; + + link_grp_kn = kernfs_find_and_get(kobj->sd, link_grp); + if (!link_grp_kn) + return -ENOENT; + + return PTR_ERR_OR_ZERO(kernfs_create_link(link_grp_kn, link, target_kn)); +} + /** * compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing * to a group or an attribute diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 18a10cad07aaaf..cdf7da74bf2f0b 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -12,24 +12,19 @@ #include /** - * struct akcipher_request - public key request + * struct akcipher_request - public key cipher request * * @base: Common attributes for async crypto requests * @src: Source data - * For verify op this is signature + digest, in that case - * total size of @src is @src_len + @dst_len. - * @dst: Destination data (Should be NULL for verify op) + * @dst: Destination data * @src_len: Size of the input buffer - * For verify op it's size of signature part of @src, this part - * is supposed to be operated by cipher. - * @dst_len: Size of @dst buffer (for all ops except verify). + * @dst_len: Size of @dst buffer * It needs to be at least as big as the expected result * depending on the operation. * After operation it will be updated with the actual size of the * result. * In case of error where the dst sgl size was insufficient, * it will be updated to the size required for the operation. - * For verify op this is size of digest part in @src. * @__ctx: Start of private context data */ struct akcipher_request { @@ -55,15 +50,8 @@ struct crypto_akcipher { }; /** - * struct akcipher_alg - generic public key algorithm + * struct akcipher_alg - generic public key cipher algorithm * - * @sign: Function performs a sign operation as defined by public key - * algorithm. In case of error, where the dst_len was insufficient, - * the req->dst_len will be updated to the size required for the - * operation - * @verify: Function performs a complete verify operation as defined by - * public key algorithm, returning verification status. Requires - * digest value as input parameter. * @encrypt: Function performs an encrypt operation as defined by public key * algorithm. In case of error, where the dst_len was insufficient, * the req->dst_len will be updated to the size required for the @@ -94,8 +82,6 @@ struct crypto_akcipher { * @base: Common crypto API algorithm data structure */ struct akcipher_alg { - int (*sign)(struct akcipher_request *req); - int (*verify)(struct akcipher_request *req); int (*encrypt)(struct akcipher_request *req); int (*decrypt)(struct akcipher_request *req); int (*set_pub_key)(struct crypto_akcipher *tfm, const void *key, @@ -110,9 +96,9 @@ struct akcipher_alg { }; /** - * DOC: Generic Public Key API + * DOC: Generic Public Key Cipher API * - * The Public Key API is used with the algorithms of type + * The Public Key Cipher API is used with the algorithms of type * CRYPTO_ALG_TYPE_AKCIPHER (listed as type "akcipher" in /proc/crypto) */ @@ -243,10 +229,9 @@ static inline void akcipher_request_set_callback(struct akcipher_request *req, * * @req: public key request * @src: ptr to input scatter list - * @dst: ptr to output scatter list or NULL for verify op + * @dst: ptr to output scatter list * @src_len: size of the src input scatter list to be processed - * @dst_len: size of the dst output scatter list or size of signature - * portion in @src for verify op + * @dst_len: size of the dst output scatter list */ static inline void akcipher_request_set_crypt(struct akcipher_request *req, struct scatterlist *src, @@ -347,44 +332,6 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, const void *src, unsigned int slen, void *dst, unsigned int dlen); -/** - * crypto_akcipher_sign() - Invoke public key sign operation - * - * Function invokes the specific public key sign operation for a given - * public key algorithm - * - * @req: asymmetric key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_sign(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - - return crypto_akcipher_alg(tfm)->sign(req); -} - -/** - * crypto_akcipher_verify() - Invoke public key signature verification - * - * Function invokes the specific public key signature verification operation - * for a given public key algorithm. - * - * @req: asymmetric key request - * - * Note: req->dst should be NULL, req->src should point to SG of size - * (req->src_size + req->dst_size), containing signature (of req->src_size - * length) with appended digest (of req->dst_size length). - * - * Return: zero on verification success; error code in case of error. - */ -static inline int crypto_akcipher_verify(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - - return crypto_akcipher_alg(tfm)->verify(req); -} - /** * crypto_akcipher_set_pub_key() - Invoke set public key operation * diff --git a/include/crypto/internal/akcipher.h b/include/crypto/internal/akcipher.h index a0fba4b2eccfa0..14ee62bc52b6cd 100644 --- a/include/crypto/internal/akcipher.h +++ b/include/crypto/internal/akcipher.h @@ -124,7 +124,7 @@ static inline struct akcipher_alg *crypto_spawn_akcipher_alg( /** * crypto_register_akcipher() -- Register public key algorithm * - * Function registers an implementation of a public key verify algorithm + * Function registers an implementation of a public key cipher algorithm * * @alg: algorithm definition * @@ -135,7 +135,7 @@ int crypto_register_akcipher(struct akcipher_alg *alg); /** * crypto_unregister_akcipher() -- Unregister public key algorithm * - * Function unregisters an implementation of a public key verify algorithm + * Function unregisters an implementation of a public key cipher algorithm * * @alg: algorithm definition */ diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h index 0717a53ae73223..71483e5305e1dc 100644 --- a/include/crypto/internal/ecc.h +++ b/include/crypto/internal/ecc.h @@ -42,6 +42,18 @@ #define ECC_POINT_INIT(x, y, ndigits) (struct ecc_point) { x, y, ndigits } +/* + * The integers r and s making up the signature are expected to be + * formatted as two consecutive u64 arrays of size ECC_MAX_BYTES. + * The bytes within each u64 digit are in native endianness, + * but the order of the u64 digits themselves is little endian. + * This format allows direct use by internal vli_*() functions. + */ +struct ecdsa_raw_sig { + u64 r[ECC_MAX_DIGITS]; + u64 s[ECC_MAX_DIGITS]; +}; + /** * ecc_swap_digits() - Copy ndigits from big endian array to native array * @in: Input array @@ -293,4 +305,6 @@ void ecc_point_mult_shamir(const struct ecc_point *result, const u64 *y, const struct ecc_point *q, const struct ecc_curve *curve); +extern struct crypto_template ecdsa_x962_tmpl; +extern struct crypto_template ecdsa_p1363_tmpl; #endif diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h index e870133f4b7751..071a1951b992c1 100644 --- a/include/crypto/internal/rsa.h +++ b/include/crypto/internal/rsa.h @@ -8,6 +8,7 @@ #ifndef _RSA_HELPER_ #define _RSA_HELPER_ #include +#include /** * rsa_key - RSA key structure @@ -53,5 +54,33 @@ int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key, int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len); +#define RSA_PUB (true) +#define RSA_PRIV (false) + +static inline int rsa_set_key(struct crypto_akcipher *child, + unsigned int *key_size, bool is_pubkey, + const void *key, unsigned int keylen) +{ + int err; + + *key_size = 0; + + if (is_pubkey) + err = crypto_akcipher_set_pub_key(child, key, keylen); + else + err = crypto_akcipher_set_priv_key(child, key, keylen); + if (err) + return err; + + /* Find out new modulus size from rsa implementation */ + err = crypto_akcipher_maxsize(child); + if (err > PAGE_SIZE) + return -ENOTSUPP; + + *key_size = err; + return 0; +} + extern struct crypto_template rsa_pkcs1pad_tmpl; +extern struct crypto_template rsassa_pkcs1_tmpl; #endif diff --git a/include/crypto/internal/sig.h b/include/crypto/internal/sig.h index 97cb26ef8115d2..b16648c1a986f5 100644 --- a/include/crypto/internal/sig.h +++ b/include/crypto/internal/sig.h @@ -10,8 +10,88 @@ #include #include +struct sig_instance { + void (*free)(struct sig_instance *inst); + union { + struct { + char head[offsetof(struct sig_alg, base)]; + struct crypto_instance base; + }; + struct sig_alg alg; + }; +}; + +struct crypto_sig_spawn { + struct crypto_spawn base; +}; + static inline void *crypto_sig_ctx(struct crypto_sig *tfm) { return crypto_tfm_ctx(&tfm->base); } + +/** + * crypto_register_sig() -- Register public key signature algorithm + * + * Function registers an implementation of a public key signature algorithm + * + * @alg: algorithm definition + * + * Return: zero on success; error code in case of error + */ +int crypto_register_sig(struct sig_alg *alg); + +/** + * crypto_unregister_sig() -- Unregister public key signature algorithm + * + * Function unregisters an implementation of a public key signature algorithm + * + * @alg: algorithm definition + */ +void crypto_unregister_sig(struct sig_alg *alg); + +int sig_register_instance(struct crypto_template *tmpl, + struct sig_instance *inst); + +static inline struct sig_instance *sig_instance(struct crypto_instance *inst) +{ + return container_of(&inst->alg, struct sig_instance, alg.base); +} + +static inline struct sig_instance *sig_alg_instance(struct crypto_sig *tfm) +{ + return sig_instance(crypto_tfm_alg_instance(&tfm->base)); +} + +static inline struct crypto_instance *sig_crypto_instance(struct sig_instance + *inst) +{ + return container_of(&inst->alg.base, struct crypto_instance, alg); +} + +static inline void *sig_instance_ctx(struct sig_instance *inst) +{ + return crypto_instance_ctx(sig_crypto_instance(inst)); +} + +int crypto_grab_sig(struct crypto_sig_spawn *spawn, + struct crypto_instance *inst, + const char *name, u32 type, u32 mask); + +static inline struct crypto_sig *crypto_spawn_sig(struct crypto_sig_spawn + *spawn) +{ + return crypto_spawn_tfm2(&spawn->base); +} + +static inline void crypto_drop_sig(struct crypto_sig_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct sig_alg *crypto_spawn_sig_alg(struct crypto_sig_spawn + *spawn) +{ + return container_of(spawn->base.alg, struct sig_alg, base); +} #endif diff --git a/include/crypto/sig.h b/include/crypto/sig.h index d25186bb2be31d..cff41ad93824c0 100644 --- a/include/crypto/sig.h +++ b/include/crypto/sig.h @@ -19,6 +19,56 @@ struct crypto_sig { struct crypto_tfm base; }; +/** + * struct sig_alg - generic public key signature algorithm + * + * @sign: Function performs a sign operation as defined by public key + * algorithm. Optional. + * @verify: Function performs a complete verify operation as defined by + * public key algorithm, returning verification status. Optional. + * @set_pub_key: Function invokes the algorithm specific set public key + * function, which knows how to decode and interpret + * the BER encoded public key and parameters. Mandatory. + * @set_priv_key: Function invokes the algorithm specific set private key + * function, which knows how to decode and interpret + * the BER encoded private key and parameters. Optional. + * @key_size: Function returns key size. Mandatory. + * @digest_size: Function returns maximum digest size. Optional. + * @max_size: Function returns maximum signature size. Optional. + * @init: Initialize the cryptographic transformation object. + * This function is used to initialize the cryptographic + * transformation object. This function is called only once at + * the instantiation time, right after the transformation context + * was allocated. In case the cryptographic hardware has some + * special requirements which need to be handled by software, this + * function shall check for the precise requirement of the + * transformation and put any software fallbacks in place. + * @exit: Deinitialize the cryptographic transformation object. This is a + * counterpart to @init, used to remove various changes set in + * @init. + * + * @base: Common crypto API algorithm data structure + */ +struct sig_alg { + int (*sign)(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); + int (*verify)(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); + int (*set_pub_key)(struct crypto_sig *tfm, + const void *key, unsigned int keylen); + int (*set_priv_key)(struct crypto_sig *tfm, + const void *key, unsigned int keylen); + unsigned int (*key_size)(struct crypto_sig *tfm); + unsigned int (*digest_size)(struct crypto_sig *tfm); + unsigned int (*max_size)(struct crypto_sig *tfm); + int (*init)(struct crypto_sig *tfm); + void (*exit)(struct crypto_sig *tfm); + + struct crypto_alg base; +}; + /** * DOC: Generic Public Key Signature API * @@ -47,6 +97,21 @@ static inline struct crypto_tfm *crypto_sig_tfm(struct crypto_sig *tfm) return &tfm->base; } +static inline struct crypto_sig *__crypto_sig_tfm(struct crypto_tfm *tfm) +{ + return container_of(tfm, struct crypto_sig, base); +} + +static inline struct sig_alg *__crypto_sig_alg(struct crypto_alg *alg) +{ + return container_of(alg, struct sig_alg, base); +} + +static inline struct sig_alg *crypto_sig_alg(struct crypto_sig *tfm) +{ + return __crypto_sig_alg(crypto_sig_tfm(tfm)->__crt_alg); +} + /** * crypto_free_sig() - free signature tfm handle * @@ -60,16 +125,55 @@ static inline void crypto_free_sig(struct crypto_sig *tfm) } /** - * crypto_sig_maxsize() - Get len for output buffer + * crypto_sig_keysize() - Get key size + * + * Function returns the key size in bytes. + * Function assumes that the key is already set in the transformation. If this + * function is called without a setkey or with a failed setkey, you may end up + * in a NULL dereference. + * + * @tfm: signature tfm handle allocated with crypto_alloc_sig() + */ +static inline unsigned int crypto_sig_keysize(struct crypto_sig *tfm) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->key_size(tfm); +} + +/** + * crypto_sig_digestsize() - Get maximum digest size + * + * Function returns the maximum digest size in bytes. + * Function assumes that the key is already set in the transformation. If this + * function is called without a setkey or with a failed setkey, you may end up + * in a NULL dereference. + * + * @tfm: signature tfm handle allocated with crypto_alloc_sig() + */ +static inline unsigned int crypto_sig_digestsize(struct crypto_sig *tfm) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->digest_size(tfm); +} + +/** + * crypto_sig_maxsize() - Get maximum signature size * - * Function returns the dest buffer size required for a given key. + * Function returns the maximum signature size in bytes. * Function assumes that the key is already set in the transformation. If this - * function is called without a setkey or with a failed setkey, you will end up + * function is called without a setkey or with a failed setkey, you may end up * in a NULL dereference. * * @tfm: signature tfm handle allocated with crypto_alloc_sig() */ -int crypto_sig_maxsize(struct crypto_sig *tfm); +static inline unsigned int crypto_sig_maxsize(struct crypto_sig *tfm) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->max_size(tfm); +} /** * crypto_sig_sign() - Invoke signing operation @@ -84,9 +188,14 @@ int crypto_sig_maxsize(struct crypto_sig *tfm); * * Return: zero on success; error code in case of error */ -int crypto_sig_sign(struct crypto_sig *tfm, - const void *src, unsigned int slen, - void *dst, unsigned int dlen); +static inline int crypto_sig_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->sign(tfm, src, slen, dst, dlen); +} /** * crypto_sig_verify() - Invoke signature verification @@ -102,9 +211,14 @@ int crypto_sig_sign(struct crypto_sig *tfm, * * Return: zero on verification success; error code in case of error. */ -int crypto_sig_verify(struct crypto_sig *tfm, - const void *src, unsigned int slen, - const void *digest, unsigned int dlen); +static inline int crypto_sig_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->verify(tfm, src, slen, digest, dlen); +} /** * crypto_sig_set_pubkey() - Invoke set public key operation @@ -119,8 +233,13 @@ int crypto_sig_verify(struct crypto_sig *tfm, * * Return: zero on success; error code in case of error */ -int crypto_sig_set_pubkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen); +static inline int crypto_sig_set_pubkey(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->set_pub_key(tfm, key, keylen); +} /** * crypto_sig_set_privkey() - Invoke set private key operation @@ -135,6 +254,11 @@ int crypto_sig_set_pubkey(struct crypto_sig *tfm, * * Return: zero on success; error code in case of error */ -int crypto_sig_set_privkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen); +static inline int crypto_sig_set_privkey(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct sig_alg *alg = crypto_sig_alg(tfm); + + return alg->set_priv_key(tfm, key, keylen); +} #endif diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index 69a13e1e5b2e5d..e2af07fec3c6fc 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -84,6 +84,8 @@ extern struct key *find_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *id_2, bool partial); +ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen); + int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size, const struct key *keyring); diff --git a/include/keys/x509-parser.h b/include/keys/x509-parser.h new file mode 100644 index 00000000000000..8e450befe3b937 --- /dev/null +++ b/include/keys/x509-parser.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* X.509 certificate parser + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifndef _KEYS_X509_PARSER_H +#define _KEYS_X509_PARSER_H + +#include +#include +#include +#include + +struct x509_certificate { + struct x509_certificate *next; + struct x509_certificate *signer; /* Certificate that signed this one */ + struct public_key *pub; /* Public key details */ + struct public_key_signature *sig; /* Signature parameters */ + char *issuer; /* Name of certificate issuer */ + char *subject; /* Name of certificate subject */ + struct asymmetric_key_id *id; /* Issuer + Serial number */ + struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ + time64_t valid_from; + 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; + const void *raw_issuer; /* Raw issuer name in ASN.1 */ + const void *raw_subject; /* Raw subject name in ASN.1 */ + unsigned raw_subject_size; + unsigned raw_skid_size; + const void *raw_skid; /* Raw subjectKeyId in ASN.1 */ + const void *raw_san; /* Raw subjectAltName in ASN.1 */ + unsigned raw_san_size; + unsigned index; + bool seen; /* Infinite recursion prevention */ + bool verified; + bool self_signed; /* T if self-signed (check unsupported_sig too) */ + bool unsupported_sig; /* T if signature uses unsupported crypto */ + bool blacklisted; +}; + +struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); +void x509_free_certificate(struct x509_certificate *cert); + +DEFINE_FREE(x509_free_certificate, struct x509_certificate *, + if (!IS_ERR(_T)) x509_free_certificate(_T)) + +#endif /* _KEYS_X509_PARSER_H */ diff --git a/include/linux/asn1_decoder.h b/include/linux/asn1_decoder.h index 83f9c6e1e5e960..b41bce82a19111 100644 --- a/include/linux/asn1_decoder.h +++ b/include/linux/asn1_decoder.h @@ -9,6 +9,7 @@ #define _LINUX_ASN1_DECODER_H #include +#include struct asn1_decoder; diff --git a/include/linux/asn1_encoder.h b/include/linux/asn1_encoder.h index 08cd0c2ad34f0e..d17484dffb745b 100644 --- a/include/linux/asn1_encoder.h +++ b/include/linux/asn1_encoder.h @@ -6,7 +6,6 @@ #include #include #include -#include #define asn1_oid_len(oid) (sizeof(oid)/sizeof(u32)) unsigned char * diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 87c79d076d6d73..d5726d070dba91 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -407,6 +407,8 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, void kernfs_get(struct kernfs_node *kn); void kernfs_put(struct kernfs_node *kn); +DEFINE_FREE(kernfs_put, struct kernfs_node *, if (_T) kernfs_put(_T)) + struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry); struct kernfs_root *kernfs_root_from_sb(struct super_block *sb); struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn); diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 6f9242259edc48..44679f0a3fd646 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -145,6 +145,9 @@ enum OID { OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */ OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */ + /* PCI */ + OID_CMA, /* 2.23.147 */ + OID__NR }; diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h index 1f14aed4354b8b..0d3d7656c4565f 100644 --- a/include/linux/pci-doe.h +++ b/include/linux/pci-doe.h @@ -15,6 +15,10 @@ struct pci_doe_mb; +/* Max data object length is 2^18 dwords (including 2 dwords for header) */ +#define PCI_DOE_MAX_LENGTH (1 << 18) +#define PCI_DOE_MAX_PAYLOAD ((PCI_DOE_MAX_LENGTH - 2) * sizeof(u32)) + struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor, u8 type); diff --git a/include/linux/pci.h b/include/linux/pci.h index 573b4c4c2be61f..9389a551f43b9a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -518,6 +519,9 @@ struct pci_dev { #ifdef CONFIG_PCI_DOE struct xarray doe_mbs; /* Data Object Exchange mailboxes */ #endif +#ifdef CONFIG_PCI_CMA + struct spdm_state *spdm_state; /* Security Protocol and Data Model */ +#endif #ifdef CONFIG_PCI_NPEM struct npem *npem; /* Native PCIe Enclosure Management */ #endif @@ -2426,6 +2430,14 @@ static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int res static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { } #endif +#ifdef CONFIG_PCI_CMA +void pci_cma_claim_ownership(struct pci_dev *pdev); +void pci_cma_return_ownership(struct pci_dev *pdev); +#else +static inline void pci_cma_claim_ownership(struct pci_dev *pdev) { } +static inline void pci_cma_return_ownership(struct pci_dev *pdev) { } +#endif + #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) void pci_hp_create_module_link(struct pci_slot *pci_slot); void pci_hp_remove_module_link(struct pci_slot *pci_slot); @@ -2673,6 +2685,18 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); #endif +#ifdef CONFIG_PCI_CMA +static inline struct spdm_state *pci_dev_to_spdm_state(struct pci_dev *pdev) +{ + return pdev->spdm_state; +} +#else +static inline struct spdm_state *pci_dev_to_spdm_state(struct pci_dev *pdev) +{ + return NULL; +} +#endif + #include #define pci_printk(level, pdev, fmt, arg...) \ diff --git a/include/linux/slab.h b/include/linux/slab.h index b35e2db7eb0ecc..0268ea7abf8b9f 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -448,6 +448,7 @@ void kfree_sensitive(const void *objp); size_t __ksize(const void *objp); 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 diff --git a/include/linux/spdm.h b/include/linux/spdm.h new file mode 100644 index 00000000000000..27c48ec23d8e5a --- /dev/null +++ b/include/linux/spdm.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Copyright (C) 2021-22 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#ifndef _SPDM_H_ +#define _SPDM_H_ + +#include + +struct key; +struct device; +struct spdm_state; +struct x509_certificate; + +typedef ssize_t (spdm_transport)(void *priv, struct device *dev, + const void *request, size_t request_sz, + void *response, size_t response_sz); + +typedef int (spdm_validate)(struct device *dev, u8 slot, + struct x509_certificate *leaf_cert); + +struct spdm_state *spdm_create(struct device *dev, spdm_transport *transport, + void *transport_priv, u32 transport_sz, + struct key *keyring, spdm_validate *validate); + +int spdm_authenticate(struct spdm_state *spdm_state); + +void spdm_await(struct spdm_state *spdm_state); + +void spdm_destroy(struct spdm_state *spdm_state); + +#ifdef CONFIG_SYSFS +extern const struct attribute_group spdm_attr_group; +extern const struct attribute_group spdm_certificates_group; +extern const struct attribute_group spdm_signatures_group; +void spdm_publish_log(struct spdm_state *spdm_state); +#else +static inline void spdm_publish_log(struct spdm_state *spdm_state) { } +#endif + +#endif diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index c4e64dc112063f..703161e6fc8c26 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -451,6 +451,12 @@ int sysfs_add_file_to_group(struct kobject *kobj, const struct attribute *attr, const char *group); void sysfs_remove_file_from_group(struct kobject *kobj, const struct attribute *attr, const char *group); +int sysfs_add_bin_file_to_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group); +void sysfs_remove_bin_file_from_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group); int sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp); void sysfs_unmerge_group(struct kobject *kobj, @@ -459,6 +465,9 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, struct kobject *target, const char *link_name); void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, const char *link_name); +int sysfs_add_link_to_sibling_group(struct kobject *kobj, + const char *link_grp, const char *link, + const char *target_grp, const char *target); int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, struct kobject *target_kobj, const char *target_name, @@ -660,6 +669,19 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj, { } +static inline int sysfs_add_bin_file_to_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group) +{ + return 0; +} + +static inline void sysfs_remove_bin_file_from_group(struct kobject *kobj, + const struct bin_attribute *attr, + const char *group) +{ +} + static inline int sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp) { @@ -683,6 +705,13 @@ static inline void sysfs_remove_link_from_group(struct kobject *kobj, { } +static inline int sysfs_add_link_to_sibling_group(struct kobject *kobj, + const char *link_grp, const char *link, + const char *target_grp, const char *target) +{ + return 0; +} + static inline int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, struct kobject *target_kobj, const char *target_name, diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h index 20a6c0fc149e23..db05e04199726c 100644 --- a/include/uapi/linux/cryptouser.h +++ b/include/uapi/linux/cryptouser.h @@ -64,6 +64,7 @@ enum crypto_attr_type_t { CRYPTOCFGA_STAT_AKCIPHER, /* No longer supported, do not use. */ CRYPTOCFGA_STAT_KPP, /* No longer supported, do not use. */ CRYPTOCFGA_STAT_ACOMP, /* No longer supported, do not use. */ + CRYPTOCFGA_REPORT_SIG, /* struct crypto_report_sig */ __CRYPTOCFGA_MAX #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) @@ -207,6 +208,10 @@ struct crypto_report_acomp { char type[CRYPTO_MAX_NAME]; }; +struct crypto_report_sig { + char type[CRYPTO_MAX_NAME]; +}; + #define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \ sizeof(struct crypto_report_blkcipher)) diff --git a/include/uapi/linux/virtio_crypto.h b/include/uapi/linux/virtio_crypto.h index 71a54a6849ca9f..2fccb64c9d6bfd 100644 --- a/include/uapi/linux/virtio_crypto.h +++ b/include/uapi/linux/virtio_crypto.h @@ -329,6 +329,7 @@ struct virtio_crypto_op_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x00) #define VIRTIO_CRYPTO_AKCIPHER_DECRYPT \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x01) + /* akcipher sign/verify opcodes are deprecated */ #define VIRTIO_CRYPTO_AKCIPHER_SIGN \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x02) #define VIRTIO_CRYPTO_AKCIPHER_VERIFY \ diff --git a/lib/Kconfig b/lib/Kconfig index b38849af6f1302..68f46e4a72a60d 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -777,3 +777,18 @@ config POLYNOMIAL config FIRMWARE_TABLE bool + +config SPDM + tristate + select CRYPTO + select KEYS + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select X509_CERTIFICATE_PARSER + help + The Security Protocol and Data Model (SPDM) allows for device + authentication, measurement, key exchange and encrypted sessions. + + Crypto algorithms negotiated with SPDM are limited to those enabled + in .config. Drivers selecting SPDM therefore need to also select + any algorithms they deem mandatory. diff --git a/lib/Makefile b/lib/Makefile index 773adf88af4166..5c6a4836599309 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -301,6 +301,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o obj-$(CONFIG_ASN1) += asn1_decoder.o obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o +obj-$(CONFIG_SPDM) += spdm/ + obj-$(CONFIG_FONT_SUPPORT) += fonts/ hostprogs := gen_crc32table diff --git a/lib/spdm/Makefile b/lib/spdm/Makefile new file mode 100644 index 00000000000000..edd4a3cc3f5c3e --- /dev/null +++ b/lib/spdm/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# DMTF Security Protocol and Data Model (SPDM) +# https://www.dmtf.org/dsp/DSP0274 +# +# Copyright (C) 2024 Intel Corporation + +obj-$(CONFIG_SPDM) += spdm.o + +spdm-y := core.o req-authenticate.o +spdm-$(CONFIG_SYSFS) += req-sysfs.o diff --git a/lib/spdm/core.c b/lib/spdm/core.c new file mode 100644 index 00000000000000..d547e486e76acd --- /dev/null +++ b/lib/spdm/core.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Core routines for message exchange, message transcript, + * signature verification and session state lifecycle + * + * Copyright (C) 2021-22 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#include "spdm.h" + +#include +#include + +#include +#include + +LIST_HEAD(spdm_state_list); /* list of all struct spdm_state */ +DEFINE_MUTEX(spdm_state_mutex); /* protects spdm_state_list */ + +static int spdm_err(struct device *dev, struct spdm_error_rsp *rsp) +{ + switch (rsp->error_code) { + case SPDM_INVALID_REQUEST: + dev_err(dev, "Invalid request\n"); + return -EINVAL; + case SPDM_INVALID_SESSION: + if (rsp->version == 0x11) { + dev_err(dev, "Invalid session %#x\n", rsp->error_data); + return -EINVAL; + } + break; + case SPDM_BUSY: + dev_err(dev, "Busy\n"); + return -EBUSY; + case SPDM_UNEXPECTED_REQUEST: + dev_err(dev, "Unexpected request\n"); + return -EINVAL; + case SPDM_UNSPECIFIED: + dev_err(dev, "Unspecified error\n"); + return -EINVAL; + case SPDM_DECRYPT_ERROR: + dev_err(dev, "Decrypt error\n"); + return -EIO; + case SPDM_UNSUPPORTED_REQUEST: + dev_err(dev, "Unsupported request %#x\n", rsp->error_data); + return -EINVAL; + case SPDM_REQUEST_IN_FLIGHT: + dev_err(dev, "Request in flight\n"); + return -EINVAL; + case SPDM_INVALID_RESPONSE_CODE: + dev_err(dev, "Invalid response code\n"); + return -EINVAL; + case SPDM_SESSION_LIMIT_EXCEEDED: + dev_err(dev, "Session limit exceeded\n"); + return -EBUSY; + case SPDM_SESSION_REQUIRED: + dev_err(dev, "Session required\n"); + return -EINVAL; + case SPDM_RESET_REQUIRED: + dev_err(dev, "Reset required\n"); + return -ECONNRESET; + case SPDM_RESPONSE_TOO_LARGE: + dev_err(dev, "Response too large\n"); + return -EINVAL; + case SPDM_REQUEST_TOO_LARGE: + dev_err(dev, "Request too large\n"); + return -EINVAL; + case SPDM_LARGE_RESPONSE: + dev_err(dev, "Large response\n"); + return -EMSGSIZE; + case SPDM_MESSAGE_LOST: + dev_err(dev, "Message lost\n"); + return -EIO; + case SPDM_INVALID_POLICY: + dev_err(dev, "Invalid policy\n"); + return -EINVAL; + case SPDM_VERSION_MISMATCH: + dev_err(dev, "Version mismatch\n"); + return -EINVAL; + case SPDM_RESPONSE_NOT_READY: + dev_err(dev, "Response not ready\n"); + return -EINPROGRESS; + case SPDM_REQUEST_RESYNCH: + dev_err(dev, "Request resynchronization\n"); + return -ECONNRESET; + case SPDM_OPERATION_FAILED: + dev_err(dev, "Operation failed\n"); + return -EINVAL; + case SPDM_NO_PENDING_REQUESTS: + return -ENOENT; + case SPDM_VENDOR_DEFINED_ERROR: + dev_err(dev, "Vendor defined error\n"); + return -EINVAL; + } + + dev_err(dev, "Undefined error %#x\n", rsp->error_code); + return -EINVAL; +} + +/** + * spdm_exchange() - Perform SPDM message exchange with device + * + * @spdm_state: SPDM session state + * @req: Request message + * @req_sz: Size of @req + * @rsp: Response message + * @rsp_sz: Size of @rsp + * + * Send the request @req to the device via the @transport in @spdm_state and + * receive the response into @rsp, respecting the maximum buffer size @rsp_sz. + * The request version is automatically populated. + * + * Return response size on success or a negative errno. Response size may be + * less than @rsp_sz and the caller is responsible for checking that. It may + * also be more than expected (though never more than @rsp_sz), e.g. if the + * transport receives only dword-sized chunks. + */ +ssize_t spdm_exchange(struct spdm_state *spdm_state, + void *req, size_t req_sz, void *rsp, size_t rsp_sz) +{ + struct spdm_header *request = req; + struct spdm_header *response = rsp; + ssize_t rc, length; + + if (req_sz < sizeof(struct spdm_header) || + rsp_sz < sizeof(struct spdm_header)) + return -EINVAL; + + request->version = spdm_state->version; + + rc = spdm_state->transport(spdm_state->transport_priv, spdm_state->dev, + req, req_sz, rsp, rsp_sz); + if (rc < 0) + return rc; + + length = rc; + if (length < sizeof(struct spdm_header)) + return length; /* Truncated response is handled by callers */ + + if (response->code == SPDM_ERROR) + return spdm_err(spdm_state->dev, (struct spdm_error_rsp *)rsp); + + if (response->code != (request->code & ~SPDM_REQ)) { + dev_err(spdm_state->dev, + "Response code %#x does not match request code %#x\n", + response->code, request->code); + return -EPROTO; + } + + return length; +} + +/** + * spdm_alloc_transcript() - Allocate transcript buffer + * + * @spdm_state: SPDM session state + * + * Allocate a buffer to accommodate the concatenation of all SPDM messages + * exchanged during an authentication or measurement sequence. Used to verify + * the signature, as it is computed over the hashed transcript. + * + * Transcript size is initially one page. It grows by additional pages as + * needed. Minimum size of an authentication sequence is 1k (only one slot + * occupied, only one ECC P256 certificate in chain, SHA 256 hash selected). + * Maximum can be several MBytes. Between 4k and 64k is probably typical. + * + * Return 0 on success or a negative errno. + */ +int spdm_alloc_transcript(struct spdm_state *spdm_state) +{ + spdm_state->transcript = kvmalloc(PAGE_SIZE, GFP_KERNEL); + if (!spdm_state->transcript) + return -ENOMEM; + + spdm_state->transcript_end = spdm_state->transcript; + spdm_state->transcript_max = PAGE_SIZE; + + return 0; +} + +/** + * spdm_free_transcript() - Free transcript buffer + * + * @spdm_state: SPDM session state + * + * Free the transcript buffer after performing authentication or measurement. + * Reset the pointer to the current end of transcript as well as the allocation + * size. + */ +void spdm_free_transcript(struct spdm_state *spdm_state) +{ + kvfree(spdm_state->transcript); + spdm_state->transcript_end = NULL; + spdm_state->transcript_max = 0; +} + +/** + * spdm_append_transcript() - Append a message to transcript buffer + * + * @spdm_state: SPDM session state + * @msg: SPDM message + * @msg_sz: Size of @msg + * + * Append an SPDM message to the transcript after reception or transmission. + * Reallocate a larger transcript buffer if the message exceeds its current + * allocation size. + * + * If the message to be appended is known to fit into the allocation size, + * it may be directly received into or transmitted from the transcript buffer + * instead of calling this function: Simply use the @transcript_end pointer in + * struct spdm_state as the position to store the message, then advance the + * pointer by the message size. + * + * Return 0 on success or a negative errno. + */ +int spdm_append_transcript(struct spdm_state *spdm_state, + const void *msg, size_t msg_sz) +{ + size_t transcript_sz = spdm_state->transcript_end - + spdm_state->transcript; + + if (transcript_sz + msg_sz > spdm_state->transcript_max) { + size_t new_sz = round_up(transcript_sz + msg_sz, PAGE_SIZE); + void *new = kvrealloc(spdm_state->transcript, + new_sz, GFP_KERNEL); + if (!new) + return -ENOMEM; + + spdm_state->transcript = new; + spdm_state->transcript_end = new + transcript_sz; + spdm_state->transcript_max = new_sz; + } + + memcpy(spdm_state->transcript_end, msg, msg_sz); + spdm_state->transcript_end += msg_sz; + + return 0; +} + +/** + * spdm_create_combined_prefix() - Create combined_spdm_prefix for a hash + * + * @version: SPDM version negotiated during GET_VERSION exchange + * @spdm_context: SPDM context of signature generation (or verification) + * @buf: Buffer to receive combined_spdm_prefix (100 bytes) + * + * From SPDM 1.2, a hash is prefixed with the SPDM version and context before + * a signature is generated (or verified) over the resulting concatenation + * (SPDM 1.2.0 section 15). Create that prefix. + */ +void spdm_create_combined_prefix(u8 version, const char *spdm_context, + void *buf) +{ + u8 major = FIELD_GET(0xf0, version); + u8 minor = FIELD_GET(0x0f, version); + size_t len = strlen(spdm_context); + int rc, zero_pad; + + rc = snprintf(buf, SPDM_PREFIX_SZ + 1, + "dmtf-spdm-v%hhx.%hhx.*dmtf-spdm-v%hhx.%hhx.*" + "dmtf-spdm-v%hhx.%hhx.*dmtf-spdm-v%hhx.%hhx.*", + major, minor, major, minor, major, minor, major, minor); + WARN_ON(rc != SPDM_PREFIX_SZ); + + zero_pad = SPDM_COMBINED_PREFIX_SZ - SPDM_PREFIX_SZ - 1 - len; + WARN_ON(zero_pad < 0); + + memset(buf + SPDM_PREFIX_SZ + 1, 0, zero_pad); + memcpy(buf + SPDM_PREFIX_SZ + 1 + zero_pad, spdm_context, len); +} + +/** + * spdm_verify_signature() - Verify signature against leaf key + * + * @spdm_state: SPDM session state + * @spdm_context: SPDM context (used to create combined_spdm_prefix) + * + * Implementation of the abstract SPDMSignatureVerify() function described in + * SPDM 1.2.0 section 16: Compute the hash over @spdm_state->transcript and + * verify that the signature at the end of the transcript was generated by + * @spdm_state->leaf_key. Hashing the entire transcript allows detection + * of message modification by a man-in-the-middle or media error. + * + * Return 0 on success or a negative errno. + */ +int spdm_verify_signature(struct spdm_state *spdm_state, + const char *spdm_context) +{ + struct public_key_signature sig = { + .s = spdm_state->transcript_end - spdm_state->sig_len, + .s_size = spdm_state->sig_len, + .encoding = spdm_state->base_asym_enc, + .hash_algo = spdm_state->base_hash_alg_name, + }; + u8 *mhash __free(kfree) = NULL; + u8 *m __free(kfree); + int rc; + + m = kmalloc(SPDM_COMBINED_PREFIX_SZ + spdm_state->hash_len, GFP_KERNEL); + if (!m) + return -ENOMEM; + + /* Hash the transcript (sans trailing signature) */ + rc = crypto_shash_digest(spdm_state->desc, spdm_state->transcript, + (void *)sig.s - spdm_state->transcript, + m + SPDM_COMBINED_PREFIX_SZ); + if (rc) + return rc; + + if (spdm_state->version <= 0x11) { + /* + * SPDM 1.0 and 1.1 compute the signature only over the hash + * (SPDM 1.0.0 section 4.9.2.7). + */ + sig.digest = m + SPDM_COMBINED_PREFIX_SZ; + sig.digest_size = spdm_state->hash_len; + } else { + /* + * From SPDM 1.2, the hash is prefixed with spdm_context before + * computing the signature over the resulting message M + * (SPDM 1.2.0 sec 15). + */ + spdm_create_combined_prefix(spdm_state->version, spdm_context, + m); + + /* + * RSA and ECDSA algorithms require that M is hashed once more. + * EdDSA and SM2 algorithms omit that step. + * The switch statement prepares for their introduction. + */ + switch (spdm_state->base_asym_alg) { + default: + mhash = kmalloc(spdm_state->hash_len, GFP_KERNEL); + if (!mhash) + return -ENOMEM; + + rc = crypto_shash_digest(spdm_state->desc, m, + SPDM_COMBINED_PREFIX_SZ + spdm_state->hash_len, + mhash); + if (rc) + return rc; + + sig.digest = mhash; + sig.digest_size = spdm_state->hash_len; + break; + } + } + + return public_key_verify_signature(spdm_state->leaf_key, &sig); +} + +/** + * spdm_reset() - Free cryptographic data structures + * + * @spdm_state: SPDM session state + * + * Free cryptographic data structures when an SPDM session is destroyed or + * when the device is reauthenticated. + */ +void spdm_reset(struct spdm_state *spdm_state) +{ + public_key_free(spdm_state->leaf_key); + spdm_state->leaf_key = NULL; + + kfree(spdm_state->desc); + spdm_state->desc = NULL; + + crypto_free_shash(spdm_state->shash); + spdm_state->shash = NULL; +} + +/** + * spdm_create() - Allocate SPDM session + * + * @dev: Responder device + * @transport: Transport function to perform one message exchange + * @transport_priv: Transport private data + * @transport_sz: Maximum message size the transport is capable of (in bytes) + * @keyring: Trusted root certificates + * @validate: Function to validate additional leaf certificate requirements + * (optional, may be %NULL) + * + * Return a pointer to the allocated SPDM session state or NULL on error. + */ +struct spdm_state *spdm_create(struct device *dev, spdm_transport *transport, + void *transport_priv, u32 transport_sz, + struct key *keyring, spdm_validate *validate) +{ + struct spdm_state *spdm_state = kzalloc(sizeof(*spdm_state), GFP_KERNEL); + + if (!spdm_state) + return NULL; + + spdm_state->dev = dev; + spdm_state->transport = transport; + spdm_state->transport_priv = transport_priv; + spdm_state->transport_sz = transport_sz; + spdm_state->root_keyring = keyring; + spdm_state->validate = validate; + + mutex_init(&spdm_state->lock); + INIT_LIST_HEAD(&spdm_state->log); + + mutex_lock(&spdm_state_mutex); + list_add_tail(&spdm_state->list, &spdm_state_list); + mutex_unlock(&spdm_state_mutex); + + return spdm_state; +} +EXPORT_SYMBOL_GPL(spdm_create); + +/** + * spdm_await() - Wait for ongoing spdm_authenticate() to finish + * + * @spdm_state: SPDM session state + */ +void spdm_await(struct spdm_state *spdm_state) +{ + mutex_lock(&spdm_state->lock); + mutex_unlock(&spdm_state->lock); +} + +/** + * spdm_destroy() - Destroy SPDM session + * + * @spdm_state: SPDM session state + */ +void spdm_destroy(struct spdm_state *spdm_state) +{ + u8 slot; + + mutex_lock(&spdm_state_mutex); + list_del(&spdm_state->list); + mutex_unlock(&spdm_state_mutex); + + for_each_set_bit(slot, &spdm_state->provisioned_slots, SPDM_SLOTS) + kvfree(spdm_state->slot[slot]); + + spdm_reset(spdm_state); + spdm_destroy_log(spdm_state); + mutex_destroy(&spdm_state->lock); + kfree(spdm_state->next_nonce); + kfree(spdm_state); +} +EXPORT_SYMBOL_GPL(spdm_destroy); + +MODULE_DESCRIPTION("DMTF Security Protocol and Data Model"); +MODULE_LICENSE("GPL"); diff --git a/lib/spdm/req-authenticate.c b/lib/spdm/req-authenticate.c new file mode 100644 index 00000000000000..180a2374e230ca --- /dev/null +++ b/lib/spdm/req-authenticate.c @@ -0,0 +1,813 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Requester role: Authenticate a device + * + * Copyright (C) 2021-22 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#include "spdm.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* SPDM 1.2.0 margin no 359 and 803 */ +static const char *spdm_context = "responder-challenge_auth signing"; + +/* + * All SPDM messages exchanged during an authentication sequence up to and + * including GET_DIGESTS fit into a single page, hence are stored in the + * transcript without bounds checking. Only subsequent GET_CERTIFICATE + * and CHALLENGE exchanges may exceed one page. + */ +static_assert(PAGE_SIZE >= + sizeof(struct spdm_get_version_req) + + struct_size_t(struct spdm_get_version_rsp, + version_number_entries, 255) + + sizeof(struct spdm_get_capabilities_req) + + sizeof(struct spdm_get_capabilities_rsp) + + sizeof(struct spdm_negotiate_algs_req) + + sizeof(struct spdm_negotiate_algs_rsp) + + sizeof(struct spdm_req_alg_struct) * 2 * SPDM_MAX_REQ_ALG_STRUCT + + sizeof(struct spdm_get_digests_req) + + struct_size_t(struct spdm_get_digests_rsp, + digests, SPDM_SLOTS * SHA512_DIGEST_SIZE)); + +static int spdm_get_version(struct spdm_state *spdm_state) +{ + struct spdm_get_version_req *req = spdm_state->transcript; + struct spdm_get_version_rsp *rsp; + bool foundver = false; + int rc, length, i; + + spdm_state->version = 0x10; + + *req = (struct spdm_get_version_req) { + .code = SPDM_GET_VERSION, + }; + + rsp = spdm_state->transcript_end += sizeof(*req); + + rc = spdm_exchange(spdm_state, req, sizeof(*req), rsp, + struct_size(rsp, version_number_entries, 255)); + if (rc < 0) + return rc; + + length = rc; + if (length < sizeof(*rsp) || + length < struct_size(rsp, version_number_entries, + rsp->version_number_entry_count)) { + dev_err(spdm_state->dev, "Truncated version response\n"); + return -EIO; + } + + spdm_state->transcript_end += + struct_size(rsp, version_number_entries, + rsp->version_number_entry_count); + + for (i = 0; i < rsp->version_number_entry_count; i++) { + u8 ver = le16_to_cpu(rsp->version_number_entries[i]) >> 8; + + if (ver >= spdm_state->version && ver <= SPDM_MAX_VER) { + spdm_state->version = ver; + foundver = true; + } + } + if (!foundver) { + dev_err(spdm_state->dev, "No common supported version\n"); + return -EPROTO; + } + + return 0; +} + +static int spdm_get_capabilities(struct spdm_state *spdm_state) +{ + struct spdm_get_capabilities_req *req = spdm_state->transcript_end; + struct spdm_get_capabilities_rsp *rsp; + size_t req_sz, rsp_sz; + int rc, length; + + *req = (struct spdm_get_capabilities_req) { + .code = SPDM_GET_CAPABILITIES, + .ctexponent = SPDM_CTEXPONENT, + .flags = cpu_to_le32(SPDM_REQ_CAPS), + }; + + if (spdm_state->version == 0x10) { + req_sz = offsetofend(typeof(*req), param2); + rsp_sz = offsetofend(typeof(*rsp), flags); + } else if (spdm_state->version == 0x11) { + req_sz = offsetofend(typeof(*req), flags); + rsp_sz = offsetofend(typeof(*rsp), flags); + } else { + req_sz = sizeof(*req); + rsp_sz = sizeof(*rsp); + req->data_transfer_size = cpu_to_le32(spdm_state->transport_sz); + req->max_spdm_msg_size = cpu_to_le32(UINT_MAX); + req->flags = cpu_to_le32(req->flags | SPDM_CHUNK_CAP); + } + + rsp = spdm_state->transcript_end += req_sz; + + rc = spdm_exchange(spdm_state, req, req_sz, rsp, rsp_sz); + if (rc < 0) + return rc; + + length = rc; + if (length < rsp_sz) { + dev_err(spdm_state->dev, "Truncated capabilities response\n"); + return -EIO; + } + + spdm_state->transcript_end += rsp_sz; + + spdm_state->rsp_caps = le32_to_cpu(rsp->flags); + if ((spdm_state->rsp_caps & SPDM_RSP_MIN_CAPS) != SPDM_RSP_MIN_CAPS) + return -EPROTONOSUPPORT; + + if (spdm_state->version >= 0x12) { + u32 data_transfer_size = le32_to_cpu(rsp->data_transfer_size); + if (data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE) { + dev_err(spdm_state->dev, + "Malformed capabilities response\n"); + return -EPROTO; + } + spdm_state->transport_sz = min(spdm_state->transport_sz, + data_transfer_size); + } + + return 0; +} + +static int spdm_parse_algs(struct spdm_state *spdm_state) +{ + switch (spdm_state->base_asym_alg) { + case SPDM_ASYM_RSASSA_2048: + spdm_state->sig_len = 256; + spdm_state->base_asym_enc = "pkcs1"; + break; + case SPDM_ASYM_RSASSA_3072: + spdm_state->sig_len = 384; + spdm_state->base_asym_enc = "pkcs1"; + break; + case SPDM_ASYM_RSASSA_4096: + spdm_state->sig_len = 512; + spdm_state->base_asym_enc = "pkcs1"; + break; + case SPDM_ASYM_ECDSA_ECC_NIST_P256: + spdm_state->sig_len = 64; + spdm_state->base_asym_enc = "p1363"; + break; + case SPDM_ASYM_ECDSA_ECC_NIST_P384: + spdm_state->sig_len = 96; + spdm_state->base_asym_enc = "p1363"; + break; + case SPDM_ASYM_ECDSA_ECC_NIST_P521: + spdm_state->sig_len = 132; + spdm_state->base_asym_enc = "p1363"; + break; + default: + dev_err(spdm_state->dev, "Unknown asym algorithm\n"); + return -EINVAL; + } + + switch (spdm_state->base_hash_alg) { + case SPDM_HASH_SHA_256: + spdm_state->base_hash_alg_name = "sha256"; + break; + case SPDM_HASH_SHA_384: + spdm_state->base_hash_alg_name = "sha384"; + break; + case SPDM_HASH_SHA_512: + spdm_state->base_hash_alg_name = "sha512"; + break; + default: + dev_err(spdm_state->dev, "Unknown hash algorithm\n"); + return -EINVAL; + } + + /* + * shash and desc allocations are reused for subsequent measurement + * retrieval, hence are not freed until spdm_reset(). + */ + spdm_state->shash = crypto_alloc_shash(spdm_state->base_hash_alg_name, + 0, 0); + if (!spdm_state->shash) + return -ENOMEM; + + spdm_state->desc = kzalloc(sizeof(*spdm_state->desc) + + crypto_shash_descsize(spdm_state->shash), + GFP_KERNEL); + if (!spdm_state->desc) + return -ENOMEM; + + spdm_state->desc->tfm = spdm_state->shash; + + /* Used frequently to compute offsets, so cache H */ + spdm_state->hash_len = crypto_shash_digestsize(spdm_state->shash); + + return crypto_shash_init(spdm_state->desc); +} + +static int spdm_negotiate_algs(struct spdm_state *spdm_state) +{ + struct spdm_negotiate_algs_req *req = spdm_state->transcript_end; + struct spdm_negotiate_algs_rsp *rsp; + struct spdm_req_alg_struct *req_alg_struct; + size_t req_sz, rsp_sz; + int rc, length, i = 0; + + req_sz = sizeof(*req) + + sizeof(*req_alg_struct) * SPDM_MAX_REQ_ALG_STRUCT; + + /* Request length shall be <= 128 bytes (SPDM 1.1.0 margin no 185) */ + BUILD_BUG_ON(req_sz > 128); + + *req = (struct spdm_negotiate_algs_req) { + .code = SPDM_NEGOTIATE_ALGS, + .measurement_specification = SPDM_MEAS_SPEC_DMTF, + .base_asym_algo = cpu_to_le32(SPDM_ASYM_ALGOS), + .base_hash_algo = cpu_to_le32(SPDM_HASH_ALGOS), + }; + + /* + * Only OpaqueDataFmt1 is supported with SPDM 1.2 or later + * (Secured Messages using SPDM Spec 1.1.0 margin no 118) + */ + if (spdm_state->version >= 0x12 && + spdm_state->rsp_caps & SPDM_KEY_EX_CAP) + req->other_params_support = SPDM_OPAQUE_DATA_FMT_GENERAL; + + /* ReqAlgStruct order shall be by AlgType (SPDM 1.1.0 margin no 186) */ + req_alg_struct = (struct spdm_req_alg_struct *)(req + 1); + if (spdm_state->rsp_caps & SPDM_KEY_EX_CAP) { + req_alg_struct[i++] = (struct spdm_req_alg_struct) { + .alg_type = SPDM_REQ_ALG_STRUCT_DHE, + .alg_count = 0x20, + .alg_supported = cpu_to_le16(SPDM_DHE_ALGOS), + }; + req_alg_struct[i++] = (struct spdm_req_alg_struct) { + .alg_type = SPDM_REQ_ALG_STRUCT_AEAD, + .alg_count = 0x20, + .alg_supported = cpu_to_le16(SPDM_AEAD_ALGOS), + }; + } + if (spdm_state->rsp_caps & SPDM_MUT_AUTH_CAP) + req_alg_struct[i++] = (struct spdm_req_alg_struct) { + .alg_type = SPDM_REQ_ALG_STRUCT_REQ_BASE_ASYM_ALG, + .alg_count = 0x20, + .alg_supported = cpu_to_le16(SPDM_ASYM_ALGOS), + }; + if (spdm_state->rsp_caps & SPDM_KEY_EX_CAP) + req_alg_struct[i++] = (struct spdm_req_alg_struct) { + .alg_type = SPDM_REQ_ALG_STRUCT_KEY_SCHEDULE, + .alg_count = 0x20, + .alg_supported = cpu_to_le16(SPDM_KEY_SCHEDULE_SPDM), + }; + WARN_ON(i > SPDM_MAX_REQ_ALG_STRUCT); + req_sz = sizeof(*req) + i * sizeof(*req_alg_struct); + rsp_sz = sizeof(*rsp) + i * sizeof(*req_alg_struct); + req->length = cpu_to_le16(req_sz); + req->param1 = i; + + rsp = spdm_state->transcript_end += req_sz; + + rc = spdm_exchange(spdm_state, req, req_sz, rsp, rsp_sz); + if (rc < 0) + return rc; + + length = rc; + if (length < sizeof(*rsp) || + length < sizeof(*rsp) + rsp->param1 * sizeof(*req_alg_struct)) { + dev_err(spdm_state->dev, "Truncated algorithms response\n"); + return -EIO; + } + + /* + * If request contained a ReqAlgStruct not supported by responder, + * the corresponding RespAlgStruct may be omitted in response. + * Calculate the actual (possibly shorter) response length: + */ + spdm_state->transcript_end += + sizeof(*rsp) + rsp->param1 * sizeof(*req_alg_struct); + + spdm_state->base_asym_alg = le32_to_cpu(rsp->base_asym_sel); + spdm_state->base_hash_alg = le32_to_cpu(rsp->base_hash_sel); + spdm_state->meas_hash_alg = le32_to_cpu(rsp->measurement_hash_algo); + + if ((spdm_state->base_asym_alg & SPDM_ASYM_ALGOS) == 0 || + (spdm_state->base_hash_alg & SPDM_HASH_ALGOS) == 0) { + dev_err(spdm_state->dev, "No common supported algorithms\n"); + return -EPROTO; + } + + /* Responder shall select exactly 1 alg (SPDM 1.0.0 table 14) */ + if (hweight32(spdm_state->base_asym_alg) != 1 || + hweight32(spdm_state->base_hash_alg) != 1 || + rsp->ext_asym_sel_count != 0 || + rsp->ext_hash_sel_count != 0 || + rsp->param1 > req->param1 || + rsp->other_params_sel != req->other_params_support || + (spdm_state->rsp_caps & SPDM_MEAS_CAP_MASK && + (hweight32(spdm_state->meas_hash_alg) != 1 || + rsp->measurement_specification_sel != SPDM_MEAS_SPEC_DMTF))) { + dev_err(spdm_state->dev, "Malformed algorithms response\n"); + return -EPROTO; + } + + return spdm_parse_algs(spdm_state); +} + +static int spdm_get_digests(struct spdm_state *spdm_state) +{ + struct spdm_get_digests_req *req = spdm_state->transcript_end; + struct spdm_get_digests_rsp *rsp; + unsigned long deprovisioned_slots; + u8 slot, supported_slots; + int rc, length; + size_t rsp_sz; + + *req = (struct spdm_get_digests_req) { + .code = SPDM_GET_DIGESTS, + }; + + rsp = spdm_state->transcript_end += sizeof(*req); + + /* + * Assume all 8 slots are populated. We know the hash length (and thus + * the response size) because the responder only returns digests for + * the hash algorithm selected during the NEGOTIATE_ALGORITHMS exchange + * (SPDM 1.1.2 margin no 206). + */ + rsp_sz = sizeof(*rsp) + SPDM_SLOTS * spdm_state->hash_len; + + rc = spdm_exchange(spdm_state, req, sizeof(*req), rsp, rsp_sz); + if (rc < 0) + return rc; + + length = rc; + if (length < sizeof(*rsp) || + length < sizeof(*rsp) + hweight8(rsp->param2) * + spdm_state->hash_len) { + dev_err(spdm_state->dev, "Truncated digests response\n"); + return -EIO; + } + + spdm_state->transcript_end += sizeof(*rsp) + hweight8(rsp->param2) * + spdm_state->hash_len; + + deprovisioned_slots = spdm_state->provisioned_slots & ~rsp->param2; + for_each_set_bit(slot, &deprovisioned_slots, SPDM_SLOTS) { + kvfree(spdm_state->slot[slot]); + spdm_state->slot_sz[slot] = 0; + spdm_state->slot[slot] = NULL; + } + + /* + * Authentication-capable endpoints must carry at least 1 cert chain + * (SPDM 1.0.0 section 4.9.2.1). + */ + spdm_state->provisioned_slots = rsp->param2; + if (!spdm_state->provisioned_slots) { + dev_err(spdm_state->dev, "No certificates provisioned\n"); + return -EPROTO; + } + + /* + * If a bit is set in ProvisionedSlotMask, the corresponding bit in + * SupportedSlotMask shall also be set (SPDM 1.3.0 table 35). + */ + if (spdm_state->version >= 0x13 && rsp->param2 & ~rsp->param1) { + dev_err(spdm_state->dev, "Malformed digests response\n"); + return -EPROTO; + } + + if (spdm_state->version >= 0x13) + supported_slots = rsp->param1; + else + supported_slots = GENMASK(7, 0); + + if (spdm_state->supported_slots != supported_slots) { + spdm_state->supported_slots = supported_slots; + + if (device_is_registered(spdm_state->dev)) { + rc = sysfs_update_group(&spdm_state->dev->kobj, + &spdm_certificates_group); + if (rc) + dev_err(spdm_state->dev, + "Cannot update certificates in sysfs: " + "%d\n", rc); + } + } + + return 0; +} + +static int spdm_get_certificate(struct spdm_state *spdm_state, u8 slot) +{ + struct spdm_cert_chain *certs __free(kvfree) = NULL; + struct spdm_get_certificate_rsp *rsp __free(kvfree); + struct spdm_get_certificate_req req = { + .code = SPDM_GET_CERTIFICATE, + .param1 = slot, + }; + size_t rsp_sz, total_length, header_length; + u16 remainder_length = 0xffff; + u16 portion_length; + u16 offset = 0; + int rc, length; + + /* + * It is legal for the responder to send more bytes than requested. + * (Note the "should" in SPDM 1.0.0 table 19.) If we allocate a + * too small buffer, we can't calculate the hash over the (truncated) + * response. Only choice is thus to allocate the maximum possible 64k. + */ + rsp_sz = min_t(u32, sizeof(*rsp) + 0xffff, spdm_state->transport_sz); + rsp = kvmalloc(rsp_sz, GFP_KERNEL); + if (!rsp) + return -ENOMEM; + + do { + /* + * If transport_sz is sufficiently large, first request will be + * for offset 0 and length 0xffff, which means entire cert + * chain (SPDM 1.0.0 table 18). + */ + req.offset = cpu_to_le16(offset); + req.length = cpu_to_le16(min_t(size_t, remainder_length, + rsp_sz - sizeof(*rsp))); + + rc = spdm_exchange(spdm_state, &req, sizeof(req), rsp, rsp_sz); + if (rc < 0) + return rc; + + length = rc; + if (length < sizeof(*rsp) || + length < sizeof(*rsp) + le16_to_cpu(rsp->portion_length)) { + dev_err(spdm_state->dev, + "Truncated certificate response\n"); + return -EIO; + } + + portion_length = le16_to_cpu(rsp->portion_length); + remainder_length = le16_to_cpu(rsp->remainder_length); + + rc = spdm_append_transcript(spdm_state, &req, sizeof(req)); + if (rc) + return rc; + + rc = spdm_append_transcript(spdm_state, rsp, + sizeof(*rsp) + portion_length); + if (rc) + return rc; + + /* + * On first response we learn total length of cert chain. + * Should portion_length + remainder_length exceed 0xffff, + * the min() ensures that the malformed check triggers below. + */ + if (!certs) { + total_length = min(portion_length + remainder_length, + 0xffff); + certs = kvmalloc(total_length, GFP_KERNEL); + if (!certs) + return -ENOMEM; + } + + if (!portion_length || + (rsp->param1 & 0xf) != slot || + offset + portion_length + remainder_length != total_length) + { + dev_err(spdm_state->dev, + "Malformed certificate response\n"); + return -EPROTO; + } + + memcpy((u8 *)certs + offset, rsp->cert_chain, portion_length); + offset += portion_length; + } while (remainder_length > 0); + + header_length = sizeof(struct spdm_cert_chain) + spdm_state->hash_len; + + if (total_length < header_length || + total_length != le16_to_cpu(certs->length)) { + dev_err(spdm_state->dev, + "Malformed certificate chain in slot %u\n", slot); + return -EPROTO; + } + + kvfree(spdm_state->slot[slot]); + spdm_state->slot_sz[slot] = total_length; + spdm_state->slot[slot] = no_free_ptr(certs); + + return 0; +} + +static int spdm_validate_cert_chain(struct spdm_state *spdm_state, u8 slot) +{ + struct x509_certificate *cert __free(x509_free_certificate) = NULL; + struct x509_certificate *prev __free(x509_free_certificate) = NULL; + size_t header_length, total_length; + bool is_leaf_cert; + size_t offset = 0; + struct key *key; + int rc, length; + u8 *certs; + + header_length = sizeof(struct spdm_cert_chain) + spdm_state->hash_len; + total_length = spdm_state->slot_sz[slot] - header_length; + certs = (u8 *)spdm_state->slot[slot] + header_length; + + do { + rc = x509_get_certificate_length(certs + offset, + total_length - offset); + if (rc < 0) { + dev_err(spdm_state->dev, "Invalid certificate length " + "at slot %u offset %zu\n", slot, offset); + return rc; + } + + length = rc; + is_leaf_cert = offset + length == total_length; + + cert = x509_cert_parse(certs + offset, length); + if (IS_ERR(cert)) { + dev_err(spdm_state->dev, "Certificate parse error %pe " + "at slot %u offset %zu\n", cert, slot, offset); + return PTR_ERR(cert); + } + if (cert->unsupported_sig) { + dev_err(spdm_state->dev, "Unsupported signature " + "at slot %u offset %zu\n", slot, offset); + return -EKEYREJECTED; + } + if (cert->blacklisted) + return -EKEYREJECTED; + + /* + * Basic Constraints CA value shall be false for leaf cert, + * true for intermediate and root certs (SPDM 1.3.0 table 42). + * Key Usage bit for digital signature shall be set, except + * for GenericCert in slot > 0 (SPDM 1.3.0 margin no 354). + * KeyCertSign bit must be 0 for non-CA (RFC 5280 sec 4.2.1.9). + */ + if ((is_leaf_cert == + test_bit(KEY_EFLAG_CA, &cert->pub->key_eflags)) || + (is_leaf_cert && slot == 0 && + !test_bit(KEY_EFLAG_DIGITALSIG, &cert->pub->key_eflags)) || + (is_leaf_cert && + test_bit(KEY_EFLAG_KEYCERTSIGN, &cert->pub->key_eflags))) { + dev_err(spdm_state->dev, "Malformed certificate " + "at slot %u offset %zu\n", slot, offset); + return -EKEYREJECTED; + } + + if (!prev) { + /* First cert in chain, check against root_keyring */ + key = find_asymmetric_key(spdm_state->root_keyring, + cert->sig->auth_ids[0], + cert->sig->auth_ids[1], + cert->sig->auth_ids[2], + false); + if (IS_ERR(key)) { + dev_info(spdm_state->dev, "Root certificate " + "of slot %u not found in %s " + "keyring: %s\n", slot, + spdm_state->root_keyring->description, + cert->issuer); + return PTR_ERR(key); + } + + rc = verify_signature(key, cert->sig); + key_put(key); + } else { + /* Subsequent cert in chain, check against previous */ + rc = public_key_verify_signature(prev->pub, cert->sig); + } + + if (rc) { + dev_err(spdm_state->dev, "Signature validation error " + "%d at slot %u offset %zu\n", rc, slot, offset); + return rc; + } + + x509_free_certificate(prev); + prev = cert; + cert = ERR_PTR(-ENOKEY); + + offset += length; + } while (offset < total_length); + + if (spdm_state->validate) { + rc = spdm_state->validate(spdm_state->dev, slot, prev); + if (rc) + return rc; + } + + /* Steal pub pointer ahead of x509_free_certificate() */ + spdm_state->leaf_key = prev->pub; + prev->pub = NULL; + + return 0; +} + +/** + * spdm_challenge_rsp_sz() - Calculate CHALLENGE_AUTH response size + * + * @spdm_state: SPDM session state + * @rsp: CHALLENGE_AUTH response (optional) + * + * A CHALLENGE_AUTH response contains multiple variable-length fields + * as well as optional fields. This helper eases calculating its size. + * + * If @rsp is %NULL, assume the maximum OpaqueDataLength of 1024 bytes + * (SPDM 1.0.0 table 21). Otherwise read OpaqueDataLength from @rsp. + * OpaqueDataLength can only be > 0 for SPDM 1.0 and 1.1, as they lack + * the OtherParamsSupport field in the NEGOTIATE_ALGORITHMS request. + * For SPDM 1.2+, we do not offer any Opaque Data Formats in that field, + * which forces OpaqueDataLength to 0 (SPDM 1.2.0 margin no 261). + */ +static size_t spdm_challenge_rsp_sz(struct spdm_state *spdm_state, + struct spdm_challenge_rsp *rsp) +{ + size_t size = sizeof(*rsp) /* Header */ + + spdm_state->hash_len /* CertChainHash */ + + SPDM_NONCE_SZ; /* Nonce */ + + if (rsp) + /* May be unaligned if hash algorithm has odd length */ + size += get_unaligned_le16((u8 *)rsp + size); + else + size += SPDM_MAX_OPAQUE_DATA; /* OpaqueData */ + + size += 2; /* OpaqueDataLength */ + + if (spdm_state->version >= 0x13) + size += 8; /* RequesterContext */ + + return size + spdm_state->sig_len; /* Signature */ +} + +static int spdm_challenge(struct spdm_state *spdm_state, u8 slot, bool verify) +{ + size_t req_sz, rsp_sz, rsp_sz_max, req_nonce_off, rsp_nonce_off; + struct spdm_challenge_rsp *rsp __free(kfree); + struct spdm_challenge_req req = { + .code = SPDM_CHALLENGE, + .param1 = slot, + .param2 = 0, /* No measurement summary hash */ + }; + int rc, length; + + if (spdm_state->next_nonce) { + memcpy(&req.nonce, spdm_state->next_nonce, sizeof(req.nonce)); + kfree(spdm_state->next_nonce); + spdm_state->next_nonce = NULL; + } else { + get_random_bytes(&req.nonce, sizeof(req.nonce)); + } + + if (spdm_state->version <= 0x12) + req_sz = offsetofend(typeof(req), nonce); + else + req_sz = sizeof(req); + + rsp_sz_max = spdm_challenge_rsp_sz(spdm_state, NULL); + rsp = kzalloc(rsp_sz_max, GFP_KERNEL); + if (!rsp) + return -ENOMEM; + + rc = spdm_exchange(spdm_state, &req, req_sz, rsp, rsp_sz_max); + if (rc < 0) + return rc; + + length = rc; + rsp_sz = spdm_challenge_rsp_sz(spdm_state, rsp); + if (length < rsp_sz) { + dev_err(spdm_state->dev, "Truncated challenge_auth response\n"); + return -EIO; + } + + req_nonce_off = spdm_state->transcript_end - spdm_state->transcript + + offsetof(typeof(req), nonce); + rc = spdm_append_transcript(spdm_state, &req, req_sz); + if (rc) + return rc; + + rsp_nonce_off = spdm_state->transcript_end - spdm_state->transcript + + sizeof(*rsp) + spdm_state->hash_len; + rc = spdm_append_transcript(spdm_state, rsp, rsp_sz); + if (rc) + return rc; + + rc = -EKEYREJECTED; + if (verify) { + /* Verify signature at end of transcript against leaf key */ + rc = spdm_verify_signature(spdm_state, spdm_context); + if (rc) + dev_err(spdm_state->dev, + "Cannot verify challenge_auth signature: %d\n", + rc); + else + dev_info(spdm_state->dev, + "Authenticated with certificate slot %u\n", + slot); + } + + spdm_create_log_entry(spdm_state, spdm_context, slot, + req_nonce_off, rsp_nonce_off); + + return rc; +} + +/** + * spdm_authenticate() - Authenticate device + * + * @spdm_state: SPDM session state + * + * Authenticate a device through a sequence of GET_VERSION, GET_CAPABILITIES, + * NEGOTIATE_ALGORITHMS, GET_DIGESTS, GET_CERTIFICATE and CHALLENGE exchanges. + * + * Perform internal locking to serialize multiple concurrent invocations. + * Can be called repeatedly for reauthentication. + * + * Return 0 on success or a negative errno. In particular, -EPROTONOSUPPORT + * indicates authentication is not supported by the device. + */ +int spdm_authenticate(struct spdm_state *spdm_state) +{ + bool verify = false; + u8 slot; + int rc; + + mutex_lock(&spdm_state->lock); + spdm_reset(spdm_state); + + rc = spdm_alloc_transcript(spdm_state); + if (rc) + goto unlock; + + rc = spdm_get_version(spdm_state); + if (rc) + goto unlock; + + rc = spdm_get_capabilities(spdm_state); + if (rc) + goto unlock; + + rc = spdm_negotiate_algs(spdm_state); + if (rc) + goto unlock; + + rc = spdm_get_digests(spdm_state); + if (rc) + goto unlock; + + for_each_set_bit(slot, &spdm_state->provisioned_slots, SPDM_SLOTS) { + rc = spdm_get_certificate(spdm_state, slot); + if (rc) + goto unlock; + } + + for_each_set_bit(slot, &spdm_state->provisioned_slots, SPDM_SLOTS) { + rc = spdm_validate_cert_chain(spdm_state, slot); + if (rc == 0) { + verify = true; + break; + } + } + + /* + * If no cert chain validates, perform challenge-response with + * arbitrary slot to be able to expose a signature in sysfs + * about which user space can make up its own mind. + */ + if (rc) + slot = __ffs(spdm_state->provisioned_slots); + + rc = spdm_challenge(spdm_state, slot, verify); + +unlock: + if (rc) + spdm_reset(spdm_state); + spdm_state->authenticated = !rc; + spdm_free_transcript(spdm_state); + mutex_unlock(&spdm_state->lock); + return rc; +} +EXPORT_SYMBOL_GPL(spdm_authenticate); diff --git a/lib/spdm/req-sysfs.c b/lib/spdm/req-sysfs.c new file mode 100644 index 00000000000000..0f459f18d220c0 --- /dev/null +++ b/lib/spdm/req-sysfs.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Requester role: sysfs interface + * + * Copyright (C) 2023-24 Intel Corporation + */ + +#include "spdm.h" + +#include + +/** + * dev_to_spdm_state() - Retrieve SPDM session state for given device + * + * @dev: Responder device + * + * Returns a pointer to the device's SPDM session state, + * %NULL if the device doesn't have one or + * %ERR_PTR if it couldn't be determined whether SPDM is supported. + * + * In the %ERR_PTR case, attributes are visible but return an error on access. + * This prevents downgrade attacks where an attacker disturbs memory allocation + * or communication with the device in order to create the appearance that SPDM + * is unsupported. E.g. with PCI devices, the attacker may foil CMA or DOE + * initialization by simply hogging memory. + */ +static struct spdm_state *dev_to_spdm_state(struct device *dev) +{ + if (dev_is_pci(dev)) + return pci_dev_to_spdm_state(to_pci_dev(dev)); + + /* Insert mappers for further bus types here. */ + + return NULL; +} + +/* authenticated attribute */ + +static umode_t spdm_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + + if (!spdm_state) + return SYSFS_GROUP_INVISIBLE; + + return a->mode; +} + +static ssize_t authenticated_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + int rc; + + if (IS_ERR(spdm_state)) + return PTR_ERR(spdm_state); + + if (sysfs_streq(buf, "re")) { + rc = spdm_authenticate(spdm_state); + if (rc) + return rc; + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t authenticated_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + + if (IS_ERR(spdm_state)) + return PTR_ERR(spdm_state); + + return sysfs_emit(buf, "%u\n", spdm_state->authenticated); +} +static DEVICE_ATTR_RW(authenticated); + +static struct attribute *spdm_attrs[] = { + &dev_attr_authenticated.attr, + NULL +}; + +const struct attribute_group spdm_attr_group = { + .attrs = spdm_attrs, + .is_visible = spdm_attrs_are_visible, +}; + +/* certificates attributes */ + +static umode_t spdm_certificates_are_visible(struct kobject *kobj, + struct bin_attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + u8 slot = a->attr.name[4] - '0'; + + if (IS_ERR_OR_NULL(spdm_state)) + return SYSFS_GROUP_INVISIBLE; + + if (!(spdm_state->supported_slots & BIT(slot))) + return 0; + + return a->attr.mode; +} + +static ssize_t spdm_cert_read(struct file *file, struct kobject *kobj, + struct bin_attribute *a, char *buf, loff_t off, + size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + u8 slot = a->attr.name[4] - '0'; + size_t header_size, cert_size; + + /* + * Serialize with spdm_authenticate() as it may change hash_len, + * slot_sz[] and slot[] members in struct spdm_state. + */ + guard(mutex)(&spdm_state->lock); + + /* + * slot[] is prefixed by the 4 + H header per SPDM 1.0.0 table 15. + * The header is not exposed to user space, only the certificates are. + */ + header_size = sizeof(struct spdm_cert_chain) + spdm_state->hash_len; + cert_size = spdm_state->slot_sz[slot] - header_size; + + if (!spdm_state->slot[slot]) + return 0; + if (!count) + return 0; + if (off > cert_size) + return 0; + if (off + count > cert_size) + count = cert_size - off; + + memcpy(buf, (u8 *)spdm_state->slot[slot] + header_size + off, count); + return count; +} + +static BIN_ATTR(slot0, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot1, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot2, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot3, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot4, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot5, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot6, 0444, spdm_cert_read, NULL, 0xffff); +static BIN_ATTR(slot7, 0444, spdm_cert_read, NULL, 0xffff); + +static struct bin_attribute *spdm_certificates_bin_attrs[] = { + &bin_attr_slot0, + &bin_attr_slot1, + &bin_attr_slot2, + &bin_attr_slot3, + &bin_attr_slot4, + &bin_attr_slot5, + &bin_attr_slot6, + &bin_attr_slot7, + NULL +}; + +const struct attribute_group spdm_certificates_group = { + .name = "certificates", + .bin_attrs = spdm_certificates_bin_attrs, + .is_bin_visible = spdm_certificates_are_visible, +}; + +/* signatures attributes */ + +static umode_t spdm_signatures_are_visible(struct kobject *kobj, + struct bin_attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + + if (IS_ERR_OR_NULL(spdm_state)) + return SYSFS_GROUP_INVISIBLE; + + return a->attr.mode; +} + +static ssize_t next_requester_nonce_write(struct file *file, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct spdm_state *spdm_state = dev_to_spdm_state(dev); + + guard(mutex)(&spdm_state->lock); + + if (!spdm_state->next_nonce) { + spdm_state->next_nonce = kmalloc(SPDM_NONCE_SZ, GFP_KERNEL); + if (!spdm_state->next_nonce) + return -ENOMEM; + } + + memcpy(spdm_state->next_nonce + off, buf, count); + return count; +} +static BIN_ATTR_WO(next_requester_nonce, SPDM_NONCE_SZ); + +static struct bin_attribute *spdm_signatures_bin_attrs[] = { + &bin_attr_next_requester_nonce, + NULL +}; + +const struct attribute_group spdm_signatures_group = { + .name = "signatures", + .bin_attrs = spdm_signatures_bin_attrs, + .is_bin_visible = spdm_signatures_are_visible, +}; + +static unsigned int spdm_max_log_sz = SZ_16M; /* per device */ + +/** + * struct spdm_log_entry - log entry representing one received SPDM signature + * + * @list: List node. Added to the @log list in struct spdm_state. + * @sig: sysfs attribute of received signature (located at end of transcript). + * @req_nonce: sysfs attribute of requester nonce (located within transcript). + * @rsp_nonce: sysfs attribute of responder nonce (located within transcript). + * @transcript: sysfs attribute of transcript (concatenation of all SPDM + * messages exchanged during an authentication or measurement sequence) + * sans trailing signature (to simplify signature verification by user + * space). + * @combined_prefix: sysfs attribute of combined_spdm_prefix + * (SPDM 1.2.0 margin no 806, needed to verify signature). + * @spdm_context: sysfs attribute of spdm_context + * (SPDM 1.2.0 margin no 803, needed to create combined_spdm_prefix). + * @hash_alg: sysfs attribute of hash algorithm (needed to verify signature). + * @sig_name: Name of @sig attribute (with prepended signature counter). + * @req_nonce_name: Name of @req_nonce attribute. + * @rsp_nonce_name: Name of @rsp_nonce attribute. + * @transcript_name: Name of @transcript attribute. + * @combined_prefix_name: Name of @combined_prefix attribute. + * @spdm_context_name: Name of @spdm_context attribute. + * @hash_alg_name: Name of @hash_alg attribute. + * @counter: Signature counter (needed to create certificate_chain symlink). + * @version: Negotiated SPDM version + * (SPDM 1.2.0 margin no 803, needed to create combined_spdm_prefix). + * @slot: Slot which was used to generate the signature + * (needed to create certificate_chain symlink). + */ +struct spdm_log_entry { + struct list_head list; + struct bin_attribute sig; + struct bin_attribute req_nonce; + struct bin_attribute rsp_nonce; + struct bin_attribute transcript; + struct bin_attribute combined_prefix; + struct dev_ext_attribute spdm_context; + struct dev_ext_attribute hash_alg; + char sig_name[sizeof(__stringify(UINT_MAX) "_signature")]; + char req_nonce_name[sizeof(__stringify(UINT_MAX) "_requester_nonce")]; + char rsp_nonce_name[sizeof(__stringify(UINT_MAX) "_responder_nonce")]; + char transcript_name[sizeof(__stringify(UINT_MAX) "_transcript")]; + char combined_prefix_name[sizeof(__stringify(UINT_MAX) "_combined_spdm_prefix")]; + char spdm_context_name[sizeof(__stringify(UINT_MAX) "_type")]; + char hash_alg_name[sizeof(__stringify(UINT_MAX) "_hash_algorithm")]; + u32 counter; + u8 version; + u8 slot; +}; + +static void spdm_unpublish_log_entry(struct kobject *kobj, + struct spdm_log_entry *log) +{ + const char *group = spdm_signatures_group.name; + + sysfs_remove_bin_file_from_group(kobj, &log->sig, group); + sysfs_remove_bin_file_from_group(kobj, &log->req_nonce, group); + sysfs_remove_bin_file_from_group(kobj, &log->rsp_nonce, group); + sysfs_remove_bin_file_from_group(kobj, &log->transcript, group); + sysfs_remove_bin_file_from_group(kobj, &log->combined_prefix, group); + sysfs_remove_file_from_group(kobj, &log->spdm_context.attr.attr, group); + sysfs_remove_file_from_group(kobj, &log->hash_alg.attr.attr, group); + + char cert_chain[sizeof(__stringify(UINT_MAX) "_certificate_chain")]; + snprintf(cert_chain, sizeof(cert_chain), "%u_certificate_chain", + log->counter); + + sysfs_remove_link_from_group(kobj, group, cert_chain); +} + +static void spdm_publish_log_entry(struct kobject *kobj, + struct spdm_log_entry *log) +{ + const char *group = spdm_signatures_group.name; + int rc; + + rc = sysfs_add_bin_file_to_group(kobj, &log->sig, group); + if (rc) + goto err; + + rc = sysfs_add_bin_file_to_group(kobj, &log->req_nonce, group); + if (rc) + goto err; + + rc = sysfs_add_bin_file_to_group(kobj, &log->rsp_nonce, group); + if (rc) + goto err; + + rc = sysfs_add_bin_file_to_group(kobj, &log->transcript, group); + if (rc) + goto err; + + rc = sysfs_add_bin_file_to_group(kobj, &log->combined_prefix, group); + if (rc) + goto err; + + rc = sysfs_add_file_to_group(kobj, &log->spdm_context.attr.attr, group); + if (rc) + goto err; + + rc = sysfs_add_file_to_group(kobj, &log->hash_alg.attr.attr, group); + if (rc) + goto err; + + char cert_chain[sizeof(__stringify(UINT_MAX) "_certificate_chain")]; + snprintf(cert_chain, sizeof(cert_chain), "%u_certificate_chain", + log->counter); + + char slot[sizeof("slot0")]; + snprintf(slot, sizeof(slot), "slot%hhu", log->slot); + + rc = sysfs_add_link_to_sibling_group(kobj, group, cert_chain, + spdm_certificates_group.name, + slot); + if (rc) + goto err; + + return; + +err: + dev_err(kobj_to_dev(kobj), + "Failed to publish signature log entry in sysfs: %d\n", rc); + spdm_unpublish_log_entry(kobj, log); +} + +static ssize_t spdm_read_combined_prefix(struct file *file, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct spdm_log_entry *log = attr->private; + + /* + * SPDM 1.0 and 1.1 do not add a combined prefix to the hash + * before computing the signature, so return an empty file. + */ + if (log->version <= 0x11) + return 0; + + void *tmp __free(kfree) = kmalloc(SPDM_COMBINED_PREFIX_SZ, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + spdm_create_combined_prefix(log->version, log->spdm_context.var, tmp); + memcpy(buf, tmp + off, count); + return count; +} + +static void spdm_destroy_log_entry(struct spdm_state *spdm_state, + struct spdm_log_entry *log) +{ + spdm_state->log_sz -= log->transcript.size + log->sig.size + + sizeof(*log); + + list_del(&log->list); + kvfree(log->transcript.private); + kfree(log); +} + +static void spdm_shrink_log(struct spdm_state *spdm_state) +{ + while (spdm_state->log_sz > spdm_max_log_sz && + !list_is_singular(&spdm_state->log)) { + struct spdm_log_entry *log = + list_first_entry(&spdm_state->log, typeof(*log), list); + + if (device_is_registered(spdm_state->dev)) + spdm_unpublish_log_entry(&spdm_state->dev->kobj, log); + + spdm_destroy_log_entry(spdm_state, log); + } +} + +/** + * spdm_create_log_entry() - Allocate log entry for one received SPDM signature + * + * @spdm_state: SPDM session state + * @spdm_context: SPDM context (needed to create combined_spdm_prefix) + * @slot: Slot which was used to generate the signature + * (needed to create certificate_chain symlink) + * @req_nonce_off: Requester nonce offset within the transcript + * @rsp_nonce_off: Responder nonce offset within the transcript + * + * Allocate and populate a struct spdm_log_entry upon device authentication or + * measurement. Publish it in sysfs if the device has already been registered + * through device_add(). + */ +void spdm_create_log_entry(struct spdm_state *spdm_state, + const char *spdm_context, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off) +{ + struct spdm_log_entry *log = kmalloc(sizeof(*log), GFP_KERNEL); + if (!log) + return; + + *log = (struct spdm_log_entry) { + .slot = slot, + .version = spdm_state->version, + .counter = spdm_state->log_counter, + .list = LIST_HEAD_INIT(log->list), + + .sig = { + .attr.name = log->sig_name, + .attr.mode = 0444, + .read = sysfs_bin_attr_simple_read, + .private = spdm_state->transcript_end - + spdm_state->sig_len, + .size = spdm_state->sig_len }, + + .req_nonce = { + .attr.name = log->req_nonce_name, + .attr.mode = 0444, + .read = sysfs_bin_attr_simple_read, + .private = spdm_state->transcript + req_nonce_off, + .size = SPDM_NONCE_SZ }, + + .rsp_nonce = { + .attr.name = log->rsp_nonce_name, + .attr.mode = 0444, + .read = sysfs_bin_attr_simple_read, + .private = spdm_state->transcript + rsp_nonce_off, + .size = SPDM_NONCE_SZ }, + + .transcript = { + .attr.name = log->transcript_name, + .attr.mode = 0444, + .read = sysfs_bin_attr_simple_read, + .private = spdm_state->transcript, + .size = spdm_state->transcript_end - + spdm_state->transcript - + spdm_state->sig_len }, + + .combined_prefix = { + .attr.name = log->combined_prefix_name, + .attr.mode = 0444, + .read = spdm_read_combined_prefix, + .private = log, + .size = spdm_state->version <= 0x11 ? 0 : + SPDM_COMBINED_PREFIX_SZ }, + + .spdm_context = { + .attr.attr.name = log->spdm_context_name, + .attr.attr.mode = 0444, + .attr.show = device_show_string, + .var = (char *)spdm_context }, + + .hash_alg = { + .attr.attr.name = log->hash_alg_name, + .attr.attr.mode = 0444, + .attr.show = device_show_string, + .var = (char *)spdm_state->base_hash_alg_name }, + }; + + snprintf(log->sig_name, sizeof(log->sig_name), + "%u_signature", spdm_state->log_counter); + snprintf(log->req_nonce_name, sizeof(log->req_nonce_name), + "%u_requester_nonce", spdm_state->log_counter); + snprintf(log->rsp_nonce_name, sizeof(log->rsp_nonce_name), + "%u_responder_nonce", spdm_state->log_counter); + snprintf(log->transcript_name, sizeof(log->transcript_name), + "%u_transcript", spdm_state->log_counter); + snprintf(log->combined_prefix_name, sizeof(log->combined_prefix_name), + "%u_combined_spdm_prefix", spdm_state->log_counter); + snprintf(log->spdm_context_name, sizeof(log->spdm_context_name), + "%u_type", spdm_state->log_counter); + snprintf(log->hash_alg_name, sizeof(log->hash_alg_name), + "%u_hash_algorithm", spdm_state->log_counter); + + sysfs_bin_attr_init(&log->sig); + sysfs_bin_attr_init(&log->req_nonce); + sysfs_bin_attr_init(&log->rsp_nonce); + sysfs_bin_attr_init(&log->transcript); + sysfs_bin_attr_init(&log->combined_prefix); + sysfs_attr_init(&log->spdm_context.attr.attr); + sysfs_attr_init(&log->hash_alg.attr.attr); + + list_add_tail(&log->list, &spdm_state->log); + spdm_state->log_counter++; + spdm_state->log_sz += log->transcript.size + log->sig.size + + sizeof(*log); + + /* Purge oldest log entries if max log size is exceeded */ + spdm_shrink_log(spdm_state); + + /* Steal transcript pointer ahead of spdm_free_transcript() */ + spdm_state->transcript = NULL; + + if (device_is_registered(spdm_state->dev)) + spdm_publish_log_entry(&spdm_state->dev->kobj, log); +} + +/** + * spdm_publish_log() - Publish log of received SPDM signatures in sysfs + * + * @spdm_state: SPDM session state + * + * sysfs attributes representing received SPDM signatures are not static, + * but created dynamically upon authentication or measurement. If a device + * was authenticated or measured before it became visible in sysfs, the + * attributes could not be created. This function retroactively creates + * those attributes in sysfs after the device has become visible through + * device_add(). + */ +void spdm_publish_log(struct spdm_state *spdm_state) +{ + struct kobject *kobj = &spdm_state->dev->kobj; + struct kernfs_node *grp_kn __free(kernfs_put); + struct spdm_log_entry *log; + + grp_kn = kernfs_find_and_get(kobj->sd, spdm_signatures_group.name); + if (WARN_ON(!grp_kn)) + return; + + mutex_lock(&spdm_state->lock); + list_for_each_entry(log, &spdm_state->log, list) { + struct kernfs_node *sig_kn __free(kernfs_put); + + /* + * Skip over log entries created in-between device_add() and + * spdm_publish_log() as they've already been published. + */ + sig_kn = kernfs_find_and_get(grp_kn, log->sig_name); + if (sig_kn) + continue; + + spdm_publish_log_entry(kobj, log); + } + mutex_unlock(&spdm_state->lock); +} +EXPORT_SYMBOL_GPL(spdm_publish_log); + +/** + * spdm_destroy_log() - Destroy log of received SPDM signatures + * + * @spdm_state: SPDM session state + * + * Be sure to unregister the device through device_del() beforehand, + * which implicitly unpublishes the log in sysfs. + */ +void spdm_destroy_log(struct spdm_state *spdm_state) +{ + struct spdm_log_entry *log, *tmp; + + list_for_each_entry_safe(log, tmp, &spdm_state->log, list) + spdm_destroy_log_entry(spdm_state, log); +} + +#ifdef CONFIG_SYSCTL +static int proc_max_log_sz(const struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + unsigned int old_max_log_sz = spdm_max_log_sz; + struct spdm_state *spdm_state; + int rc; + + rc = proc_douintvec_minmax(table, write, buffer, lenp, ppos); + if (rc) + return rc; + + /* Purge oldest log entries if max log size has been reduced */ + if (write && spdm_max_log_sz < old_max_log_sz) { + mutex_lock(&spdm_state_mutex); + list_for_each_entry(spdm_state, &spdm_state_list, list) { + mutex_lock(&spdm_state->lock); + spdm_shrink_log(spdm_state); + mutex_unlock(&spdm_state->lock); + } + mutex_unlock(&spdm_state_mutex); + } + + return 0; +} + +static struct ctl_table spdm_ctl_table[] = { + { + .procname = "max_signatures_size", + .data = &spdm_max_log_sz, + .maxlen = sizeof(spdm_max_log_sz), + .mode = 0644, + .proc_handler = proc_max_log_sz, + .extra1 = SYSCTL_ZERO, + /* + * 2 GiB limit avoids filename collision on + * wraparound of unsigned 32-bit log_counter + */ + .extra2 = SYSCTL_INT_MAX, + }, +}; + +static int __init spdm_init(void) +{ + register_sysctl_init("spdm", spdm_ctl_table); + return 0; +} +fs_initcall(spdm_init); +#endif /* CONFIG_SYSCTL */ diff --git a/lib/spdm/spdm.h b/lib/spdm/spdm.h new file mode 100644 index 00000000000000..16c18ceb43e727 --- /dev/null +++ b/lib/spdm/spdm.h @@ -0,0 +1,612 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Copyright (C) 2021-22 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#ifndef _LIB_SPDM_H_ +#define _LIB_SPDM_H_ + +#undef DEFAULT_SYMBOL_NAMESPACE +#define DEFAULT_SYMBOL_NAMESPACE SPDM + +#define dev_fmt(fmt) "SPDM: " fmt + +#include +#include +#include + +/* SPDM versions supported by this implementation */ +#define SPDM_MIN_VER 0x10 +#define SPDM_MAX_VER 0x13 + +/* SPDM capabilities (SPDM 1.1.0 margin no 177, 178) */ +#define SPDM_CACHE_CAP BIT(0) /* 1.0 resp only */ +#define SPDM_CERT_CAP BIT(1) /* 1.0 */ +#define SPDM_CHAL_CAP BIT(2) /* 1.0 */ +#define SPDM_MEAS_CAP_MASK GENMASK(4, 3) /* 1.0 resp only */ +#define SPDM_MEAS_CAP_NO 0 /* 1.0 resp only */ +#define SPDM_MEAS_CAP_MEAS 1 /* 1.0 resp only */ +#define SPDM_MEAS_CAP_MEAS_SIG 2 /* 1.0 resp only */ +#define SPDM_MEAS_FRESH_CAP BIT(5) /* 1.0 resp only */ +#define SPDM_ENCRYPT_CAP BIT(6) /* 1.1 */ +#define SPDM_MAC_CAP BIT(7) /* 1.1 */ +#define SPDM_MUT_AUTH_CAP BIT(8) /* 1.1 */ +#define SPDM_KEY_EX_CAP BIT(9) /* 1.1 */ +#define SPDM_PSK_CAP_MASK GENMASK(11, 10) /* 1.1 */ +#define SPDM_PSK_CAP_NO 0 /* 1.1 */ +#define SPDM_PSK_CAP_PSK 1 /* 1.1 */ +#define SPDM_PSK_CAP_PSK_CTX 2 /* 1.1 resp only */ +#define SPDM_ENCAP_CAP BIT(12) /* 1.1 */ +#define SPDM_HBEAT_CAP BIT(13) /* 1.1 */ +#define SPDM_KEY_UPD_CAP BIT(14) /* 1.1 */ +#define SPDM_HANDSHAKE_ITC_CAP BIT(15) /* 1.1 */ +#define SPDM_PUB_KEY_ID_CAP BIT(16) /* 1.1 */ +#define SPDM_CHUNK_CAP BIT(17) /* 1.2 */ +#define SPDM_ALIAS_CERT_CAP BIT(18) /* 1.2 resp only */ +#define SPDM_SET_CERT_CAP BIT(19) /* 1.2 resp only */ +#define SPDM_CSR_CAP BIT(20) /* 1.2 resp only */ +#define SPDM_CERT_INST_RESET_CAP BIT(21) /* 1.2 resp only */ +#define SPDM_EP_INFO_CAP_MASK GENMASK(23, 22) /* 1.3 */ +#define SPDM_EP_INFO_CAP_NO 0 /* 1.3 */ +#define SPDM_EP_INFO_CAP_RSP 1 /* 1.3 */ +#define SPDM_EP_INFO_CAP_RSP_SIG 2 /* 1.3 */ +#define SPDM_MEL_CAP BIT(24) /* 1.3 resp only */ +#define SPDM_EVENT_CAP BIT(25) /* 1.3 */ +#define SPDM_MULTI_KEY_CAP_MASK GENMASK(27, 26) /* 1.3 */ +#define SPDM_MULTI_KEY_CAP_NO 0 /* 1.3 */ +#define SPDM_MULTI_KEY_CAP_ONLY 1 /* 1.3 */ +#define SPDM_MULTI_KEY_CAP_SEL 2 /* 1.3 */ +#define SPDM_GET_KEY_PAIR_INFO_CAP BIT(28) /* 1.3 resp only */ +#define SPDM_SET_KEY_PAIR_INFO_CAP BIT(29) /* 1.3 resp only */ + +/* SPDM capabilities supported by this implementation */ +#define SPDM_REQ_CAPS (SPDM_CERT_CAP | SPDM_CHAL_CAP) + +/* SPDM capabilities required from responders */ +#define SPDM_RSP_MIN_CAPS (SPDM_CERT_CAP | SPDM_CHAL_CAP) + +/* + * SPDM cryptographic timeout of this implementation: + * Assume calculations may take up to 1 sec on a busy machine, which equals + * roughly 1 << 20. That's within the limits mandated for responders by CMA + * (1 << 23 usec, PCIe r6.2 sec 6.31.3) and DOE (1 sec, PCIe r6.2 sec 6.30.2). + * Used in GET_CAPABILITIES exchange. + */ +#define SPDM_CTEXPONENT 20 + +/* SPDM asymmetric key signature algorithms (SPDM 1.0.0 table 13) */ +#define SPDM_ASYM_RSASSA_2048 BIT(0) /* 1.0 */ +#define SPDM_ASYM_RSAPSS_2048 BIT(1) /* 1.0 */ +#define SPDM_ASYM_RSASSA_3072 BIT(2) /* 1.0 */ +#define SPDM_ASYM_RSAPSS_3072 BIT(3) /* 1.0 */ +#define SPDM_ASYM_ECDSA_ECC_NIST_P256 BIT(4) /* 1.0 */ +#define SPDM_ASYM_RSASSA_4096 BIT(5) /* 1.0 */ +#define SPDM_ASYM_RSAPSS_4096 BIT(6) /* 1.0 */ +#define SPDM_ASYM_ECDSA_ECC_NIST_P384 BIT(7) /* 1.0 */ +#define SPDM_ASYM_ECDSA_ECC_NIST_P521 BIT(8) /* 1.0 */ +#define SPDM_ASYM_SM2_ECC_SM2_P256 BIT(9) /* 1.2 */ +#define SPDM_ASYM_EDDSA_ED25519 BIT(10) /* 1.2 */ +#define SPDM_ASYM_EDDSA_ED448 BIT(11) /* 1.2 */ + +/* SPDM hash algorithms (SPDM 1.0.0 table 13) */ +#define SPDM_HASH_SHA_256 BIT(0) /* 1.0 */ +#define SPDM_HASH_SHA_384 BIT(1) /* 1.0 */ +#define SPDM_HASH_SHA_512 BIT(2) /* 1.0 */ +#define SPDM_HASH_SHA3_256 BIT(3) /* 1.0 */ +#define SPDM_HASH_SHA3_384 BIT(4) /* 1.0 */ +#define SPDM_HASH_SHA3_512 BIT(5) /* 1.0 */ +#define SPDM_HASH_SM3_256 BIT(6) /* 1.2 */ + +/* SPDM measurement specifications (SPDM 1.0.0 sec 4.10.1.3) */ +#define SPDM_MEAS_SPEC_DMTF BIT(0) /* 1.0 */ + +/* SPDM measurement hash algorithms (SPDM 1.0.0 table 14) */ +#define SPDM_MEAS_HASH_RAW BIT(0) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA_256 BIT(1) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA_384 BIT(2) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA_512 BIT(3) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA3_256 BIT(4) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA3_384 BIT(5) /* 1.0 */ +#define SPDM_MEAS_HASH_SHA3_512 BIT(6) /* 1.0 */ +#define SPDM_MEAS_HASH_SM3_257 BIT(7) /* 1.2 */ + +/* SPDM Diffie-Hellman Ephemeral groups (SPDM 1.1.0 margin no 189) */ +#define SPDM_REQ_ALG_STRUCT_DHE 2 /* 1.1 */ +#define SPDM_DHE_FFDHE_2048 BIT(0) /* 1.1 */ +#define SPDM_DHE_FFDHE_3072 BIT(1) /* 1.1 */ +#define SPDM_DHE_FFDHE_4096 BIT(2) /* 1.1 */ +#define SPDM_DHE_SECP_256R1 BIT(3) /* 1.1 */ +#define SPDM_DHE_SECP_384R1 BIT(4) /* 1.1 */ +#define SPDM_DHE_SECP_521R1 BIT(5) /* 1.1 */ +#define SPDM_DHE_SM2_P256 BIT(6) /* 1.2 */ + +/* SPDM Authenticated Encryption w/ AD algorithms (SPDM 1.1.0 margin no 190) */ +#define SPDM_REQ_ALG_STRUCT_AEAD 3 /* 1.1 */ +#define SPDM_AEAD_AES_128_GCM BIT(0) /* 1.1 */ +#define SPDM_AEAD_AES_256_GCM BIT(1) /* 1.1 */ +#define SPDM_AEAD_CHACHA20_POLY1305 BIT(2) /* 1.1 */ +#define SPDM_AEAD_SM4_GCM BIT(3) /* 1.2 */ + +/* SPDM asymmetric key signature algorithms (SPDM 1.1.0 margin no 191) */ +#define SPDM_REQ_ALG_STRUCT_REQ_BASE_ASYM_ALG 4 /* 1.1 */ + +/* SPDM key schedule algorithms (SPDM 1.1.0 margin no 192) */ +#define SPDM_REQ_ALG_STRUCT_KEY_SCHEDULE 5 /* 1.1 */ +#define SPDM_KEY_SCHEDULE_SPDM BIT(0) /* 1.1 */ + +/* SPDM opaque data formats (SPDM 1.2.0 margin no 261) */ +#define SPDM_OPAQUE_DATA_FMT_VENDOR BIT(0) /* 1.2 */ +#define SPDM_OPAQUE_DATA_FMT_GENERAL BIT(1) /* 1.2 */ + +#if IS_ENABLED(CONFIG_CRYPTO_RSA) +#define SPDM_ASYM_RSA SPDM_ASYM_RSASSA_2048 | \ + SPDM_ASYM_RSASSA_3072 | \ + SPDM_ASYM_RSASSA_4096 +#else +#define SPDM_ASYM_RSA 0 +#endif + +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +#define SPDM_ASYM_ECDSA SPDM_ASYM_ECDSA_ECC_NIST_P256 | \ + SPDM_ASYM_ECDSA_ECC_NIST_P384 | \ + SPDM_ASYM_ECDSA_ECC_NIST_P521 +#else +#define SPDM_ASYM_ECDSA 0 +#endif + +#if IS_ENABLED(CONFIG_CRYPTO_SHA256) +#define SPDM_HASH_SHA2_256 SPDM_HASH_SHA_256 +#else +#define SPDM_HASH_SHA2_256 0 +#endif + +#if IS_ENABLED(CONFIG_CRYPTO_SHA512) +#define SPDM_HASH_SHA2_384_512 SPDM_HASH_SHA_384 | \ + SPDM_HASH_SHA_512 +#else +#define SPDM_HASH_SHA2_384_512 0 +#endif + +/* SPDM algorithms supported by this implementation */ +#define SPDM_ASYM_ALGOS (SPDM_ASYM_RSA | \ + SPDM_ASYM_ECDSA) + +#define SPDM_HASH_ALGOS (SPDM_HASH_SHA2_256 | \ + SPDM_HASH_SHA2_384_512) + +#define SPDM_DHE_ALGOS (SPDM_DHE_FFDHE_2048 | \ + SPDM_DHE_FFDHE_3072 | \ + SPDM_DHE_SECP_256R1 | \ + SPDM_DHE_SECP_384R1) + +#define SPDM_AEAD_ALGOS (SPDM_AEAD_AES_256_GCM | \ + SPDM_AEAD_CHACHA20_POLY1305) + +/* + * Common header shared by all messages. + * Note that the meaning of param1 and param2 is message dependent. + */ +struct spdm_header { + u8 version; + u8 code; /* RequestResponseCode */ + u8 param1; + u8 param2; +} __packed; + +#define SPDM_REQ 0x80 +#define SPDM_GET_VERSION 0x84 + +struct spdm_get_version_req { + u8 version; + u8 code; + u8 param1; + u8 param2; +} __packed; + +struct spdm_get_version_rsp { + u8 version; + u8 code; + u8 param1; + u8 param2; + + u8 reserved; + u8 version_number_entry_count; + __le16 version_number_entries[] __counted_by(version_number_entry_count); +} __packed; + +#define SPDM_GET_CAPABILITIES 0xe1 +#define SPDM_MIN_DATA_TRANSFER_SIZE 42 /* SPDM 1.2.0 margin no 226 */ + +/* + * Newer SPDM versions insert fields at the end of messages (enlarging them) + * or use reserved space for new fields (leaving message size unchanged). + */ +struct spdm_get_capabilities_req { + u8 version; + u8 code; + u8 param1; + u8 param2; + /* End of SPDM 1.0 structure */ + + u8 reserved1; /* 1.1 */ + u8 ctexponent; /* 1.1 */ + u16 reserved2; /* 1.1 */ + __le32 flags; /* 1.1 */ + /* End of SPDM 1.1 structure */ + + __le32 data_transfer_size; /* 1.2 */ + __le32 max_spdm_msg_size; /* 1.2 */ +} __packed; + +struct spdm_get_capabilities_rsp { + u8 version; + u8 code; + u8 param1; + u8 param2; + + u8 reserved1; + u8 ctexponent; + u16 reserved2; + __le32 flags; + /* End of SPDM 1.0 structure */ + + __le32 data_transfer_size; /* 1.2 */ + __le32 max_spdm_msg_size; /* 1.2 */ + /* End of SPDM 1.2 structure */ + + /* + * Additional optional fields at end of this structure: + * - SupportedAlgorithms: variable size * 1.3 * + */ +} __packed; + +#define SPDM_NEGOTIATE_ALGS 0xe3 + +struct spdm_negotiate_algs_req { + u8 version; + u8 code; + u8 param1; /* Number of ReqAlgStruct entries at end */ + u8 param2; + + __le16 length; + u8 measurement_specification; + u8 other_params_support; /* 1.2 */ + + __le32 base_asym_algo; + __le32 base_hash_algo; + + u8 reserved1[12]; + u8 ext_asym_count; + u8 ext_hash_count; + u8 reserved2; + u8 mel_specification; /* 1.3 */ + + /* + * Additional optional fields at end of this structure: + * - ExtAsym: 4 bytes * ext_asym_count + * - ExtHash: 4 bytes * ext_hash_count + * - ReqAlgStruct: variable size * param1 * 1.1 * + */ +} __packed; + +struct spdm_negotiate_algs_rsp { + u8 version; + u8 code; + u8 param1; /* Number of RespAlgStruct entries at end */ + u8 param2; + + __le16 length; + u8 measurement_specification_sel; + u8 other_params_sel; /* 1.2 */ + + __le32 measurement_hash_algo; + __le32 base_asym_sel; + __le32 base_hash_sel; + + u8 reserved1[11]; + u8 mel_specification_sel; /* 1.3 */ + u8 ext_asym_sel_count; /* Either 0 or 1 */ + u8 ext_hash_sel_count; /* Either 0 or 1 */ + u8 reserved2[2]; + + /* + * Additional optional fields at end of this structure: + * - ExtAsym: 4 bytes * ext_asym_count + * - ExtHash: 4 bytes * ext_hash_count + * - RespAlgStruct: variable size * param1 * 1.1 * + */ +} __packed; + +/* Maximum number of ReqAlgStructs sent by this implementation */ +#define SPDM_MAX_REQ_ALG_STRUCT 4 + +struct spdm_req_alg_struct { + u8 alg_type; + u8 alg_count; /* 0x2K where K is number of alg_external entries */ + __le16 alg_supported; /* Size is in alg_count[7:4], always 2 */ + __le32 alg_external[]; +} __packed; + +#define SPDM_GET_DIGESTS 0x81 + +struct spdm_get_digests_req { + u8 version; + u8 code; + u8 param1; /* Reserved */ + u8 param2; /* Reserved */ +} __packed; + +struct spdm_get_digests_rsp { + u8 version; + u8 code; + u8 param1; /* SupportedSlotMask */ /* 1.3 */ + u8 param2; /* ProvisionedSlotMask */ + u8 digests[]; /* Hash of struct spdm_cert_chain for each slot */ + /* End of SPDM 1.2 (and earlier) structure */ + + /* + * Additional optional fields at end of this structure: + * (omitted as long as we do not advertise MULTI_KEY_CAP) + * - KeyPairID: 1 byte for each slot * 1.3 * + * - CertificateInfo: 1 byte for each slot * 1.3 * + * - KeyUsageMask: 2 bytes for each slot * 1.3 * + */ +} __packed; + +#define SPDM_GET_CERTIFICATE 0x82 +#define SPDM_SLOTS 8 /* SPDM 1.0.0 section 4.9.2.1 */ + +struct spdm_get_certificate_req { + u8 version; + u8 code; + u8 param1; /* Slot number 0..7 */ + u8 param2; /* SlotSizeRequested */ /* 1.3 */ + __le16 offset; + __le16 length; +} __packed; + +struct spdm_get_certificate_rsp { + u8 version; + u8 code; + u8 param1; /* Slot number 0..7 */ + u8 param2; /* CertificateInfo */ /* 1.3 */ + __le16 portion_length; + __le16 remainder_length; + u8 cert_chain[]; /* PortionLength long */ +} __packed; + +struct spdm_cert_chain { + __le16 length; + u8 reserved[2]; + /* + * Additional fields at end of this structure: + * - RootHash: Digest of Root Certificate + * - Certificates: Chain of ASN.1 DER-encoded X.509 v3 certificates + */ +} __packed; + +#define SPDM_CHALLENGE 0x83 +#define SPDM_NONCE_SZ 32 /* SPDM 1.0.0 table 20 */ +#define SPDM_PREFIX_SZ 64 /* SPDM 1.2.0 margin no 803 */ +#define SPDM_COMBINED_PREFIX_SZ 100 /* SPDM 1.2.0 margin no 806 */ +#define SPDM_MAX_OPAQUE_DATA 1024 /* SPDM 1.0.0 table 21 */ + +struct spdm_challenge_req { + u8 version; + u8 code; + u8 param1; /* Slot number 0..7 */ + u8 param2; /* MeasurementSummaryHash type */ + u8 nonce[SPDM_NONCE_SZ]; + /* End of SPDM 1.2 (and earlier) structure */ + + u8 context[8]; /* 1.3 */ +} __packed; + +struct spdm_challenge_rsp { + u8 version; + u8 code; + u8 param1; /* Slot number 0..7 */ + u8 param2; /* Slot mask */ + /* + * Additional fields at end of this structure: + * - CertChainHash: Hash of struct spdm_cert_chain for selected slot + * - Nonce: 32 bytes long + * - MeasurementSummaryHash: Optional hash of selected measurements + * - OpaqueDataLength: 2 bytes long + * - OpaqueData: Up to 1024 bytes long + * - RequesterContext: 8 bytes long * 1.3 * + * (inserted, moves Signature field) + * - Signature + */ +} __packed; + +#define SPDM_ERROR 0x7f + +enum spdm_error_code { + SPDM_INVALID_REQUEST = 0x01, /* 1.0 */ + SPDM_INVALID_SESSION = 0x02, /* 1.1 only */ + SPDM_BUSY = 0x03, /* 1.0 */ + SPDM_UNEXPECTED_REQUEST = 0x04, /* 1.0 */ + SPDM_UNSPECIFIED = 0x05, /* 1.0 */ + SPDM_DECRYPT_ERROR = 0x06, /* 1.1 */ + SPDM_UNSUPPORTED_REQUEST = 0x07, /* 1.0 */ + SPDM_REQUEST_IN_FLIGHT = 0x08, /* 1.1 */ + SPDM_INVALID_RESPONSE_CODE = 0x09, /* 1.1 */ + SPDM_SESSION_LIMIT_EXCEEDED = 0x0a, /* 1.1 */ + SPDM_SESSION_REQUIRED = 0x0b, /* 1.2 */ + SPDM_RESET_REQUIRED = 0x0c, /* 1.2 */ + SPDM_RESPONSE_TOO_LARGE = 0x0d, /* 1.2 */ + SPDM_REQUEST_TOO_LARGE = 0x0e, /* 1.2 */ + SPDM_LARGE_RESPONSE = 0x0f, /* 1.2 */ + SPDM_MESSAGE_LOST = 0x10, /* 1.2 */ + SPDM_INVALID_POLICY = 0x11, /* 1.3 */ + SPDM_VERSION_MISMATCH = 0x41, /* 1.0 */ + SPDM_RESPONSE_NOT_READY = 0x42, /* 1.0 */ + SPDM_REQUEST_RESYNCH = 0x43, /* 1.0 */ + SPDM_OPERATION_FAILED = 0x44, /* 1.3 */ + SPDM_NO_PENDING_REQUESTS = 0x45, /* 1.3 */ + SPDM_VENDOR_DEFINED_ERROR = 0xff, /* 1.0 */ +}; + +struct spdm_error_rsp { + u8 version; + u8 code; + enum spdm_error_code error_code:8; + u8 error_data; + + u8 extended_error_data[]; +} __packed; + +/** + * struct spdm_state - SPDM session state + * + * @dev: Responder device. Used for error reporting and passed to @transport. + * Attributes in sysfs appear below this device's directory. + * @lock: Serializes multiple concurrent spdm_authenticate() calls. + * @list: List node. Added to spdm_state_list. Used to iterate over all + * SPDM-capable devices when a global sysctl parameter is changed. + * @authenticated: Whether device was authenticated successfully. + * @dev: Responder device. Used for error reporting and passed to @transport. + * @transport: Transport function to perform one message exchange. + * @transport_priv: Transport private data. + * @transport_sz: Maximum message size the transport is capable of (in bytes). + * Used as DataTransferSize in GET_CAPABILITIES exchange. + * @version: Maximum common supported version of requester and responder. + * Negotiated during GET_VERSION exchange. + * @rsp_caps: Cached capabilities of responder. + * Received during GET_CAPABILITIES exchange. + * @base_asym_alg: Asymmetric key algorithm for signature verification of + * CHALLENGE_AUTH and MEASUREMENTS messages. + * Selected by responder during NEGOTIATE_ALGORITHMS exchange. + * @base_hash_alg: Hash algorithm for signature verification of + * CHALLENGE_AUTH and MEASUREMENTS messages. + * Selected by responder during NEGOTIATE_ALGORITHMS exchange. + * @meas_hash_alg: Hash algorithm for measurement blocks. + * Selected by responder during NEGOTIATE_ALGORITHMS exchange. + * @supported_slots: Bitmask of responder's supported certificate slots. + * Received during GET_DIGESTS exchange (from SPDM 1.3). + * @provisioned_slots: Bitmask of responder's provisioned certificate slots. + * Received during GET_DIGESTS exchange. + * @base_asym_enc: Human-readable name of @base_asym_alg's signature encoding. + * Passed to crypto subsystem when calling verify_signature(). + * @sig_len: Signature length of @base_asym_alg (in bytes). + * S or SigLen in SPDM specification. + * @base_hash_alg_name: Human-readable name of @base_hash_alg. + * Passed to crypto subsystem when calling crypto_alloc_shash() and + * verify_signature(). + * @shash: Synchronous hash handle for @base_hash_alg computation. + * @desc: Synchronous hash context for @base_hash_alg computation. + * @hash_len: Hash length of @base_hash_alg (in bytes). + * H in SPDM specification. + * @slot: Certificate chain in each of the 8 slots. NULL pointer if a slot is + * not populated. Prefixed by the 4 + H header per SPDM 1.0.0 table 15. + * @slot_sz: Certificate chain size (in bytes). + * @leaf_key: Public key portion of leaf certificate against which to check + * responder's signatures. + * @root_keyring: Keyring against which to check the first certificate in + * responder's certificate chain. + * @validate: Function to validate additional leaf certificate requirements. + * @transcript: Concatenation of all SPDM messages exchanged during an + * authentication or measurement sequence. Used to verify the signature, + * as it is computed over the hashed transcript. + * @transcript_end: Pointer into the @transcript buffer. Marks the current + * end of transcript. If another message is transmitted, it is appended + * at this position. + * @transcript_max: Allocation size of @transcript. Multiple of PAGE_SIZE. + * @log: Linked list of past authentication events. Each list entry is of type + * struct spdm_log_entry and is exposed as several files in sysfs. + * @log_sz: Memory occupied by @log (in bytes) to enforce the limit set by + * spdm_max_log_sz. Includes, for every entry, the struct spdm_log_entry + * itself and the transcript with trailing signature. + * @log_counter: Number of generated log entries so far. Will be prefixed to + * the sysfs files of the next generated log entry. + * @next_nonce: Requester nonce to be used for the next authentication + * sequence. Populated from user space through sysfs. + * If user space does not provide a nonce, the kernel uses a random one. + */ +struct spdm_state { + struct device *dev; + struct mutex lock; + struct list_head list; + unsigned int authenticated:1; + + /* Transport */ + spdm_transport *transport; + void *transport_priv; + u32 transport_sz; + + /* Negotiated state */ + u8 version; + u32 rsp_caps; + u32 base_asym_alg; + u32 base_hash_alg; + u32 meas_hash_alg; + unsigned long supported_slots; + unsigned long provisioned_slots; + + /* Signature algorithm */ + const char *base_asym_enc; + size_t sig_len; + + /* Hash algorithm */ + const char *base_hash_alg_name; + struct crypto_shash *shash; + struct shash_desc *desc; + size_t hash_len; + + /* Certificates */ + struct spdm_cert_chain *slot[SPDM_SLOTS]; + size_t slot_sz[SPDM_SLOTS]; + struct public_key *leaf_key; + struct key *root_keyring; + spdm_validate *validate; + + /* Transcript */ + void *transcript; + void *transcript_end; + size_t transcript_max; + + /* Signatures Log */ + struct list_head log; + size_t log_sz; + u32 log_counter; + u8 *next_nonce; +}; + +extern struct list_head spdm_state_list; +extern struct mutex spdm_state_mutex; + +ssize_t spdm_exchange(struct spdm_state *spdm_state, + void *req, size_t req_sz, void *rsp, size_t rsp_sz); + +int spdm_alloc_transcript(struct spdm_state *spdm_state); +void spdm_free_transcript(struct spdm_state *spdm_state); +int spdm_append_transcript(struct spdm_state *spdm_state, + const void *msg, size_t msg_sz); + +void spdm_create_combined_prefix(u8 version, const char *spdm_context, + void *buf); +int spdm_verify_signature(struct spdm_state *spdm_state, + const char *spdm_context); + +void spdm_reset(struct spdm_state *spdm_state); + +#ifdef CONFIG_SYSFS +void spdm_create_log_entry(struct spdm_state *spdm_state, + const char *spdm_context, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off); +void spdm_destroy_log(struct spdm_state *spdm_state); +#else +static inline void spdm_create_log_entry(struct spdm_state *spdm_state, + const char *spdm_context, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off) { } +static inline void spdm_destroy_log(struct spdm_state *spdm_state) { } +#endif + +#endif /* _LIB_SPDM_H_ */ diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 06132cf47016da..34ea02addb70b2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -1114,7 +1114,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); #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 * * 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 * 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 * avoid the verification loop. * @@ -1136,7 +1136,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); */ 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 0;