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