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