tls_kdf.c
Go to the documentation of this file.
1 /**
2  * @file tls_kdf.c
3  * @brief TLS key derivation functions
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "kdf/tls_kdf.h"
37 #include "kdf/hkdf.h"
38 #include "mac/hmac.h"
39 
40 //Check crypto library configuration
41 #if (TLS_KDF_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Pseudorandom function (TLS 1.0 and 1.1)
46  *
47  * The pseudorandom function (PRF) takes as input a secret, a seed, and
48  * an identifying label and produces an output of arbitrary length. This
49  * function is used to expand secrets into blocks of data for the purpose
50  * of key generation
51  *
52  * @param[in] secret Pointer to the secret
53  * @param[in] secretLen Length of the secret
54  * @param[in] label Identifying label (NULL-terminated string)
55  * @param[in] seed Pointer to the seed
56  * @param[in] seedLen Length of the seed
57  * @param[out] output Pointer to the output
58  * @param[in] outputLen Desired output length
59  * @return Error code
60  **/
61 
62 error_t tlsPrf(const uint8_t *secret, size_t secretLen, const char_t *label,
63  const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
64 {
65 #if (MD5_SUPPORT == ENABLED && SHA1_SUPPORT == ENABLED)
66  uint_t i;
67  uint_t j;
68  size_t labelLen;
69  size_t sLen;
70  const uint8_t *s1;
71  const uint8_t *s2;
72  HmacContext *hmacContext;
73  uint8_t a[SHA1_DIGEST_SIZE];
74 
75  //Check parameters
76  if(secret == NULL || label == NULL || seed == NULL || output == NULL)
78 
79 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
80  //Allocate a memory buffer to hold the HMAC context
81  hmacContext = cryptoAllocMem(sizeof(HmacContext));
82  //Failed to allocate memory?
83  if(hmacContext == NULL)
84  return ERROR_OUT_OF_MEMORY;
85 #endif
86 
87  //Retrieve the length of the label
88  labelLen = osStrlen(label);
89 
90  //The secret is partitioned into two halves S1 and S2
91  //with the possibility of one shared byte
92  sLen = (secretLen + 1) / 2;
93  //S1 is taken from the first half of the secret
94  s1 = secret;
95  //S2 is taken from the second half
96  s2 = secret + secretLen - sLen;
97 
98  //First compute A(1) = HMAC_MD5(S1, label + seed)
99  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
100  hmacUpdate(hmacContext, label, labelLen);
101  hmacUpdate(hmacContext, seed, seedLen);
102  hmacFinal(hmacContext, a);
103 
104  //Apply the data expansion function P_MD5
105  for(i = 0; i < outputLen; )
106  {
107  //Compute HMAC_MD5(S1, A(i) + label + seed)
108  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
109  hmacUpdate(hmacContext, a, MD5_DIGEST_SIZE);
110  hmacUpdate(hmacContext, label, labelLen);
111  hmacUpdate(hmacContext, seed, seedLen);
112  hmacFinal(hmacContext, NULL);
113 
114  //Copy the resulting digest
115  for(j = 0; i < outputLen && j < MD5_DIGEST_SIZE; i++, j++)
116  {
117  output[i] = hmacContext->digest[j];
118  }
119 
120  //Compute A(i + 1) = HMAC_MD5(S1, A(i))
121  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
122  hmacUpdate(hmacContext, a, MD5_DIGEST_SIZE);
123  hmacFinal(hmacContext, a);
124  }
125 
126  //First compute A(1) = HMAC_SHA1(S2, label + seed)
127  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
128  hmacUpdate(hmacContext, label, labelLen);
129  hmacUpdate(hmacContext, seed, seedLen);
130  hmacFinal(hmacContext, a);
131 
132  //Apply the data expansion function P_SHA1
133  for(i = 0; i < outputLen; )
134  {
135  //Compute HMAC_SHA1(S2, A(i) + label + seed)
136  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
137  hmacUpdate(hmacContext, a, SHA1_DIGEST_SIZE);
138  hmacUpdate(hmacContext, label, labelLen);
139  hmacUpdate(hmacContext, seed, seedLen);
140  hmacFinal(hmacContext, NULL);
141 
142  //Copy the resulting digest
143  for(j = 0; i < outputLen && j < SHA1_DIGEST_SIZE; i++, j++)
144  {
145  output[i] ^= hmacContext->digest[j];
146  }
147 
148  //Compute A(i + 1) = HMAC_SHA1(S2, A(i))
149  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
150  hmacUpdate(hmacContext, a, SHA1_DIGEST_SIZE);
151  hmacFinal(hmacContext, a);
152  }
153 
154 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
155  //Free previously allocated memory
156  cryptoFreeMem(hmacContext);
157 #endif
158 
159  //Successful processing
160  return NO_ERROR;
161 #else
162  //Not implemented
163  return ERROR_NOT_IMPLEMENTED;
164 #endif
165 }
166 
167 
168 /**
169  * @brief Pseudorandom function (TLS 1.2)
170  *
171  * The pseudorandom function (PRF) takes as input a secret, a seed, and
172  * an identifying label and produces an output of arbitrary length. This
173  * function is used to expand secrets into blocks of data for the purpose
174  * of key generation
175  *
176  * @param[in] hashAlgo Hash function used to compute PRF
177  * @param[in] secret Pointer to the secret
178  * @param[in] secretLen Length of the secret
179  * @param[in] label Identifying label (NULL-terminated string)
180  * @param[in] seed Pointer to the seed
181  * @param[in] seedLen Length of the seed
182  * @param[out] output Pointer to the output
183  * @param[in] outputLen Desired output length
184  * @return Error code
185  **/
186 
187 error_t tls12Prf(const HashAlgo *hashAlgo, const uint8_t *secret,
188  size_t secretLen, const char_t *label, const uint8_t *seed, size_t seedLen,
189  uint8_t *output, size_t outputLen)
190 {
191  size_t n;
192  size_t labelLen;
193  HmacContext *hmacContext;
194  uint8_t a[MAX_HASH_DIGEST_SIZE];
195 
196  //Check parameters
197  if(hashAlgo == NULL || secret == NULL || label == NULL || seed == NULL ||
198  output == NULL)
199  {
201  }
202 
203 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
204  //Allocate a memory buffer to hold the HMAC context
205  hmacContext = cryptoAllocMem(sizeof(HmacContext));
206  //Failed to allocate memory?
207  if(hmacContext == NULL)
208  return ERROR_OUT_OF_MEMORY;
209 #endif
210 
211  //Retrieve the length of the label
212  labelLen = osStrlen(label);
213 
214  //First compute A(1) = HMAC_hash(secret, label + seed)
215  hmacInit(hmacContext, hashAlgo, secret, secretLen);
216  hmacUpdate(hmacContext, label, labelLen);
217  hmacUpdate(hmacContext, seed, seedLen);
218  hmacFinal(hmacContext, a);
219 
220  //Apply the data expansion function P_hash
221  while(outputLen > 0)
222  {
223  //Compute HMAC_hash(secret, A(i) + label + seed)
224  hmacInit(hmacContext, hashAlgo, secret, secretLen);
225  hmacUpdate(hmacContext, a, hashAlgo->digestSize);
226  hmacUpdate(hmacContext, label, labelLen);
227  hmacUpdate(hmacContext, seed, seedLen);
228  hmacFinal(hmacContext, NULL);
229 
230  //Calculate the number of bytes to copy
231  n = MIN(outputLen, hashAlgo->digestSize);
232  //Copy the resulting digest
233  osMemcpy(output, hmacContext->digest, n);
234 
235  //Compute A(i + 1) = HMAC_hash(secret, A(i))
236  hmacInit(hmacContext, hashAlgo, secret, secretLen);
237  hmacUpdate(hmacContext, a, hashAlgo->digestSize);
238  hmacFinal(hmacContext, a);
239 
240  //Advance data pointer
241  output += n;
242  //Decrement byte counter
243  outputLen -= n;
244  }
245 
246 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
247  //Free previously allocated memory
248  cryptoFreeMem(hmacContext);
249 #endif
250 
251  //Successful processing
252  return NO_ERROR;
253 }
254 
255 
256 /**
257  * @brief HKDF-Expand-Label function (TLS 1.3)
258  * @param[in] hashAlgo Hash function used by HKDF
259  * @param[in] secret Pointer to the secret
260  * @param[in] secretLen Length of the secret
261  * @param[in] prefix Label prefix ("tls13 " for TLS, "dtls13" for DTLS)
262  * @param[in] label Identifying label (NULL-terminated string)
263  * @param[in] context Pointer to the upper-layer context
264  * @param[in] contextLen Length of the upper-layer context
265  * @param[out] output Pointer to the output
266  * @param[in] outputLen Desired output length
267  * @return Error code
268  **/
269 
270 error_t hkdfExpandLabel(const HashAlgo *hashAlgo, const uint8_t *secret,
271  size_t secretLen, const char_t *prefix, const char_t *label,
272  const uint8_t *context, size_t contextLen, uint8_t *output,
273  size_t outputLen)
274 {
275 #if (HKDF_SUPPORT == ENABLED)
276  error_t error;
277  size_t prefixLen;
278  size_t labelLen;
279  uint8_t temp[4];
280  DataFrag hkdfLabelFrags[6];
281 
282  //Check parameters
283  if(prefix == NULL || label == NULL)
285 
286  if(context == NULL && contextLen != 0)
288 
289  //Retrieve the length of the prefix
291  //Retrieve the length of the label
292  labelLen = osStrlen(label);
293 
294  //Check the length of the label
295  if((prefixLen + labelLen) < 7 || (prefixLen + labelLen) > 255)
296  return ERROR_INVALID_LENGTH;
297 
298  //Check the length of the context
299  if(contextLen > 255)
300  return ERROR_INVALID_LENGTH;
301 
302  //Check the length of the output
303  if(outputLen > 65535)
304  return ERROR_INVALID_LENGTH;
305 
306  //The length field is represented as a uint16
307  temp[0] = MSB(outputLen);
308  temp[1] = LSB(outputLen);
309  //The label length is represented as a uint8
310  temp[2] = (uint8_t) (prefixLen + labelLen);
311  //The context length is represented as a uint8
312  temp[3] = (uint8_t) contextLen;
313 
314  //Format HkdfLabel structure
315  hkdfLabelFrags[0].buffer = &temp[0];
316  hkdfLabelFrags[0].length = sizeof(uint16_t);
317  hkdfLabelFrags[1].buffer = &temp[2];
318  hkdfLabelFrags[1].length = sizeof(uint8_t);
319  hkdfLabelFrags[2].buffer = prefix;
320  hkdfLabelFrags[2].length = prefixLen;
321  hkdfLabelFrags[3].buffer = label;
322  hkdfLabelFrags[3].length = labelLen;
323  hkdfLabelFrags[4].buffer = &temp[3];
324  hkdfLabelFrags[4].length = sizeof(uint8_t);
325  hkdfLabelFrags[5].buffer = context;
326  hkdfLabelFrags[5].length = contextLen;
327 
328  //Compute HKDF-Expand(Secret, HkdfLabel, Length)
329  error = hkdfExpandEx(hashAlgo, secret, secretLen, hkdfLabelFrags,
330  arraysize(hkdfLabelFrags), output, outputLen);
331 
332  //Return status code
333  return error;
334 #else
335  //Not implemented
336  return ERROR_NOT_IMPLEMENTED;
337 #endif
338 }
339 
340 #endif
const void * buffer
Definition: crypto.h:1165
HMAC algorithm context.
Definition: hmac.h:59
#define SHA1_HASH_ALGO
Definition: sha1.h:49
error_t tls12Prf(const HashAlgo *hashAlgo, const uint8_t *secret, size_t secretLen, const char_t *label, const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
Pseudorandom function (TLS 1.2)
Definition: tls_kdf.c:187
uint8_t a
Definition: ndp.h:411
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
error_t tlsPrf(const uint8_t *secret, size_t secretLen, const char_t *label, const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
Pseudorandom function (TLS 1.0 and 1.1)
Definition: tls_kdf.c:62
size_t digestSize
Definition: crypto.h:1249
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define osStrlen(s)
Definition: os_port.h:171
Ipv6Addr prefix
TLS key derivation functions.
#define MAX_HASH_DIGEST_SIZE
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
error_t
Error codes.
Definition: error.h:43
#define MD5_HASH_ALGO
Definition: md5.h:49
Data fragment descriptor.
Definition: crypto.h:1164
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
#define MSB(x)
Definition: os_port.h:59
size_t length
Definition: crypto.h:1166
#define LSB(x)
Definition: os_port.h:55
#define MIN(a, b)
Definition: os_port.h:63
#define MD5_DIGEST_SIZE
Definition: md5.h:45
uint8_t secret[TLS_MASTER_SECRET_SIZE]
Master secret.
Definition: tls.h:2053
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
uint8_t prefixLen
char char_t
Definition: compiler_port.h:55
error_t hkdfExpandLabel(const HashAlgo *hashAlgo, const uint8_t *secret, size_t secretLen, const char_t *prefix, const char_t *label, const uint8_t *context, size_t contextLen, uint8_t *output, size_t outputLen)
HKDF-Expand-Label function (TLS 1.3)
Definition: tls_kdf.c:270
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
uint8_t n
HKDF (HMAC-based Key Derivation Function)
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
#define cryptoFreeMem(p)
Definition: crypto.h:966
error_t hkdfExpandEx(const HashAlgo *hashAlgo, const uint8_t *prk, size_t prkLen, const DataFrag *infoFrags, size_t infoNumFrags, uint8_t *okm, size_t okmLen)
HKDF expand step.
Definition: hkdf.c:195
#define cryptoAllocMem(size)
Definition: crypto.h:961
Common interface for hash algorithms.
Definition: crypto.h:1243
unsigned int uint_t
Definition: compiler_port.h:57
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
@ NO_ERROR
Success.
Definition: error.h:44
HMAC (Keyed-Hashing for Message Authentication)
#define arraysize(a)
Definition: os_port.h:71