1diff --git a/kernel-open/conftest.sh b/kernel-open/conftest.sh
2index fdceda72..3bfe39aa 100755
3--- a/kernel-open/conftest.sh
4+++ b/kernel-open/conftest.sh
5@@ -6721,6 +6721,47 @@ compile_test() {
6 compile_check_conftest "$CODE" "NV_CRYPTO_PRESENT" "" "symbols"
7 ;;
8
9+ crypto_akcipher_verify)
10+ #
11+ # Determine whether the crypto_akcipher_verify API is still present.
12+ # It was removed by commit 6b34562 ('crypto: akcipher - Drop sign/verify operations')
13+ # in v6.13-rc1 (2024-10-04).
14+ #
15+ # This test is dependent on the crypto conftest to determine whether crypto should be
16+ # enabled at all. That means that if the kernel is old enough such that crypto_akcipher_verify
17+ #
18+ # The test merely checks for the presence of the API, as it assumes that if the API
19+ # is no longer present, the new API to replace it (crypto_sig_verify) must be present.
20+ # If the kernel version is too old to have crypto_akcipher_verify, it will fail the crypto
21+ # conftest above and all crypto code will be compiled out.
22+ #
23+ CODE="
24+ #include <crypto/akcipher.h>
25+ #include <linux/crypto.h>
26+ void conftest_crypto_akcipher_verify(void) {
27+ (void)crypto_akcipher_verify;
28+ }"
29+
30+ compile_check_conftest "$CODE" "NV_CRYPTO_AKCIPHER_VERIFY_PRESENT" "" "symbols"
31+ ;;
32+
33+ ecc_digits_from_bytes)
34+ #
35+ # Determine whether ecc_digits_from_bytes is present.
36+ # It was added in commit c6ab5c915da4 ('crypto: ecc - Prevent ecc_digits_from_bytes from
37+ # reading too many bytes') in v6.10.
38+ #
39+ # This functionality is needed when crypto_akcipher_verify is not present.
40+ #
41+ CODE="
42+ #include <crypto/internal/ecc.h>
43+ void conftest_ecc_digits_from_bytes(void) {
44+ (void)ecc_digits_from_bytes;
45+ }"
46+
47+ compile_check_conftest "$CODE" "NV_ECC_DIGITS_FROM_BYTES_PRESENT" "" "symbols"
48+ ;;
49+
50 mempolicy_has_unified_nodes)
51 #
52 # Determine if the 'mempolicy' structure has
53diff --git a/kernel-open/nvidia/internal_crypt_lib.h b/kernel-open/nvidia/internal_crypt_lib.h
54index 2eac7d5e..917acb26 100644
55--- a/kernel-open/nvidia/internal_crypt_lib.h
56+++ b/kernel-open/nvidia/internal_crypt_lib.h
57@@ -64,7 +64,9 @@
58 * old or even just user disabled. If we should use LKCA, include headers, else
59 * define stubs to return errors.
60 */
61-#if defined(NV_CRYPTO_PRESENT) && defined (NV_CONFIG_CRYPTO_PRESENT)
62+#if defined(NV_CRYPTO_PRESENT) && defined (NV_CONFIG_CRYPTO_PRESENT) && \
63+ (defined(NV_CRYPTO_AKCIPHER_VERIFY_PRESENT) || \
64+ (defined(NV_CRYPTO_SIG_H_PRESENT) && defined(NV_ECC_DIGITS_FROM_BYTES_PRESENT)))
65 #define USE_LKCA 1
66 #endif
67
68diff --git a/kernel-open/nvidia/libspdm_ecc.c b/kernel-open/nvidia/libspdm_ecc.c
69index 1f8f0100..a9eb4db5 100644
70--- a/kernel-open/nvidia/libspdm_ecc.c
71+++ b/kernel-open/nvidia/libspdm_ecc.c
72@@ -30,14 +30,26 @@ MODULE_SOFTDEP("pre: ecdh_generic,ecdsa_generic");
73 #include <crypto/akcipher.h>
74 #include <crypto/ecdh.h>
75 #include <crypto/internal/ecc.h>
76+#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
77+#include <crypto/sig.h>
78+
79+struct signature
80+{
81+ u64 r[ECC_MAX_DIGITS];
82+ u64 s[ECC_MAX_DIGITS];
83+};
84+#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
85+
86+#define ECDSA_PUBKEY_HEADER_XY_PRESENT (0x4)
87
88 struct ecc_ctx {
89 unsigned int curve_id;
90 u64 priv_key[ECC_MAX_DIGITS]; // In big endian
91
92 struct {
93- // ecdsa wants byte preceding pub_key to be set to '4'
94- u64 pub_key_prefix;
95+ // ecdsa pubkey has header indicating length of pubkey
96+ u8 padding[7];
97+ u8 pub_key_prefix;
98 u64 pub_key[2 * ECC_MAX_DIGITS];
99 };
100
101@@ -221,25 +233,84 @@ bool lkca_ec_compute_key(void *ec_context, const uint8_t *peer_public,
102 #endif
103 }
104
105-bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
106- const uint8_t *message_hash, size_t hash_size,
107- const uint8_t *signature, size_t sig_size)
108+#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
109+static bool lkca_ecdsa_verify_crypto_sig(void *ec_context, size_t hash_nid,
110+ const uint8_t *message_hash, size_t hash_size,
111+ const uint8_t *signature, size_t sig_size)
112 {
113 #ifndef USE_LKCA
114 return false;
115 #else
116 struct ecc_ctx *ctx = ec_context;
117+ u8 *pub_key;
118+ int err;
119+ DECLARE_CRYPTO_WAIT(wait);
120+ struct crypto_sig * tfm = NULL;
121+ struct signature sig;
122+
123+ if (sig_size != ctx->size || !ctx->pub_key_set)
124+ {
125+ return false;
126+ }
127+
128+ tfm = crypto_alloc_sig(ctx->name, CRYPTO_ALG_TYPE_SIG, 0);
129+ if (IS_ERR(tfm)) {
130+ pr_info("crypto_alloc_sig failed in lkca_ecdsa_verify\n");
131+ return false;
132+ }
133+
134+ // modify header of pubkey to indicate size
135+ pub_key = (u8 *) &(ctx->pub_key_prefix);
136+ *pub_key = ECDSA_PUBKEY_HEADER_XY_PRESENT;
137+ err = crypto_sig_set_pubkey(tfm, pub_key, ctx->size + 1);
138+ if (err != 0)
139+ {
140+ pr_info("crypto_sig_set_pubkey failed in lkca_ecdsa_verify: %d", -err);
141+ goto failTfm;
142+ }
143+
144+ //
145+ // Compared to the way we receive the signature, we need to:
146+ // - swap order of all digits
147+ // - swap endianness for each digit
148+ //
149+ memset(&sig, 0, sizeof(sig));
150+ ecc_digits_from_bytes(signature, ctx->size/2, sig.r, ECC_MAX_DIGITS);
151+ ecc_digits_from_bytes(signature + ctx->size/2, ctx->size/2, sig.s, ECC_MAX_DIGITS);
152+
153+ err = crypto_sig_verify(tfm, (void *)&sig, sizeof(sig), message_hash, hash_size);
154+ if (err != 0)
155+ {
156+ pr_info("crypto_sig_verify failed in lkca_ecdsa_verify %d\n", -err);
157+ }
158+
159+failTfm:
160+ crypto_free_sig(tfm);
161+
162+ return err == 0;
163+#endif // USE_LKCA
164+}
165+
166+#else // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
167+static bool lkca_ecdsa_verify_akcipher(void *ec_context, size_t hash_nid,
168+ const uint8_t *message_hash, size_t hash_size,
169+ const uint8_t *signature, size_t sig_size)
170+{
171+#ifndef USE_LKCA
172+ return false;
173+#else // USE_LKCA
174+ struct ecc_ctx *ctx = ec_context;
175+ u8 *pub_key;
176+ int err;
177+ DECLARE_CRYPTO_WAIT(wait);
178
179 // Roundabout way
180 u64 ber_max_len = 3 + 2 * (4 + (ECC_MAX_BYTES));
181 u64 ber_len = 0;
182 u8 *ber = NULL;
183- u8 *pub_key;
184 struct akcipher_request *req = NULL;
185 struct crypto_akcipher *tfm = NULL;
186 struct scatterlist sg;
187- DECLARE_CRYPTO_WAIT(wait);
188- int err;
189
190 if (sig_size != ctx->size) {
191 return false;
192@@ -251,21 +322,21 @@ bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
193
194 tfm = crypto_alloc_akcipher(ctx->name, CRYPTO_ALG_TYPE_AKCIPHER, 0);
195 if (IS_ERR(tfm)) {
196- pr_info("ALLOC FAILED\n");
197+ pr_info("crypto_alloc_akcipher failed in lkca_ecdsa_verify\n");
198 return false;
199 }
200
201- pub_key = (u8 *) ctx->pub_key;
202- pub_key--; // Go back into byte of pub_key_prefix
203- *pub_key = 4; // And set it to 4 to placate kernel
204+ // modify header of pubkey to indicate size
205+ pub_key = (u8 *) &(ctx->pub_key_prefix);
206+ *pub_key = ECDSA_PUBKEY_HEADER_XY_PRESENT;
207 if ((err = crypto_akcipher_set_pub_key(tfm, pub_key, ctx->size + 1)) != 0) {
208- pr_info("SET PUB KEY FAILED: %d\n", -err);
209+ pr_info("crypto_akcipher_set_pub_key failed in lkca_ecdsa_verify: %d\n", -err);
210 goto failTfm;
211 }
212
213 req = akcipher_request_alloc(tfm, GFP_KERNEL);
214 if (IS_ERR(req)) {
215- pr_info("REQUEST ALLOC FAILED\n");
216+ pr_info("akcipher_request_alloc failed in lkca_ecdsa_verify\n");
217 goto failTfm;
218 }
219
220@@ -310,9 +381,8 @@ bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
221 CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait);
222 akcipher_request_set_crypt(req, &sg, NULL, ber_len, hash_size);
223 err = crypto_wait_req(crypto_akcipher_verify(req), &wait);
224-
225 if (err != 0){
226- pr_info("Verify FAILED %d\n", -err);
227+ pr_info("crypto_akcipher_verify failed in lkca_ecdsa_verify %d\n", -err);
228 }
229
230 kfree(ber);
231@@ -322,5 +392,19 @@ failTfm:
232 crypto_free_akcipher(tfm);
233
234 return err == 0;
235-#endif
236+#endif // USE_LKCA
237+}
238+#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
239+
240+bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
241+ const uint8_t *message_hash, size_t hash_size,
242+ const uint8_t *signature, size_t sig_size)
243+{
244+#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
245+ return lkca_ecdsa_verify_crypto_sig(ec_context, hash_nid, message_hash, hash_size,
246+ signature, sig_size);
247+#else // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
248+ return lkca_ecdsa_verify_akcipher(ec_context, hash_nid, message_hash, hash_size,
249+ signature, sig_size);
250+#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
251 }