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