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 Secure Component                                                 */
17 /**                                                                       */
18 /**    Transport Layer Security (TLS) - Generate Session Keys             */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SECURE_SOURCE_CODE
24 
25 #include "nx_secure_tls.h"
26 #ifdef NX_SECURE_ENABLE_DTLS
27 #include "nx_secure_dtls.h"
28 #endif /* NX_SECURE_ENABLE_DTLS */
29 
30 /* This local static buffer needs to be large enough to hold both the server random and the client random. */
31 static UCHAR _nx_secure_tls_gen_keys_random[NX_SECURE_TLS_RANDOM_SIZE << 1];
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_secure_generate_session_keys                    PORTABLE C      */
38 /*                                                           6.2.0        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yanwu Cai, Microsoft Corporation                                    */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function generates the session keys used by TLS to encrypt     */
46 /*    the data being transmitted. It uses data gathered during the TLS    */
47 /*    handshake to generate a block of "key material" that is split into  */
48 /*    the various keys needed for each session.                           */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    ciphersuite                           Selected cipher suite         */
53 /*    protocol_version                      Selected TLS version          */
54 /*    session_prf_method                    Pointer to PRF crypto method  */
55 /*    tls_key_material                      TLS key material              */
56 /*    master_sec                            Pointer to master secret      */
57 /*    prf_metadata                          Metadata for PRF crypto method*/
58 /*    prf_metadata_size                     Size of PRF metadata          */
59 /*                                                                        */
60 /*  OUTPUT                                                                */
61 /*                                                                        */
62 /*    status                                Completion status             */
63 /*                                                                        */
64 /*  CALLS                                                                 */
65 /*                                                                        */
66 /*    [nx_crypto_init]                      Initialize crypto             */
67 /*    [nx_crypto_operation]                 Crypto operation              */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    _nx_secure_tls_generate_keys          Generate session keys         */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  10-31-2022     Yanwu Cai                Initial Version 6.2.0         */
78 /*                                                                        */
79 /**************************************************************************/
_nx_secure_generate_session_keys(const NX_SECURE_TLS_CIPHERSUITE_INFO * ciphersuite,USHORT protocol_version,const NX_CRYPTO_METHOD * session_prf_method,NX_SECURE_TLS_KEY_MATERIAL * tls_key_material,UCHAR * master_sec,VOID * prf_metadata,ULONG prf_metadata_size)80 UINT _nx_secure_generate_session_keys(const NX_SECURE_TLS_CIPHERSUITE_INFO *ciphersuite, USHORT protocol_version,
81                                       const NX_CRYPTO_METHOD *session_prf_method, NX_SECURE_TLS_KEY_MATERIAL *tls_key_material,
82                                       UCHAR *master_sec, VOID *prf_metadata, ULONG prf_metadata_size)
83 {
84 UCHAR                  *key_block; /* Maximum ciphersuite key size - AES_256_CBC_SHA, 2x32 byte keys + 2x20 byte MAC secrets + 2x16 IVs. */
85 UINT                    key_block_size;
86 UINT                    key_size;
87 UINT                    hash_size;
88 UINT                    iv_size;
89 UINT                    status;
90 const NX_CRYPTO_METHOD *session_cipher_method = NX_NULL;
91 VOID                   *handler = NX_NULL;
92 
93     NX_PARAMETER_NOT_USED(protocol_version);
94 
95     key_block_size = 0;
96 
97     /* Working pointer into our new key material block since we are generating new keys. */
98     key_block = tls_key_material -> nx_secure_tls_new_key_material_data;
99 
100 
101     /* Get our session cipher method so we can get key sizes. */
102     session_cipher_method = ciphersuite -> nx_secure_tls_session_cipher;
103 
104 
105     /* Lookup ciphersuite data for key size. We need 2 keys for each session. */
106     key_size = session_cipher_method -> nx_crypto_key_size_in_bits >> 3;
107 
108     /* Lookup ciphersuite data for hash size - used for the MAC secret. */
109     hash_size = ciphersuite -> nx_secure_tls_hash_size;
110 
111     /* Lookup initialization vector size.  */
112     iv_size = session_cipher_method -> nx_crypto_IV_size_in_bits >> 3;
113 
114     /* Now calculate block size. Need client and server for each key, hash, and iv. Note that
115        key size and iv size may be zero depending on the ciphersuite, particularly when using
116        the NULL ciphers. */
117     key_block_size = 2 * (key_size + hash_size + iv_size);
118 
119     /* Now generate keys from the master secret we obtained above. */
120     /* From the RFC (TLS 1.1):
121        To generate the key material, compute
122 
123        key_block = PRF(SecurityParameters.master_secret,
124                           "key expansion",
125                           SecurityParameters.server_random +
126              SecurityParameters.client_random);
127 
128        until enough output has been generated.  Then the key_block is
129        partitioned as follows:
130 
131        client_write_MAC_secret[SecurityParameters.hash_size]
132        server_write_MAC_secret[SecurityParameters.hash_size]
133        client_write_key[SecurityParameters.key_material_length]
134        server_write_key[SecurityParameters.key_material_length]
135      */
136 
137     /* The order of the randoms is reversed from that used for the master secret
138        when generating the key block.  */
139     NX_SECURE_MEMCPY(_nx_secure_tls_gen_keys_random, tls_key_material -> nx_secure_tls_server_random,
140                      NX_SECURE_TLS_RANDOM_SIZE); /* Use case of memcpy is verified. */
141     NX_SECURE_MEMCPY(&_nx_secure_tls_gen_keys_random[NX_SECURE_TLS_RANDOM_SIZE],
142                      tls_key_material -> nx_secure_tls_client_random, NX_SECURE_TLS_RANDOM_SIZE); /* Use case of memcpy is verified. */
143 
144     /* Key expansion uses the PRF to generate a block of key material from the master secret (generated
145        above) and the client and server random values transmitted during the initial hello negotiation. */
146     if (session_prf_method -> nx_crypto_init != NX_NULL)
147     {
148         status = session_prf_method -> nx_crypto_init((NX_CRYPTO_METHOD*)session_prf_method,
149                                                       master_sec, 48,
150                                                       &handler,
151                                                       prf_metadata,
152                                                       prf_metadata_size);
153 
154         if(status != NX_CRYPTO_SUCCESS)
155         {
156 #ifdef NX_SECURE_KEY_CLEAR
157             NX_SECURE_MEMSET(_nx_secure_tls_gen_keys_random, 0, sizeof(_nx_secure_tls_gen_keys_random));
158 #endif /* NX_SECURE_KEY_CLEAR  */
159 
160             return(status);
161         }
162     }
163 
164     if (session_prf_method -> nx_crypto_operation != NX_NULL)
165     {
166         status = session_prf_method -> nx_crypto_operation(NX_CRYPTO_PRF,
167                                                            handler,
168                                                            (NX_CRYPTO_METHOD*)session_prf_method,
169                                                            (UCHAR *)"key expansion",
170                                                            13,
171                                                            _nx_secure_tls_gen_keys_random,
172                                                            64,
173                                                            NX_NULL,
174                                                            key_block,
175                                                            key_block_size,
176                                                            prf_metadata,
177                                                            prf_metadata_size,
178                                                            NX_NULL,
179                                                            NX_NULL);
180 
181 #ifdef NX_SECURE_KEY_CLEAR
182         /* We now have a key block, clear our temporary secrets buffer. */
183         NX_SECURE_MEMSET(_nx_secure_tls_gen_keys_random, 0, sizeof(_nx_secure_tls_gen_keys_random));
184 #endif /* NX_SECURE_KEY_CLEAR  */
185 
186         if(status != NX_CRYPTO_SUCCESS)
187         {
188             /* Secrets cleared above. */
189             return(status);
190         }
191     }
192 
193     if (session_prf_method -> nx_crypto_cleanup)
194     {
195         status = session_prf_method -> nx_crypto_cleanup(prf_metadata);
196 
197         if(status != NX_CRYPTO_SUCCESS)
198         {
199             /* Secrets cleared above. */
200             return(status);
201         }
202     }
203 
204     return(NX_SECURE_TLS_SUCCESS);
205 }
206 
207