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 /**  Transport Layer Security (TLS) - PHASH function                      */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 #include "nx_crypto_phash.h"
25 
26 /**************************************************************************/
27 /*                                                                        */
28 /*  FUNCTION                                               RELEASE        */
29 /*                                                                        */
30 /*    _nx_crypto_phash                                    PORTABLE C      */
31 /*                                                           6.1          */
32 /*  AUTHOR                                                                */
33 /*                                                                        */
34 /*    Timothy Stapko, Microsoft Corporation                               */
35 /*                                                                        */
36 /*  DESCRIPTION                                                           */
37 /*                                                                        */
38 /*    This function implements phash for the crypto module.               */
39 /*                                                                        */
40 /*  INPUT                                                                 */
41 /*                                                                        */
42 /*    phash                                 phash control block           */
43 /*    output                                Pointer to output buffer      */
44 /*    desired_length                        Number of bytes to return     */
45 /*                                                                        */
46 /*  OUTPUT                                                                */
47 /*                                                                        */
48 /*    status                                Completion status             */
49 /*                                                                        */
50 /*  CALLS                                                                 */
51 /*                                                                        */
52 /*    None                                                                */
53 /*                                                                        */
54 /*  CALLED BY                                                             */
55 /*                                                                        */
56 /*    Application                                                         */
57 /*                                                                        */
58 /*  RELEASE HISTORY                                                       */
59 /*                                                                        */
60 /*    DATE              NAME                      DESCRIPTION             */
61 /*                                                                        */
62 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
63 /*  09-30-2020     Timothy Stapko           Modified comment(s), improved */
64 /*                                            buffer length verification, */
65 /*                                            verified memcpy use cases,  */
66 /*                                            and updated constants,      */
67 /*                                            resulting in version 6.1    */
68 /*                                                                        */
69 /**************************************************************************/
_nx_crypto_phash(NX_CRYPTO_PHASH * phash,UCHAR * output,UINT desired_length)70 NX_CRYPTO_KEEP UINT _nx_crypto_phash(NX_CRYPTO_PHASH *phash, UCHAR *output, UINT desired_length)
71 {
72 UINT    offset; /* point to the memory for the coming hmac data */
73 UINT    hash_size; /* the length of hmac output */
74 UINT    output_len; /* desired output length of hmac */
75 UINT    status;
76 /* A(i) */
77 UCHAR   *temp_A;
78 UINT    temp_A_size;
79 /* secret */
80 UCHAR   *secret;
81 UINT    secret_len;
82 /* seed */
83 UCHAR   *seed;
84 UINT    seed_len;
85 /* metadata */
86 UCHAR   *metadata;
87 UINT    metadata_size;
88 /* hmac output size */
89 UCHAR   *hmac_output;
90 UINT    hmac_output_size;
91 UINT    A_len; /* the length of current A(i) */
92 UINT    remaining_len, i; /* remaining length of data to be generated. */
93 VOID   *handler = NX_CRYPTO_NULL;
94 NX_CRYPTO_METHOD *hash_method = phash -> nx_crypto_hmac_method;
95 
96     NX_CRYPTO_STATE_CHECK
97 
98     /* Validate pointers. */
99     if (hash_method == NX_CRYPTO_NULL
100         || hash_method -> nx_crypto_operation == NX_CRYPTO_NULL
101         || hash_method -> nx_crypto_cleanup == NX_CRYPTO_NULL
102         || output == NX_CRYPTO_NULL)
103     {
104         return(NX_CRYPTO_INVALID_PARAMETER);
105     }
106 
107     /* Initialize temporary variables. */
108     secret = phash -> nx_crypto_phash_secret;
109     secret_len = phash -> nx_crypto_phash_secret_length;
110     seed = phash -> nx_crypto_phash_seed;
111     seed_len = phash -> nx_crypto_phash_seed_length;
112     temp_A = phash -> nx_crypto_phash_temp_A;
113     temp_A_size = phash -> nx_crypto_phash_temp_A_size;
114     hash_size = hash_method -> nx_crypto_ICV_size_in_bits >> 3;
115     metadata = phash -> nx_crypto_hmac_metadata;
116     metadata_size = phash -> nx_crypto_hmac_metadata_size;
117     hmac_output = phash -> nx_crypto_hmac_output;
118     hmac_output_size = phash -> nx_crypto_hmac_output_size;
119 
120     if (hash_size > hmac_output_size)
121     {
122         return(NX_CRYPTO_INVALID_PARAMETER);
123     }
124 
125     if (seed_len > temp_A_size)
126     {
127         return(NX_CRYPTO_SIZE_ERROR);
128     }
129 
130     /* Assign the seed as A(0). */
131     NX_CRYPTO_MEMSET(temp_A, 0, temp_A_size);
132     NX_CRYPTO_MEMCPY(temp_A, seed, seed_len); /* Use case of memcpy is verified. */
133     A_len = phash -> nx_crypto_phash_seed_length;
134 
135     remaining_len = desired_length;
136     for (offset = 0; offset < desired_length; offset += hash_size)
137     {
138         /* Calculate A(i) */
139         if (hash_method -> nx_crypto_init)
140         {
141             status = hash_method -> nx_crypto_init(hash_method,
142                                           secret,
143                                           (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
144                                           &handler,
145                                           metadata,
146                                           metadata_size);
147 
148             if(status != NX_CRYPTO_SUCCESS)
149             {
150                 return(status);
151             }
152         }
153 
154         status = hash_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
155                                            handler,
156                                            hash_method,
157                                            secret,
158                                            (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
159                                            temp_A,
160                                            A_len,
161                                            NX_CRYPTO_NULL,
162                                            temp_A,
163                                            temp_A_size,
164                                            metadata,
165                                            metadata_size,
166                                            NX_CRYPTO_NULL,
167                                            NX_CRYPTO_NULL);
168 
169         if(status != NX_CRYPTO_SUCCESS)
170         {
171             return(status);
172         }
173 
174         /* Updated the length of A(i) */
175         A_len = hash_size;
176 
177         if ((A_len + seed_len) > temp_A_size)
178         {
179             return(NX_CRYPTO_SIZE_ERROR);
180         }
181 
182         /* Concatenate A[i] and seed to feed into digest. */
183         NX_CRYPTO_MEMCPY(&temp_A[A_len], seed, seed_len); /* Use case of memcpy is verified. */
184 
185         /* Output block is the size of the digest unless the remaining
186            desired length is smaller than the digest length. */
187         if (remaining_len < hash_size)
188         {
189             output_len = remaining_len;
190         }
191         else
192         {
193             output_len = hash_size;
194         }
195 
196         /* Calculate p-hash block, store in output. */
197         status = hash_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
198                                            handler,
199                                            hash_method,
200                                            secret,
201                                            (NX_CRYPTO_KEY_SIZE)(secret_len << 3),
202                                            temp_A,
203                                            A_len + seed_len,
204                                            NX_CRYPTO_NULL,
205                                            hmac_output,
206                                            output_len,
207                                            metadata,
208                                            metadata_size,
209                                            NX_CRYPTO_NULL,
210                                            NX_CRYPTO_NULL);
211 
212         if(status != NX_CRYPTO_SUCCESS)
213         {
214             return(status);
215         }
216 
217         /* Append the hmac result to the output. */
218         for (i = 0; i < output_len; i++)
219         {
220             output[offset + i] ^= hmac_output[i];
221         }
222 
223         /* Adjust our remaining length by the number of bytes written. */
224         remaining_len -= hash_size;
225 
226         status = hash_method -> nx_crypto_cleanup(metadata);
227 
228         if(status != NX_CRYPTO_SUCCESS)
229         {
230             return(status);
231         }
232     }
233 
234     return(NX_CRYPTO_SUCCESS);
235 }
236