1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Crypto Component                                                 */
17 /**                                                                       */
18 /**   Elliptic Curve Digital Signature Algorithm (ECDSA)                  */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #include "nx_crypto_ecdsa.h"
24 
25 
26 /**************************************************************************/
27 /*                                                                        */
28 /*  FUNCTION                                               RELEASE        */
29 /*                                                                        */
30 /*    _nx_crypto_ecdsa_sign                               PORTABLE C      */
31 /*                                                           6.1          */
32 /*  AUTHOR                                                                */
33 /*                                                                        */
34 /*    Timothy Stapko, Microsoft Corporation                               */
35 /*                                                                        */
36 /*  DESCRIPTION                                                           */
37 /*                                                                        */
38 /*    This function computes a signature of the hash data using the       */
39 /*    private key.                                                        */
40 /*                                                                        */
41 /*                                                                        */
42 /*  INPUT                                                                 */
43 /*                                                                        */
44 /*    curve                                 Curve used in the ECDSA       */
45 /*    hash                                  Hash data to be signed        */
46 /*    hash_length                           Length of hash data           */
47 /*    private_key                           Pointer to EC private key     */
48 /*    signature                             Pointer to signature output   */
49 /*    scratch                               Pointer to scratch buffer.    */
50 /*                                            This scratch buffer can be  */
51 /*                                            reused after this function  */
52 /*                                            returns.                    */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    status                                Completion status             */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _nx_crypto_ec_key_pair_generation_extra                             */
61 /*                                          Generate EC Key Pair          */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    Application Code                                                    */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
72 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
73 /*                                            verified memmove use cases, */
74 /*                                            resulting in version 6.1    */
75 /*                                                                        */
76 /**************************************************************************/
_nx_crypto_ecdsa_sign(NX_CRYPTO_EC * curve,UCHAR * hash,UINT hash_length,UCHAR * private_key,UINT private_key_length,UCHAR * signature,ULONG signature_length,ULONG * actual_signature_length,HN_UBASE * scratch)77 NX_CRYPTO_KEEP UINT _nx_crypto_ecdsa_sign(NX_CRYPTO_EC *curve, UCHAR *hash, UINT hash_length,
78                                           UCHAR *private_key, UINT private_key_length,
79                                           UCHAR *signature, ULONG signature_length,
80                                           ULONG *actual_signature_length, HN_UBASE *scratch)
81 {
82 UINT                  status;
83 NX_CRYPTO_HUGE_NUMBER privkey;
84 NX_CRYPTO_HUGE_NUMBER z;
85 NX_CRYPTO_HUGE_NUMBER k;
86 NX_CRYPTO_HUGE_NUMBER ik;
87 NX_CRYPTO_HUGE_NUMBER temp;
88 NX_CRYPTO_EC_POINT    pt;
89 UINT                  buffer_size = curve -> nx_crypto_ec_n.nx_crypto_huge_buffer_size;
90 UINT                  i;
91 UINT                  curve_size;
92 UINT                  r_size;
93 UINT                  s_size;
94 UCHAR                 pad_zero_r;
95 UCHAR                 pad_zero_s;
96 UINT                  sequence_size;
97 UCHAR                *signature_r;
98 UCHAR                *signature_s;
99 
100     /* Signature format follows ASN1 DER encoding as per RFC 4492, section 5.8:
101      * Size: 1   | 1 or 2 | 1   |   1   | 0 or 1 | N |  1  |  1   | 0 or 1 | M
102      * Data: SEQ |  Size  | INT |  Size | 0x00   | r | INT | Size | 0x00   | s  */
103 
104     curve_size = curve -> nx_crypto_ec_bits >> 3;
105     if (curve -> nx_crypto_ec_bits & 7)
106     {
107         curve_size++;
108     }
109 
110     /* Check the signature_length for worst case. */
111     if (signature_length < ((curve_size << 1) + 9))
112     {
113         return(NX_CRYPTO_SIZE_ERROR);
114     }
115 
116     if (private_key_length > buffer_size)
117     {
118         return(NX_CRYPTO_SIZE_ERROR);
119     }
120 
121     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&privkey, scratch, buffer_size);
122     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&z, scratch, buffer_size);
123     /* Initialize per-message secret k buffer with 64 bits more buffer size. */
124     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&k, scratch, buffer_size + 8);
125     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&ik, scratch, buffer_size);
126     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&temp, scratch, buffer_size * 2);
127     NX_CRYPTO_EC_POINT_INITIALIZE(&pt, NX_CRYPTO_EC_POINT_AFFINE, scratch, buffer_size);
128 
129     /* Copy the private key from the caller's buffer. */
130     status = _nx_crypto_huge_number_setup(&privkey, private_key, private_key_length);
131     if (status != NX_CRYPTO_SUCCESS)
132     {
133         return(status);
134     }
135 
136     /* Truncate the hash data to the size of group order. */
137     if (hash_length > buffer_size)
138     {
139         hash_length = buffer_size;
140     }
141 
142     status = _nx_crypto_huge_number_setup(&z, hash, hash_length);
143     if (status != NX_CRYPTO_SUCCESS)
144     {
145         return(status);
146     }
147 
148     /* The bit length of the hash data used is not longer than the group order. */
149     if (curve -> nx_crypto_ec_bits < hash_length << 3)
150     {
151         _nx_crypto_huge_number_shift_right(&z, (hash_length << 3) - curve -> nx_crypto_ec_bits);
152     }
153 
154     do
155     {
156         do
157         {
158             /* Generate Key Pair. */
159             _nx_crypto_ec_key_pair_generation_extra(curve, &curve -> nx_crypto_ec_g, &k, &pt,
160                                                     scratch);
161 
162             /* Calculate r = pt.x mod n */
163             _nx_crypto_huge_number_modulus(&pt.nx_crypto_ec_point_x, &curve -> nx_crypto_ec_n);
164 
165         } while (_nx_crypto_huge_number_is_zero(&pt.nx_crypto_ec_point_x));
166 
167         /* Calculate s = k^-1 * (z + r * private_key) */
168         _nx_crypto_huge_number_inverse_modulus(&k, &curve -> nx_crypto_ec_n, &ik, scratch);
169         _nx_crypto_huge_number_multiply(&pt.nx_crypto_ec_point_x, &privkey, &temp);
170         _nx_crypto_huge_number_add_unsigned(&temp, &z);
171         _nx_crypto_huge_number_modulus(&temp, &curve -> nx_crypto_ec_n);
172         NX_CRYPTO_HUGE_NUMBER_COPY(&k, &temp);
173         _nx_crypto_huge_number_multiply(&ik, &k, &temp);
174         _nx_crypto_huge_number_modulus(&temp, &curve -> nx_crypto_ec_n);
175 
176     } while (_nx_crypto_huge_number_is_zero(&temp));
177 
178     /* Output r and s as two INTEGER in ASN.1 encoding */
179     signature_r = signature + 3;
180     status = _nx_crypto_huge_number_extract(&pt.nx_crypto_ec_point_x, signature_r, (curve_size + 3), &r_size);
181     if (status != NX_CRYPTO_SUCCESS)
182     {
183         return(status);
184     }
185 
186     signature_s = signature + (curve_size + 6);
187     status = _nx_crypto_huge_number_extract(&temp, signature_s, (curve_size + 3), &s_size);
188     if (status != NX_CRYPTO_SUCCESS)
189     {
190         return(status);
191     }
192 
193     /* Trim prefix zeros. */
194     for (i = 0; i < r_size; i++)
195     {
196         if (signature_r[i])
197         {
198 
199             /* Loop until none zero byte. */
200             break;
201         }
202     }
203     signature_r += i;
204     r_size -= i;
205 
206     /* The most significant bit must be zero to indicate positive integer. */
207     /* Pad zero at the front if necessary. */
208     pad_zero_r = (signature_r[0] & 0x80) ? 1 : 0;
209 
210     for (i = 0; i < s_size; i++)
211     {
212         if (signature_s[i])
213         {
214 
215             /* Loop until none zero byte. */
216             break;
217         }
218     }
219     signature_s += i;
220     s_size -= i;
221 
222     /* The most significant bit must be zero to indicate positive integer. */
223     /* Pad zero at the front if necessary. */
224     pad_zero_s = (signature_s[0] & 0x80) ? 1 : 0;
225 
226     /* Size of sequence. */
227     sequence_size = r_size + pad_zero_r + s_size + pad_zero_s + 4;
228 
229     signature[0] = 0x30;    /* SEQUENCE */
230     if (sequence_size < 0x80)
231     {
232         signature[1] = (UCHAR)sequence_size;
233         signature += 2;
234         *actual_signature_length = sequence_size + 2;
235     }
236     else
237     {
238         signature[1] = 0x81;
239         signature[2] = (UCHAR)sequence_size;
240         signature += 3;
241         *actual_signature_length = sequence_size + 3;
242     }
243 
244     /* Setup r. */
245     NX_CRYPTO_MEMMOVE(&signature[2 + pad_zero_r], signature_r, r_size); /* Use case of memmove is verified. */
246     signature[0] = 0x02;    /* Integer */
247     signature[1] = (UCHAR)(r_size + pad_zero_r);
248     if (pad_zero_r)
249     {
250         signature[2] = 0;
251     }
252     signature += (2u + pad_zero_r + r_size);
253 
254     /* Setup s. */
255     NX_CRYPTO_MEMMOVE(&signature[2 + pad_zero_s], signature_s, s_size); /* Use case of memmove is verified. */
256     signature[0] = 0x02;    /* Integer */
257     signature[1] = (UCHAR)(s_size + pad_zero_s);
258     if (pad_zero_s)
259     {
260         signature[2] = 0;
261     }
262 
263     return NX_CRYPTO_SUCCESS;
264 }
265 
266 /**************************************************************************/
267 /*                                                                        */
268 /*  FUNCTION                                               RELEASE        */
269 /*                                                                        */
270 /*    _nx_crypto_ecdsa_verify                             PORTABLE C      */
271 /*                                                           6.1          */
272 /*  AUTHOR                                                                */
273 /*                                                                        */
274 /*    Timothy Stapko, Microsoft Corporation                               */
275 /*                                                                        */
276 /*  DESCRIPTION                                                           */
277 /*                                                                        */
278 /*    This function verifies the signature of the hash data using the     */
279 /*    public key.                                                         */
280 /*                                                                        */
281 /*  INPUT                                                                 */
282 /*                                                                        */
283 /*    curve                                 Curve used in the ECDSA       */
284 /*    hash                                  Hash data to be verified      */
285 /*    hash_length                           Length of hash data           */
286 /*    public_key                            Pointer to EC public key      */
287 /*    signature                             Signature to be verified      */
288 /*    scratch                               Pointer to scratch buffer.    */
289 /*                                            This scratch buffer can be  */
290 /*                                            reused after this function  */
291 /*                                            returns.                    */
292 /*                                                                        */
293 /*  OUTPUT                                                                */
294 /*                                                                        */
295 /*    status                                Completion status             */
296 /*                                                                        */
297 /*  CALLS                                                                 */
298 /*                                                                        */
299 /*    _nx_crypto_huge_number_setup          Generate private key          */
300 /*                                                                        */
301 /*  CALLED BY                                                             */
302 /*                                                                        */
303 /*    Application Code                                                    */
304 /*                                                                        */
305 /*  RELEASE HISTORY                                                       */
306 /*                                                                        */
307 /*    DATE              NAME                      DESCRIPTION             */
308 /*                                                                        */
309 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
310 /*  09-30-2020     Timothy Stapko           Modified comment(s), and      */
311 /*                                            fixed input validation,     */
312 /*                                            added public key validation,*/
313 /*                                            resulting in version 6.1    */
314 /*                                                                        */
315 /**************************************************************************/
_nx_crypto_ecdsa_verify(NX_CRYPTO_EC * curve,UCHAR * hash,UINT hash_length,UCHAR * public_key,UINT public_key_length,UCHAR * signature,UINT signature_length,HN_UBASE * scratch)316 NX_CRYPTO_KEEP UINT _nx_crypto_ecdsa_verify(NX_CRYPTO_EC *curve, UCHAR *hash, UINT hash_length,
317                                             UCHAR *public_key, UINT public_key_length,
318                                             UCHAR *signature, UINT signature_length, HN_UBASE *scratch)
319 {
320 UINT                  status;
321 NX_CRYPTO_HUGE_NUMBER r;
322 NX_CRYPTO_HUGE_NUMBER s;
323 NX_CRYPTO_HUGE_NUMBER z;
324 NX_CRYPTO_HUGE_NUMBER w;
325 NX_CRYPTO_HUGE_NUMBER u1;
326 NX_CRYPTO_HUGE_NUMBER u2;
327 NX_CRYPTO_EC_POINT    pubkey;
328 NX_CRYPTO_EC_POINT    pt;
329 NX_CRYPTO_EC_POINT    pt2;
330 UINT                  buffer_size = curve -> nx_crypto_ec_n.nx_crypto_huge_buffer_size;
331 
332     /* Signature format follows ASN1 DER encoding as per RFC 4492, section 5.8:
333      * Size: 1   | 1 or 2 | 1   |   1   | 0 or 1 | N |  1  |  1   | 0 or 1 | M
334      * Data: SEQ |  Size  | INT |  Size | 0x00   | r | INT | Size | 0x00   | s  */
335 
336 
337     if (public_key_length > 1 + (buffer_size << 1))
338     {
339         return(NX_CRYPTO_SIZE_ERROR);
340     }
341 
342     /* Buffer should contain the signature data sequence. */
343     if (signature[0] != 0x30)
344     {
345         return(NX_CRYPTO_AUTHENTICATION_FAILED);
346     }
347 
348     /* Check the size in SEQUENCE.  */
349     if (signature[1] & 0x80)
350     {
351         if (signature_length < (signature[2] + 3u))
352         {
353             return(NX_CRYPTO_SIZE_ERROR);
354         }
355         signature_length = signature[2];
356         signature += 3;
357     }
358     else
359     {
360         if (signature_length < (signature[1] + 2u))
361         {
362             return(NX_CRYPTO_SIZE_ERROR);
363         }
364         signature_length = signature[1];
365         signature += 2;
366     }
367 
368     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&r, scratch, buffer_size);
369     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&s, scratch, buffer_size);
370     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&z, scratch, buffer_size);
371     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&w, scratch, buffer_size);
372     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&u1, scratch, buffer_size << 1);
373     NX_CRYPTO_HUGE_NUMBER_INITIALIZE(&u2, scratch, buffer_size << 1);
374     NX_CRYPTO_EC_POINT_INITIALIZE(&pubkey, NX_CRYPTO_EC_POINT_AFFINE, scratch, buffer_size);
375     NX_CRYPTO_EC_POINT_INITIALIZE(&pt, NX_CRYPTO_EC_POINT_AFFINE, scratch, buffer_size);
376     NX_CRYPTO_EC_POINT_INITIALIZE(&pt2, NX_CRYPTO_EC_POINT_AFFINE, scratch, buffer_size);
377 
378     /* Copy the public key from the caller's buffer. */
379     status = _nx_crypto_ec_point_setup(&pubkey, public_key, public_key_length);
380     if (status != NX_CRYPTO_SUCCESS)
381     {
382         return(status);
383     }
384 
385 #ifndef NX_CRYPTO_ECC_DISABLE_KEY_VALIDATION
386     status = _nx_crypto_ec_validate_public_key(&pubkey, curve, NX_CRYPTO_FALSE, scratch);
387     if (status != NX_CRYPTO_SUCCESS)
388     {
389         return(status);
390     }
391 #endif /* NX_CRYPTO_ECC_DISABLE_KEY_VALIDATION */
392 
393     if (signature_length < (signature[1] + 2u))
394     {
395         return(NX_CRYPTO_SIZE_ERROR);
396     }
397 
398     /* Read r value from input signature. */
399     status = _nx_crypto_huge_number_setup(&r, &signature[2], signature[1]);
400     if (status != NX_CRYPTO_SUCCESS)
401     {
402         return(status);
403     }
404     signature_length -= (signature[1] + 2u);
405     signature += signature[1] + 2;
406 
407     if (signature_length < (signature[1] + 2u))
408     {
409         return(NX_CRYPTO_SIZE_ERROR);
410     }
411 
412     /* Read s value from input signature. */
413     status = _nx_crypto_huge_number_setup(&s, &signature[2], signature[1]);
414     if (status != NX_CRYPTO_SUCCESS)
415     {
416         return(status);
417     }
418 
419     /* r and s must be in the range [1..n-1] */
420     if(_nx_crypto_huge_number_is_zero(&r) || _nx_crypto_huge_number_is_zero(&s))
421     {
422         return(NX_CRYPTO_NOT_SUCCESSFUL);
423     }
424 
425     if(NX_CRYPTO_HUGE_NUMBER_LESS != _nx_crypto_huge_number_compare_unsigned(&r, &curve -> nx_crypto_ec_n))
426     {
427         return(NX_CRYPTO_NOT_SUCCESSFUL);
428     }
429 
430     if(NX_CRYPTO_HUGE_NUMBER_LESS != _nx_crypto_huge_number_compare_unsigned(&s, &curve -> nx_crypto_ec_n))
431     {
432         return(NX_CRYPTO_NOT_SUCCESSFUL);
433     }
434 
435     /* Truncate the hash data to the size of group order. */
436     if (hash_length > buffer_size)
437     {
438         hash_length = buffer_size;
439     }
440 
441     status = _nx_crypto_huge_number_setup(&z, hash, hash_length);
442     if (status != NX_CRYPTO_SUCCESS)
443     {
444         return(status);
445     }
446 
447     if (curve -> nx_crypto_ec_bits < hash_length << 3)
448     {
449         _nx_crypto_huge_number_shift_right(&z, (hash_length << 3) - curve -> nx_crypto_ec_bits);
450     }
451 
452     /* Calculate w = s^-1 mod n */
453     _nx_crypto_huge_number_inverse_modulus(&s, &curve -> nx_crypto_ec_n, &w, scratch);
454 
455     /* Calculate u1 = zw mod n */
456     _nx_crypto_huge_number_multiply(&z, &w, &u1);
457     _nx_crypto_huge_number_modulus(&u1, &curve -> nx_crypto_ec_n);
458 
459     /* Calculate u2 = rw mod n */
460     _nx_crypto_huge_number_multiply(&r, &w, &u2);
461     _nx_crypto_huge_number_modulus(&u2, &curve -> nx_crypto_ec_n);
462 
463     /* Calculate (x1,y1) = u1*G + u2*public_key */
464     curve -> nx_crypto_ec_multiple(curve, &curve -> nx_crypto_ec_g, &u1, &pt, scratch);
465     curve -> nx_crypto_ec_multiple(curve, &pubkey, &u2, &pt2, scratch);
466 
467     curve -> nx_crypto_ec_add(curve, &pt, &pt2, scratch);
468 
469     _nx_crypto_huge_number_modulus(&pt.nx_crypto_ec_point_x, &curve -> nx_crypto_ec_n);
470 
471     /* Check r == x1 mod n */
472     if (NX_CRYPTO_HUGE_NUMBER_EQUAL != _nx_crypto_huge_number_compare_unsigned(&pt.nx_crypto_ec_point_x, &r))
473     {
474         return NX_CRYPTO_NOT_SUCCESSFUL;
475     }
476     return NX_CRYPTO_SUCCESS;
477 }
478 
479 /**************************************************************************/
480 /*                                                                        */
481 /*  FUNCTION                                               RELEASE        */
482 /*                                                                        */
483 /*    _nx_crypto_method_ecdsa_init                        PORTABLE C      */
484 /*                                                           6.3.0        */
485 /*  AUTHOR                                                                */
486 /*                                                                        */
487 /*    Timothy Stapko, Microsoft Corporation                               */
488 /*                                                                        */
489 /*  DESCRIPTION                                                           */
490 /*                                                                        */
491 /*    This function is the common crypto method init callback for         */
492 /*    Microsoft supported ECDSA cryptographic algorithm.                  */
493 /*                                                                        */
494 /*  INPUT                                                                 */
495 /*                                                                        */
496 /*    method                                Pointer to crypto method      */
497 /*    key                                   Pointer to key                */
498 /*    key_size_in_bits                      Length of key size in bits    */
499 /*    handler                               Returned crypto handler       */
500 /*    crypto_metadata                       Metadata area                 */
501 /*    crypto_metadata_size                  Size of the metadata area     */
502 /*                                                                        */
503 /*  OUTPUT                                                                */
504 /*                                                                        */
505 /*    status                                Completion status             */
506 /*                                                                        */
507 /*  CALLS                                                                 */
508 /*                                                                        */
509 /*    None                                                                */
510 /*                                                                        */
511 /*  CALLED BY                                                             */
512 /*                                                                        */
513 /*    Application Code                                                    */
514 /*                                                                        */
515 /*  RELEASE HISTORY                                                       */
516 /*                                                                        */
517 /*    DATE              NAME                      DESCRIPTION             */
518 /*                                                                        */
519 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
520 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
521 /*                                            resulting in version 6.1    */
522 /*  10-31-2023     Yanwu Cai                Modified comment(s),          */
523 /*                                            resulting in version 6.3.0  */
524 /*                                                                        */
525 /**************************************************************************/
_nx_crypto_method_ecdsa_init(struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,VOID ** handle,VOID * crypto_metadata,ULONG crypto_metadata_size)526 NX_CRYPTO_KEEP UINT  _nx_crypto_method_ecdsa_init(struct  NX_CRYPTO_METHOD_STRUCT *method,
527                                                   UCHAR *key, NX_CRYPTO_KEY_SIZE key_size_in_bits,
528                                                   VOID  **handle,
529                                                   VOID  *crypto_metadata,
530                                                   ULONG crypto_metadata_size)
531 {
532 NX_CRYPTO_ECDSA *ecdsa;
533 
534     NX_CRYPTO_PARAMETER_NOT_USED(key);
535     NX_CRYPTO_PARAMETER_NOT_USED(key_size_in_bits);
536     NX_CRYPTO_PARAMETER_NOT_USED(handle);
537 
538     NX_CRYPTO_STATE_CHECK
539 
540     if ((method == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL))
541     {
542         return(NX_CRYPTO_PTR_ERROR);
543     }
544 
545     /* Verify the metadata address is 4-byte aligned. */
546     if((((ULONG)crypto_metadata) & 0x3) != 0)
547     {
548         return(NX_CRYPTO_PTR_ERROR);
549     }
550 
551     if(crypto_metadata_size < sizeof(NX_CRYPTO_ECDSA))
552     {
553         return(NX_CRYPTO_PTR_ERROR);
554     }
555 
556     ecdsa = (NX_CRYPTO_ECDSA *)crypto_metadata;
557 
558     /* Reset ECDSA metadata. */
559     ecdsa -> nx_crypto_ecdsa_curve = NX_CRYPTO_NULL;
560     ecdsa -> nx_crypto_ecdsa_hash_method = NX_CRYPTO_NULL;
561 
562     return(NX_CRYPTO_SUCCESS);
563 }
564 
565 
566 /**************************************************************************/
567 /*                                                                        */
568 /*  FUNCTION                                               RELEASE        */
569 /*                                                                        */
570 /*    _nx_crypto_method_ecdsa_cleanup                     PORTABLE C      */
571 /*                                                           6.1          */
572 /*  AUTHOR                                                                */
573 /*                                                                        */
574 /*    Timothy Stapko, Microsoft Corporation                               */
575 /*                                                                        */
576 /*  DESCRIPTION                                                           */
577 /*                                                                        */
578 /*    This function cleans up the crypto metadata.                        */
579 /*                                                                        */
580 /*  INPUT                                                                 */
581 /*                                                                        */
582 /*    crypto_metadata                       Crypto metadata               */
583 /*                                                                        */
584 /*  OUTPUT                                                                */
585 /*                                                                        */
586 /*    status                                Completion status             */
587 /*                                                                        */
588 /*  CALLS                                                                 */
589 /*                                                                        */
590 /*    NX_CRYPTO_MEMSET                      Set the memory                */
591 /*                                                                        */
592 /*  CALLED BY                                                             */
593 /*                                                                        */
594 /*    Application Code                                                    */
595 /*                                                                        */
596 /*  RELEASE HISTORY                                                       */
597 /*                                                                        */
598 /*    DATE              NAME                      DESCRIPTION             */
599 /*                                                                        */
600 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
601 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
602 /*                                            resulting in version 6.1    */
603 /*                                                                        */
604 /**************************************************************************/
_nx_crypto_method_ecdsa_cleanup(VOID * crypto_metadata)605 NX_CRYPTO_KEEP UINT  _nx_crypto_method_ecdsa_cleanup(VOID *crypto_metadata)
606 {
607 
608     NX_CRYPTO_STATE_CHECK
609 
610 #ifdef NX_SECURE_KEY_CLEAR
611     if (!crypto_metadata)
612         return (NX_CRYPTO_SUCCESS);
613 
614     /* Clean up the crypto metadata.  */
615     NX_CRYPTO_MEMSET(crypto_metadata, 0, sizeof(NX_CRYPTO_ECDSA));
616 #else
617     NX_CRYPTO_PARAMETER_NOT_USED(crypto_metadata);
618 #endif/* NX_SECURE_KEY_CLEAR  */
619 
620     return(NX_CRYPTO_SUCCESS);
621 }
622 
623 
624 /**************************************************************************/
625 /*                                                                        */
626 /*  FUNCTION                                               RELEASE        */
627 /*                                                                        */
628 /*    _nx_crypto_method_ecdsa_operation                   PORTABLE C      */
629 /*                                                           6.3.0        */
630 /*  AUTHOR                                                                */
631 /*                                                                        */
632 /*    Timothy Stapko, Microsoft Corporation                               */
633 /*                                                                        */
634 /*  DESCRIPTION                                                           */
635 /*                                                                        */
636 /*    This function performs an ECDSA operation.                          */
637 /*                                                                        */
638 /*  INPUT                                                                 */
639 /*                                                                        */
640 /*    op                                    ECDSA operation               */
641 /*    handle                                Crypto handle                 */
642 /*    method                                Cryption Method Object        */
643 /*    key                                   Encryption Key                */
644 /*    key_size_in_bits                      Key size in bits              */
645 /*    input                                 Input data                    */
646 /*    input_length_in_byte                  Input data size               */
647 /*    iv_ptr                                Initial vector                */
648 /*    output                                Output buffer                 */
649 /*    output_length_in_byte                 Output buffer size            */
650 /*    crypto_metadata                       Metadata area                 */
651 /*    crypto_metadata_size                  Metadata area size            */
652 /*    packet_ptr                            Pointer to packet             */
653 /*    nx_crypto_hw_process_callback         Callback function pointer     */
654 /*                                                                        */
655 /*  OUTPUT                                                                */
656 /*                                                                        */
657 /*    status                                Completion status             */
658 /*                                                                        */
659 /*  CALLS                                                                 */
660 /*                                                                        */
661 /*    _nx_crypto_ecdsa_sign                 Sign using ECDSA              */
662 /*    _nx_crypto_ecdsa_verify               Verify ECDSA signature        */
663 /*                                                                        */
664 /*  CALLED BY                                                             */
665 /*                                                                        */
666 /*    Application Code                                                    */
667 /*                                                                        */
668 /*  RELEASE HISTORY                                                       */
669 /*                                                                        */
670 /*    DATE              NAME                      DESCRIPTION             */
671 /*                                                                        */
672 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
673 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
674 /*                                            resulting in version 6.1    */
675 /*  10-31-2023     Yanwu Cai                Modified comment(s),          */
676 /*                                            resulting in version 6.3.0  */
677 /*                                                                        */
678 /**************************************************************************/
_nx_crypto_method_ecdsa_operation(UINT op,VOID * handle,struct NX_CRYPTO_METHOD_STRUCT * method,UCHAR * key,NX_CRYPTO_KEY_SIZE key_size_in_bits,UCHAR * input,ULONG input_length_in_byte,UCHAR * iv_ptr,UCHAR * output,ULONG output_length_in_byte,VOID * crypto_metadata,ULONG crypto_metadata_size,VOID * packet_ptr,VOID (* nx_crypto_hw_process_callback)(VOID *,UINT))679 NX_CRYPTO_KEEP UINT _nx_crypto_method_ecdsa_operation(UINT op,
680                                                       VOID *handle,
681                                                       struct NX_CRYPTO_METHOD_STRUCT *method,
682                                                       UCHAR *key, NX_CRYPTO_KEY_SIZE key_size_in_bits,
683                                                       UCHAR *input, ULONG input_length_in_byte,
684                                                       UCHAR *iv_ptr,
685                                                       UCHAR *output, ULONG output_length_in_byte,
686                                                       VOID *crypto_metadata, ULONG crypto_metadata_size,
687                                                       VOID *packet_ptr,
688                                                       VOID (*nx_crypto_hw_process_callback)(VOID *, UINT))
689 {
690 NX_CRYPTO_ECDSA *ecdsa;
691 UINT             status = NX_CRYPTO_SUCCESS;
692 NX_CRYPTO_EXTENDED_OUTPUT
693                 *extended_output;
694 NX_CRYPTO_METHOD *hash_method;
695 VOID            *hash_handler = NX_CRYPTO_NULL;
696 UCHAR           *hash_output = NX_CRYPTO_NULL;
697 
698     NX_CRYPTO_PARAMETER_NOT_USED(handle);
699     NX_CRYPTO_PARAMETER_NOT_USED(iv_ptr);
700     NX_CRYPTO_PARAMETER_NOT_USED(packet_ptr);
701     NX_CRYPTO_PARAMETER_NOT_USED(nx_crypto_hw_process_callback);
702 
703     NX_CRYPTO_STATE_CHECK
704 
705     /* Verify the metadata address is 4-byte aligned. */
706     if((method == NX_CRYPTO_NULL) || (crypto_metadata == NX_CRYPTO_NULL) || ((((ULONG)crypto_metadata) & 0x3) != 0))
707     {
708         return(NX_CRYPTO_PTR_ERROR);
709     }
710 
711     if(crypto_metadata_size < sizeof(NX_CRYPTO_ECDSA))
712     {
713         return(NX_CRYPTO_PTR_ERROR);
714     }
715 
716     ecdsa = (NX_CRYPTO_ECDSA *)crypto_metadata;
717 
718     if (op == NX_CRYPTO_EC_CURVE_SET)
719     {
720         status = ((NX_CRYPTO_METHOD *)input) -> nx_crypto_operation(NX_CRYPTO_EC_CURVE_GET,
721                                                                     NX_CRYPTO_NULL,
722                                                                     (NX_CRYPTO_METHOD *)input,
723                                                                     NX_CRYPTO_NULL, 0,
724                                                                     NX_CRYPTO_NULL, 0,
725                                                                     NX_CRYPTO_NULL,
726                                                                     (UCHAR *)&ecdsa -> nx_crypto_ecdsa_curve,
727                                                                     sizeof(NX_CRYPTO_METHOD *),
728                                                                     NX_CRYPTO_NULL, 0,
729                                                                     NX_CRYPTO_NULL, NX_CRYPTO_NULL);
730 
731         if (status)
732         {
733             return(status);
734         }
735     }
736     else if (op == NX_CRYPTO_AUTHENTICATE)
737     {
738         if ((key == NX_CRYPTO_NULL) || (ecdsa -> nx_crypto_ecdsa_curve == NX_CRYPTO_NULL))
739         {
740             return(NX_CRYPTO_PTR_ERROR);
741         }
742 
743         extended_output = (NX_CRYPTO_EXTENDED_OUTPUT *)output;
744 
745         status = _nx_crypto_ecdsa_sign(ecdsa -> nx_crypto_ecdsa_curve,
746                                        input,
747                                        input_length_in_byte,
748                                        key,
749                                        key_size_in_bits >> 3,
750                                        extended_output -> nx_crypto_extended_output_data,
751                                        extended_output -> nx_crypto_extended_output_length_in_byte,
752                                        &extended_output -> nx_crypto_extended_output_actual_size,
753                                        ecdsa -> nx_crypto_ecdsa_scratch_buffer);
754     }
755     else if (op == NX_CRYPTO_VERIFY)
756     {
757         if (key == NX_CRYPTO_NULL)
758         {
759             return(NX_CRYPTO_PTR_ERROR);
760         }
761 
762         status = _nx_crypto_ecdsa_verify(ecdsa->nx_crypto_ecdsa_curve,
763                                          input,
764                                          input_length_in_byte,
765                                          key,
766                                          key_size_in_bits >> 3,
767                                          output, output_length_in_byte,
768                                          ecdsa -> nx_crypto_ecdsa_scratch_buffer);
769     }
770     else if (op == NX_CRYPTO_EC_KEY_PAIR_GENERATE)
771     {
772         if (ecdsa->nx_crypto_ecdsa_curve == NX_CRYPTO_NULL)
773         {
774             return(NX_CRYPTO_PTR_ERROR);
775         }
776 
777         extended_output = (NX_CRYPTO_EXTENDED_OUTPUT *)output;
778         status = _nx_crypto_ec_key_pair_stream_generate(ecdsa->nx_crypto_ecdsa_curve,
779                                                         extended_output -> nx_crypto_extended_output_data,
780                                                         extended_output -> nx_crypto_extended_output_length_in_byte,
781                                                         &extended_output -> nx_crypto_extended_output_actual_size,
782                                                         ecdsa -> nx_crypto_ecdsa_scratch_buffer);
783     }
784     else if (op == NX_CRYPTO_HASH_METHOD_SET)
785     {
786 
787         /* Setup hash method used by ECDSA. */
788         hash_method = (NX_CRYPTO_METHOD *)input;
789 
790         /* ECDSA scratch buffer shares with metadata of hash method.
791          * Check the size required by metadata of hash method. */
792         if ((hash_method -> nx_crypto_metadata_area_size +
793              (hash_method -> nx_crypto_ICV_size_in_bits >> 3)) >
794             sizeof(ecdsa -> nx_crypto_ecdsa_scratch_buffer))
795         {
796             status = NX_CRYPTO_SIZE_ERROR;
797         }
798         else
799         {
800             ecdsa -> nx_crypto_ecdsa_hash_method = hash_method;
801         }
802     }
803     else if ((op == NX_CRYPTO_SIGNATURE_GENERATE) || (op == NX_CRYPTO_SIGNATURE_VERIFY))
804     {
805         hash_method = ecdsa -> nx_crypto_ecdsa_hash_method;
806         if (hash_method == NX_CRYPTO_NULL)
807         {
808 
809             /* Hash method is not set successfully. */
810             status = NX_CRYPTO_PTR_ERROR;
811         }
812         else
813         {
814 
815             /* Put the hash at the end of scratch buffer. */
816             hash_output = (UCHAR *)(ecdsa -> nx_crypto_ecdsa_scratch_buffer) +
817                 (sizeof(ecdsa -> nx_crypto_ecdsa_scratch_buffer) - (hash_method -> nx_crypto_ICV_size_in_bits >> 3));
818 
819             /* First, calculate hash value of input message. */
820             if (hash_method -> nx_crypto_init)
821             {
822                 status = hash_method -> nx_crypto_init(hash_method,
823                                                        NX_CRYPTO_NULL,
824                                                        0,
825                                                        &hash_handler,
826                                                        ecdsa -> nx_crypto_ecdsa_scratch_buffer,
827                                                        hash_method -> nx_crypto_metadata_area_size);
828             }
829 
830             if (status == NX_CRYPTO_SUCCESS)
831             {
832                 status = hash_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
833                                                             NX_CRYPTO_NULL,
834                                                             hash_method,
835                                                             NX_CRYPTO_NULL,
836                                                             0,
837                                                             input,
838                                                             input_length_in_byte,
839                                                             NX_CRYPTO_NULL,
840                                                             hash_output,
841                                                             (hash_method -> nx_crypto_ICV_size_in_bits >> 3),
842                                                             ecdsa -> nx_crypto_ecdsa_scratch_buffer,
843                                                             hash_method -> nx_crypto_metadata_area_size,
844                                                             NX_CRYPTO_NULL, NX_CRYPTO_NULL);
845 
846                 if (status != NX_CRYPTO_SUCCESS)
847                 {
848                     return(status);
849                 }
850             }
851 
852             if (hash_method -> nx_crypto_cleanup)
853             {
854                 status = hash_method -> nx_crypto_cleanup(ecdsa -> nx_crypto_ecdsa_scratch_buffer);
855             }
856         }
857 
858         if (status == NX_CRYPTO_SUCCESS)
859         {
860 
861             /* Second, generate/verify signature. */
862             if ((key == NX_CRYPTO_NULL) || (ecdsa -> nx_crypto_ecdsa_curve == NX_CRYPTO_NULL))
863             {
864                 status = NX_CRYPTO_PTR_ERROR;
865             }
866             else if (op == NX_CRYPTO_SIGNATURE_GENERATE)
867             {
868 
869                 /* Signature generation. */
870                 extended_output = (NX_CRYPTO_EXTENDED_OUTPUT *)output;
871 
872                 status = _nx_crypto_ecdsa_sign(ecdsa -> nx_crypto_ecdsa_curve,
873                                                hash_output,
874                                                (hash_method -> nx_crypto_ICV_size_in_bits >> 3),
875                                                key,
876                                                key_size_in_bits >> 3,
877                                                extended_output -> nx_crypto_extended_output_data,
878                                                extended_output -> nx_crypto_extended_output_length_in_byte,
879                                                &extended_output -> nx_crypto_extended_output_actual_size,
880                                                ecdsa -> nx_crypto_ecdsa_scratch_buffer);
881             }
882             else
883             {
884 
885                 /* Signature verification. */
886                 status = _nx_crypto_ecdsa_verify(ecdsa->nx_crypto_ecdsa_curve,
887                                                  hash_output,
888                                                  (hash_method -> nx_crypto_ICV_size_in_bits >> 3),
889                                                  key,
890                                                  key_size_in_bits >> 3,
891                                                  output, output_length_in_byte,
892                                                  ecdsa -> nx_crypto_ecdsa_scratch_buffer);
893             }
894         }
895     }
896     else
897     {
898         status = NX_CRYPTO_NOT_SUCCESSFUL;
899     }
900 
901     return(status);
902 }
903