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 Component                                                        */
16 /**                                                                       */
17 /**   Utility                                                             */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "tx_api.h"
28 #include "nx_api.h"
29 
30 /* Define the base64 letters.  */
31 static CHAR _nx_utility_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_utility_string_length_check                     PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yuxin Zhou, Microsoft Corporation                                   */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function traverses the string and returns the string length,   */
46 /*    if the string is invalid or the string length is bigger than max    */
47 /*    string length, returns error.                                       */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    input_string                          Pointer to input string       */
52 /*    string_length                         Pointer to string length      */
53 /*    max_string_length                     Max string length             */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    None                                                                */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    Application Code                                                    */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
72 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
73 /*                                            resulting in version 6.1    */
74 /*                                                                        */
75 /**************************************************************************/
_nx_utility_string_length_check(CHAR * input_string,UINT * string_length,UINT max_string_length)76 UINT  _nx_utility_string_length_check(CHAR *input_string, UINT *string_length, UINT max_string_length)
77 {
78 
79 UINT    i;
80 
81 
82     /* Check for invalid input pointers.  */
83     if (input_string == NX_NULL)
84     {
85         return(NX_PTR_ERROR);
86     }
87 
88     /* Traverse the string.  */
89     for (i = 0; input_string[i]; i++)
90     {
91 
92         /* Check if the string length is bigger than the max string length.  */
93         if (i >= max_string_length)
94         {
95             return(NX_SIZE_ERROR);
96         }
97     }
98 
99     /* Return the string length if string_length is not NULL.
100        String_length being NULL indicates the caller needs to check for string
101        length within the max_string_length. */
102     if (string_length)
103     {
104         *string_length = i;
105     }
106 
107     /* Return success.  */
108     return(NX_SUCCESS);
109 }
110 
111 /**************************************************************************/
112 /*                                                                        */
113 /*  FUNCTION                                               RELEASE        */
114 /*                                                                        */
115 /*    _nx_utility_string_to_uint                          PORTABLE C      */
116 /*                                                           6.1.3        */
117 /*  AUTHOR                                                                */
118 /*                                                                        */
119 /*    Yuxin Zhou, Microsoft Corporation                                   */
120 /*                                                                        */
121 /*  DESCRIPTION                                                           */
122 /*                                                                        */
123 /*    This function converts the string to unsigned integer.              */
124 /*                                                                        */
125 /*  INPUT                                                                 */
126 /*                                                                        */
127 /*    input_string                          Pointer to input string       */
128 /*    string_length                         Length of input string        */
129 /*    number                                Pointer to the number         */
130 /*                                                                        */
131 /*  OUTPUT                                                                */
132 /*                                                                        */
133 /*    status                                Completion status             */
134 /*                                                                        */
135 /*  CALLS                                                                 */
136 /*                                                                        */
137 /*    None                                                                */
138 /*                                                                        */
139 /*  CALLED BY                                                             */
140 /*                                                                        */
141 /*    Application Code                                                    */
142 /*                                                                        */
143 /*  RELEASE HISTORY                                                       */
144 /*                                                                        */
145 /*    DATE              NAME                      DESCRIPTION             */
146 /*                                                                        */
147 /*  12-31-2020     Yuxin Zhou               Initial Version 6.1.3         */
148 /*                                                                        */
149 /**************************************************************************/
_nx_utility_string_to_uint(CHAR * input_string,UINT string_length,UINT * number)150 UINT  _nx_utility_string_to_uint(CHAR *input_string, UINT string_length, UINT *number)
151 {
152 
153 UINT i;
154 
155 
156     /* Check for invalid input pointers.  */
157     if ((input_string == NX_NULL) || (number == NX_NULL))
158     {
159         return(NX_PTR_ERROR);
160     }
161 
162     /* Check string length.  */
163     if (string_length == 0)
164     {
165         return(NX_SIZE_ERROR);
166     }
167 
168     /* Initialize.  */
169     i = 0;
170     *number = 0;
171 
172     /* Traverse the string.  */
173     while (i < string_length)
174     {
175 
176         /* Is a numeric character present?  */
177         if ((input_string[i] >= '0') && (input_string[i] <= '9'))
178         {
179 
180             /* Check overflow. Max Value: Hex:0xFFFFFFFF, Decimal: 4294967295.  */
181             if (((*number == 429496729) && (input_string[i] > '5')) ||
182                 (*number >= 429496730))
183             {
184                 return(NX_OVERFLOW);
185             }
186 
187             /* Yes, numeric character is present. Update the number.  */
188             *number =  (*number * 10) + (UINT) (input_string[i] - '0');
189         }
190         else
191         {
192             return(NX_INVALID_PARAMETERS);
193         }
194 
195         i++;
196     }
197 
198     /* Return success.  */
199     return(NX_SUCCESS);
200 }
201 
202 /**************************************************************************/
203 /*                                                                        */
204 /*  FUNCTION                                               RELEASE        */
205 /*                                                                        */
206 /*    _nx_utility_uint_to_string                          PORTABLE C      */
207 /*                                                           6.1.9        */
208 /*  AUTHOR                                                                */
209 /*                                                                        */
210 /*    Yuxin Zhou, Microsoft Corporation                                   */
211 /*                                                                        */
212 /*  DESCRIPTION                                                           */
213 /*                                                                        */
214 /*    This function converts the unsigned integer to string.              */
215 /*                                                                        */
216 /*  INPUT                                                                 */
217 /*                                                                        */
218 /*    number                                Input number                  */
219 /*    base                                  Base of the conversion        */
220 /*                                           8 for OCT                    */
221 /*                                           10 for DEC                   */
222 /*                                           16 for HEX                   */
223 /*    string_buffer                         Pointer to string buffer      */
224 /*    string_buffer_size                    Size of string buffer         */
225 /*                                                                        */
226 /*  OUTPUT                                                                */
227 /*                                                                        */
228 /*    size                                  The size of output string     */
229 /*                                                                        */
230 /*  CALLS                                                                 */
231 /*                                                                        */
232 /*    None                                                                */
233 /*                                                                        */
234 /*  CALLED BY                                                             */
235 /*                                                                        */
236 /*    Application Code                                                    */
237 /*                                                                        */
238 /*  RELEASE HISTORY                                                       */
239 /*                                                                        */
240 /*    DATE              NAME                      DESCRIPTION             */
241 /*                                                                        */
242 /*  08-02-2021     Yuxin Zhou               Initial Version 6.1.8         */
243 /*  10-15-2021     Yuxin Zhou               Modified comment(s),          */
244 /*                                            checked invalid input value,*/
245 /*                                            resulting in version 6.1.9  */
246 /*                                                                        */
247 /**************************************************************************/
_nx_utility_uint_to_string(UINT number,UINT base,CHAR * string_buffer,UINT string_buffer_size)248 UINT _nx_utility_uint_to_string(UINT number, UINT base, CHAR *string_buffer, UINT string_buffer_size)
249 {
250 UINT i;
251 UINT digit;
252 UINT size;
253 
254     /* Check for invalid input pointers.  */
255     if ((string_buffer == NX_NULL) || (string_buffer_size == 0) || (base == 0))
256     {
257         return(0);
258     }
259 
260     /* Initialize.  */
261     i = 0;
262     size = 0;
263 
264     /* Loop to convert the number to ASCII. Minus 1 to put NULL terminal.  */
265     while (size < string_buffer_size - 1)
266     {
267 
268         /* Shift the current digits over one.  */
269         for (i = size; i != 0; i--)
270         {
271 
272             /* Move each digit over one place.  */
273             string_buffer[i] = string_buffer[i-1];
274         }
275 
276         /* Compute the next decimal digit.  */
277         digit = number % base;
278 
279         /* Update the input number.  */
280         number = number / base;
281 
282         /* Store the new digit in ASCII form.  */
283         if (digit < 10)
284         {
285             string_buffer[0] = (CHAR) (digit + '0');
286         }
287         else
288         {
289             string_buffer[0] = (CHAR) (digit + 'a' - 0xa);
290         }
291 
292         /* Increment the size.  */
293         size++;
294 
295         /* Determine if the number is now zero.  */
296         if (number == 0)
297             break;
298     }
299 
300     /* Determine if there is an overflow error.  */
301     if (number)
302     {
303 
304         /* Error, return bad values to user.  */
305         size = 0;
306     }
307 
308     /* Make the string NULL terminated.  */
309     string_buffer[size] = (CHAR) NX_NULL;
310 
311     /* Return size to caller.  */
312     return(size);
313 }
314 
315 /**************************************************************************/
316 /*                                                                        */
317 /*  FUNCTION                                               RELEASE        */
318 /*                                                                        */
319 /*    _nx_utility_base64_encode                           PORTABLE C      */
320 /*                                                           6.2.0        */
321 /*  AUTHOR                                                                */
322 /*                                                                        */
323 /*    Yuxin Zhou, Microsoft Corporation                                   */
324 /*                                                                        */
325 /*  DESCRIPTION                                                           */
326 /*                                                                        */
327 /*    This function encodes the input string into a base64                */
328 /*    representation.                                                     */
329 /*                                                                        */
330 /*  INPUT                                                                 */
331 /*                                                                        */
332 /*    name                                  Name string                   */
333 /*    name_size                             Size of name                  */
334 /*    base64name                            Encoded base64 name string    */
335 /*    base64name_size                       Size of encoded base64 name   */
336 /*    bytes_copied                          Number of bytes copied        */
337 /*                                                                        */
338 /*  OUTPUT                                                                */
339 /*                                                                        */
340 /*    status                                Completion status             */
341 /*                                                                        */
342 /*  CALLS                                                                 */
343 /*                                                                        */
344 /*    None                                                                */
345 /*                                                                        */
346 /*  CALLED BY                                                             */
347 /*                                                                        */
348 /*    Application Code                                                    */
349 /*                                                                        */
350 /*  RELEASE HISTORY                                                       */
351 /*                                                                        */
352 /*    DATE              NAME                      DESCRIPTION             */
353 /*                                                                        */
354 /*  04-02-2021     Yuxin Zhou               Initial Version 6.1.6         */
355 /*  10-31-2022     Yuxin Zhou               Modified comment(s),          */
356 /*                                            improved the internal logic,*/
357 /*                                            resulting in version 6.2.0  */
358 /*                                                                        */
359 /**************************************************************************/
_nx_utility_base64_encode(UCHAR * name,UINT name_size,UCHAR * base64name,UINT base64name_size,UINT * bytes_copied)360 UINT _nx_utility_base64_encode(UCHAR *name, UINT name_size, UCHAR *base64name, UINT base64name_size, UINT *bytes_copied)
361 {
362 UINT    pad;
363 UINT    i, j;
364 UINT    step;
365 UINT    input_name_size = name_size;
366 
367 
368     /* Check for invalid input pointers.  */
369     if ((name == NX_NULL) || (base64name == NX_NULL) || (bytes_copied == NX_NULL))
370     {
371         return(NX_PTR_ERROR);
372     }
373 
374     /* Check the size.  */
375     if ((name_size == 0) || (base64name_size == 0))
376     {
377         return(NX_SIZE_ERROR);
378     }
379 
380     /* Adjust the length to represent the base64 name.  */
381     name_size = ((name_size * 8) / 6);
382 
383     /* Default padding to none.  */
384     pad = 0;
385 
386     /* Determine if an extra conversion is needed.  */
387     if ((name_size * 6) % 24)
388     {
389 
390         /* Some padding is needed.  */
391 
392         /* Calculate the number of pad characters.  */
393         pad = (name_size * 6) % 24;
394         pad = (24 - pad) / 6;
395         pad = pad - 1;
396 
397         /* Adjust the length to pickup the character fraction.  */
398         name_size++;
399     }
400 
401     /* Check the buffer size.  */
402     if (base64name_size <= (name_size + pad))
403     {
404         return(NX_SIZE_ERROR);
405     }
406 
407     /* Setup index into the base64name.  */
408     j = 0;
409 
410     /* Compute the base64name.  */
411     step = 0;
412     i = 0;
413     while (j < name_size)
414     {
415 
416         /* Determine which step we are in.  */
417         if (step == 0)
418         {
419 
420             /* Use first 6 bits of name character for index.  */
421             base64name[j++] = (UCHAR)_nx_utility_base64_array[((UCHAR)name[i]) >> 2];
422             step++;
423         }
424         else if (step == 1)
425         {
426 
427             /* Use last 2 bits of name character and first 4 bits of next name character for index.  */
428             if ((i + 1) < input_name_size)
429             {
430                 base64name[j++] = (UCHAR)_nx_utility_base64_array[((((UCHAR)name[i]) & 0x3) << 4) | (((UCHAR)name[i + 1]) >> 4)];
431             }
432             else
433             {
434 
435                 /* If no more name character, pad with zero.  */
436                 base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0x3) << 4];
437             }
438             i++;
439             step++;
440         }
441         else if (step == 2)
442         {
443 
444             /* Use last 4 bits of name character and first 2 bits of next name character for index.  */
445             if ((i + 1) < input_name_size)
446             {
447                 base64name[j++] = (UCHAR)_nx_utility_base64_array[((((UCHAR)name[i]) & 0xF) << 2) | (((UCHAR)name[i + 1]) >> 6)];
448             }
449             else
450             {
451 
452                 /* If no more name character, pad with zero.  */
453                 base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0xF) << 2];
454             }
455             i++;
456             step++;
457         }
458         else /* Step 3 */
459         {
460 
461             /* Use last 6 bits of name character for index.  */
462             base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0x3F)];
463             i++;
464             step = 0;
465         }
466     }
467 
468     /* Now add the PAD characters.  */
469     while (pad--)
470     {
471 
472         /* Pad base64name with '=' characters.  */
473         base64name[j++] = '=';
474     }
475 
476     /* Put a NULL character in.  */
477     base64name[j] = NX_NULL;
478     *bytes_copied = j;
479 
480     return(NX_SUCCESS);
481 }
482 
483 /**************************************************************************/
484 /*                                                                        */
485 /*  FUNCTION                                               RELEASE        */
486 /*                                                                        */
487 /*    _nx_utility_base64_decode                           PORTABLE C      */
488 /*                                                           6.1.10       */
489 /*  AUTHOR                                                                */
490 /*                                                                        */
491 /*    Yuxin Zhou, Microsoft Corporation                                   */
492 /*                                                                        */
493 /*  DESCRIPTION                                                           */
494 /*                                                                        */
495 /*    This function decodes the input base64 ASCII string and converts    */
496 /*    it into a standard ASCII representation.                            */
497 /*                                                                        */
498 /*  INPUT                                                                 */
499 /*                                                                        */
500 /*    base64name                            Encoded base64 name string    */
501 /*    base64name_size                       Size of encoded base64 name   */
502 /*    name                                  Name string                   */
503 /*    name_size                             Size of name                  */
504 /*    bytes_copied                          Number of bytes copied        */
505 /*                                                                        */
506 /*  OUTPUT                                                                */
507 /*                                                                        */
508 /*    None                                                                */
509 /*                                                                        */
510 /*  CALLS                                                                 */
511 /*                                                                        */
512 /*    None                                                                */
513 /*                                                                        */
514 /*  CALLED BY                                                             */
515 /*                                                                        */
516 /*    Application Code                                                    */
517 /*                                                                        */
518 /*  RELEASE HISTORY                                                       */
519 /*                                                                        */
520 /*    DATE              NAME                      DESCRIPTION             */
521 /*                                                                        */
522 /*  04-02-2021     Yuxin Zhou               Initial Version 6.1.6         */
523 /*  10-15-2021     Yuxin Zhou               Modified comment(s),          */
524 /*                                            removed useless condition,  */
525 /*                                            resulting in version 6.1.9  */
526 /*  01-31-2022     Yuxin Zhou               Modified comment(s),          */
527 /*                                            fixed the issue of reading  */
528 /*                                            overflow,                   */
529 /*                                            resulting in version 6.1.10 */
530 /*                                                                        */
531 /**************************************************************************/
_nx_utility_base64_decode(UCHAR * base64name,UINT base64name_size,UCHAR * name,UINT name_size,UINT * bytes_copied)532 UINT _nx_utility_base64_decode(UCHAR *base64name, UINT base64name_size, UCHAR *name, UINT name_size, UINT *bytes_copied)
533 {
534 UINT    i, j;
535 UINT    value1, value2;
536 UINT    step;
537 UINT    source_size = base64name_size;
538 
539     /* Check for invalid input pointers.  */
540     if ((base64name == NX_NULL) || (name == NX_NULL) || (bytes_copied == NX_NULL))
541     {
542         return(NX_PTR_ERROR);
543     }
544 
545     /* Check the size.  */
546     if ((base64name_size == 0) || (name_size == 0))
547     {
548         return(NX_SIZE_ERROR);
549     }
550 
551     /* Adjust the length to represent the ASCII name.  */
552     base64name_size = ((base64name_size * 6) / 8);
553 
554     if ((base64name_size) && (base64name[source_size - 1] == '='))
555     {
556         base64name_size--;
557 
558         if ((base64name_size) && (base64name[source_size - 2] == '='))
559         {
560             base64name_size--;
561         }
562     }
563 
564     /* Check the buffer size.  */
565     if (name_size <= base64name_size)
566     {
567         return(NX_SIZE_ERROR);
568     }
569 
570     /* Setup index into the ASCII name.  */
571     j = 0;
572 
573     /* Compute the ASCII name.  */
574     step = 0;
575     i =  0;
576     while ((j < base64name_size) && (base64name[i]) && (base64name[i] != '='))
577     {
578 
579         /* Derive values of the Base64 name.  */
580         if ((base64name[i] >= 'A') && (base64name[i] <= 'Z'))
581             value1 =  (UINT) (base64name[i] - 'A');
582         else if ((base64name[i] >= 'a') && (base64name[i] <= 'z'))
583             value1 =  (UINT) (base64name[i] - 'a') + 26;
584         else if ((base64name[i] >= '0') && (base64name[i] <= '9'))
585             value1 =  (UINT) (base64name[i] - '0') + 52;
586         else if ((base64name[i] == '+') ||
587                  (base64name[i] == '-')) /* Base64 URL.  */
588             value1 =  62;
589         else if ((base64name[i] == '/') ||
590                  (base64name[i] == '_')) /* Base64 URL.  */
591             value1 =  63;
592         else
593             value1 =  0;
594 
595         /* Derive value for the next character.  */
596         if ((base64name[i + 1] >= 'A') && (base64name[i + 1] <= 'Z'))
597             value2 =  (UINT) (base64name[i+1] - 'A');
598         else if ((base64name[i + 1] >= 'a') && (base64name[i + 1] <= 'z'))
599             value2 =  (UINT) (base64name[i+1] - 'a') + 26;
600         else if ((base64name[i + 1] >= '0') && (base64name[i + 1] <= '9'))
601             value2 =  (UINT) (base64name[i+1] - '0') + 52;
602         else if ((base64name[i + 1] == '+') ||
603                  (base64name[i + 1] == '-')) /* Base64 URL.  */
604             value2 =  62;
605         else if ((base64name[i + 1] == '/') ||
606                  (base64name[i + 1] == '_')) /* Base64 URL.  */
607             value2 =  63;
608         else
609             value2 =  0;
610 
611         /* Determine which step we are in.  */
612         if (step == 0)
613         {
614 
615             /* Use first value and first 2 bits of second value.  */
616             name[j++] = (UCHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3));
617             i++;
618             step++;
619         }
620         else if (step == 1)
621         {
622 
623             /* Use last 4 bits of first value and first 4 bits of next value.  */
624             name[j++] = (UCHAR) (((value1 & 0xF) << 4) | (value2 >> 2));
625             i++;
626             step++;
627         }
628         else
629         {
630 
631             /* Use first 2 bits and following 6 bits of next value.  */
632             name[j++] = (UCHAR) (((value1 & 3) << 6) | (value2 & 0x3f));
633             i++;
634             i++;
635             step =  0;
636         }
637     }
638 
639     /* Put a NULL character in.  */
640     name[j] = NX_NULL;
641     *bytes_copied = j;
642 
643     return(NX_SUCCESS);
644 }