ike_key_material.c
Go to the documentation of this file.
1 /**
2  * @file ike_key_material.c
3  * @brief Key material generation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2022-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneIPSEC 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.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL IKE_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ike/ike.h"
36 #include "ike/ike_key_material.h"
37 #include "ike/ike_algorithms.h"
38 #include "ah/ah_algorithms.h"
39 #include "esp/esp_algorithms.h"
40 #include "debug.h"
41 
42 //Check IKEv2 library configuration
43 #if (IKE_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Generate keying material for the IKE SA
48  * @param[in] sa Pointer to the IKE SA
49  * @param[in] oldSa Pointer to the old IKE SA
50  * @return Error code
51  **/
52 
54 {
55  error_t error;
56  size_t bufferLen;
57  size_t keyMaterialLen;
58  IkeContext *context;
59  uint8_t skeyseed[IKE_MAX_DIGEST_SIZE];
60  uint8_t buffer[2 * IKE_MAX_NONCE_SIZE + 2 * IKE_SPI_SIZE];
61 
62  //Point to the IKE context
63  context = sa->context;
64 
65  //Select the relevant PRF algorithm
66  error = ikeSelectPrfAlgo(sa, sa->prfAlgoId);
67  //Any error to report?
68  if(error)
69  return error;
70 
71  //Select the relevant encryption algorithm
72  error = ikeSelectEncAlgo(sa, sa->encAlgoId, sa->encKeyLen);
73  //Any error to report?
74  if(error)
75  return error;
76 
77  //AEAD encryption algorithm?
78  if(ikeIsAeadEncAlgo(sa->encAlgoId))
79  {
80  //When an authenticated encryption algorithm is selected as the encryption
81  //algorithm for any IKE SA, an integrity algorithm must not be selected
82  //for that SA (refer to RFC 5282, section 8)
83  sa->authHashAlgo = NULL;
84  sa->authCipherAlgo = NULL;
85  }
86  else
87  {
88  //Select the relevant MAC algorithm
89  error = ikeSelectAuthAlgo(sa, sa->authAlgoId);
90  //Any error to report?
91  if(error)
92  return error;
93  }
94 
95  //Length of necessary keying material
96  keyMaterialLen = 2 * sa->authKeyLen + 2 * (sa->encKeyLen + sa->saltLen) +
97  3 * sa->prfKeyLen;
98 
99  //Make sure that the buffer is large enough
100  if(keyMaterialLen > IKE_MAX_SA_KEY_MAT_LEN)
101  return ERROR_FAILURE;
102 
103  //Debug message
104  TRACE_DEBUG("Generating IKE SA keying material...\r\n");
105  TRACE_DEBUG(" Nonce (initiator):\r\n");
106  TRACE_DEBUG_ARRAY(" ", sa->initiatorNonce, sa->initiatorNonceLen);
107  TRACE_DEBUG(" Nonce (responder):\r\n");
108  TRACE_DEBUG_ARRAY(" ", sa->responderNonce, sa->responderNonceLen);
109  TRACE_DEBUG(" Shared secret:\r\n");
110  TRACE_DEBUG_ARRAY(" ", sa->sharedSecret, sa->sharedSecretLen);
111 
112  //IKE SA rekeying?
113  if(oldSa != NULL)
114  {
115  //Debug message
116  TRACE_DEBUG(" SK_d (old):\r\n");
117  TRACE_DEBUG_ARRAY(" ", oldSa->skd, oldSa->prfKeyLen);
118 
119  //Concatenate Ni and Nr
120  osMemcpy(buffer, sa->initiatorNonce, sa->initiatorNonceLen);
121  bufferLen = sa->initiatorNonceLen;
122  osMemcpy(buffer + bufferLen, sa->responderNonce, sa->responderNonceLen);
123  bufferLen += sa->responderNonceLen;
124 
125  //SKEYSEED for the new IKE SA is computed using SK_d from the existing
126  //IKE SA (refer to RFC 7296, section 2.18)
127  error = ikeInitPrf(oldSa, oldSa->skd, oldSa->prfKeyLen);
128  //Any error to report?
129  if(error)
130  return error;
131 
132  //Calculate SKEYSEED = prf(SK_d (old), g^ir (new) | Ni | Nr)
133  ikeUpdatePrf(oldSa, sa->sharedSecret, sa->sharedSecretLen);
134  ikeUpdatePrf(oldSa, buffer, bufferLen);
135 
136  //Finalize PRF calculation
137  error = ikeFinalizePrf(oldSa, skeyseed);
138  //Any error to report?
139  if(error)
140  return error;
141  }
142  else
143  {
144  //For historical backward-compatibility reasons, there are two PRFs that
145  //are treated specially in this calculation
146  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC ||
147  sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC)
148  {
149  //If the negotiated PRF is AES-XCBC-PRF-128 or AES-CMAC-PRF-128, only
150  //the first 64 bits of Ni and the first 64 bits of Nr are used in
151  //calculating SKEYSEED (refer to RFC 7296, section 2.14)
152  osMemcpy(buffer, sa->initiatorNonce, 8);
153  bufferLen = 8;
154  osMemcpy(buffer + bufferLen, sa->responderNonce, 8);
155  bufferLen += 8;
156  }
157  else
158  {
159  //Concatenate Ni and Nr
160  osMemcpy(buffer, sa->initiatorNonce, sa->initiatorNonceLen);
161  bufferLen = sa->initiatorNonceLen;
162  osMemcpy(buffer + bufferLen, sa->responderNonce, sa->responderNonceLen);
163  bufferLen += sa->responderNonceLen;
164  }
165 
166  //Each party generates a quantity called SKEYSEED = prf(Ni | Nr, g^ir)
167  error = ikeComputePrf(sa, buffer, bufferLen, sa->sharedSecret,
168  sa->sharedSecretLen, skeyseed);
169  //Any error to report?
170  if(error)
171  return error;
172  }
173 
174  //Debug message
175  TRACE_DEBUG(" SKEYSEED:\r\n");
176  TRACE_DEBUG_ARRAY(" ", skeyseed, sa->prfKeyLen);
177 
178  //Concatenate Ni, Nr, SPIi and SPIr
179  osMemcpy(buffer, sa->initiatorNonce, sa->initiatorNonceLen);
180  bufferLen = sa->initiatorNonceLen;
181  osMemcpy(buffer + bufferLen, sa->responderNonce, sa->responderNonceLen);
182  bufferLen += sa->responderNonceLen;
183  osMemcpy(buffer + bufferLen, sa->initiatorSpi, IKE_SPI_SIZE);
184  bufferLen += IKE_SPI_SIZE;
185  osMemcpy(buffer + bufferLen, sa->responderSpi, IKE_SPI_SIZE);
186  bufferLen += IKE_SPI_SIZE;
187 
188  //SKEYSEED is used to calculate seven other secrets (refer to RFC 7296,
189  //section 2.14)
190  error = ikeComputePrfPlus(sa, skeyseed, sa->prfKeyLen, buffer, bufferLen,
191  sa->keyMaterial, keyMaterialLen);
192  //Any error to report?
193  if(error)
194  return error;
195 
196  //Debug message
197  TRACE_DEBUG(" Keying material:\r\n");
198  TRACE_DEBUG_ARRAY(" ", sa->keyMaterial, keyMaterialLen);
199 
200  //SK_d is used for deriving new keys for the Child SAs established with
201  //this IKE SA
202  sa->skd = sa->keyMaterial;
203 
204  //SK_ai and SK_ar used as a key to the integrity protection algorithm
205  //for authenticating the component messages of subsequent exchanges
206  sa->skai = sa->skd + sa->prfKeyLen;
207  sa->skar = sa->skai + sa->authKeyLen;
208 
209  //SK_ei and SK_er are used for encrypting and decrypting all subsequent
210  //exchanges
211  sa->skei = sa->skar + sa->authKeyLen;
212  sa->sker = sa->skei + sa->encKeyLen + sa->saltLen;
213 
214  //SK_pi and SK_pr are used when generating an AUTH payload
215  sa->skpi = sa->sker + sa->encKeyLen + sa->saltLen;
216  sa->skpr = sa->skpi + sa->prfKeyLen;
217 
218  //Debug message
219  TRACE_DEBUG(" SK_d:\r\n");
220  TRACE_DEBUG_ARRAY(" ", sa->skd, sa->prfKeyLen);
221  TRACE_DEBUG(" SK_ai:\r\n");
222  TRACE_DEBUG_ARRAY(" ", sa->skai, sa->authKeyLen);
223  TRACE_DEBUG(" SK_ar:\r\n");
224  TRACE_DEBUG_ARRAY(" ", sa->skar, sa->authKeyLen);
225  TRACE_DEBUG(" SK_ei:\r\n");
226  TRACE_DEBUG_ARRAY(" ", sa->skei, sa->encKeyLen + sa->saltLen);
227  TRACE_DEBUG(" SK_er:\r\n");
228  TRACE_DEBUG_ARRAY(" ", sa->sker, sa->encKeyLen + sa->saltLen);
229  TRACE_DEBUG(" SK_pi:\r\n");
230  TRACE_DEBUG_ARRAY(" ", sa->skpi, sa->prfKeyLen);
231  TRACE_DEBUG(" SK_pr:\r\n");
232  TRACE_DEBUG_ARRAY(" ", sa->skpr, sa->prfKeyLen);
233 
234  //Check encryption mode
235  if(sa->cipherMode != CIPHER_MODE_CBC)
236  {
237  //The IV must be chosen by the encryptor in a manner that ensures that
238  //the same IV value is used only once for a given key (refer to RFC 5282,
239  //section 3.1)
240  error = context->prngAlgo->read(context->prngContext, sa->iv, 8);
241  //Any error to report?
242  if(error)
243  return error;
244 
245  //Debug message
246  TRACE_DEBUG(" IV:\r\n");
247  TRACE_DEBUG_ARRAY(" ", sa->iv, 8);
248  }
249 
250  //Successful processing
251  return NO_ERROR;
252 }
253 
254 
255 /**
256  * @brief Generate keying material for the Child SA
257  * @param[in] childSa Pointer to the Child SA
258  * @return Error code
259  **/
260 
262 {
263  error_t error;
264  size_t bufferLen;
265  size_t keyMaterialLen;
266  uint8_t buffer[2 * IKE_MAX_NONCE_SIZE];
267  IkeSaEntry *sa;
268 
269  //Point to the IKE SA
270  sa = childSa->sa;
271 
272 #if (AH_SUPPORT == ENABLED)
273  //AH protocol?
274  if(childSa->protocol == IPSEC_PROTOCOL_AH)
275  {
276  //AH does not provide confidentiality (encryption) service
277  childSa->cipherAlgo = NULL;
278  childSa->cipherMode = CIPHER_MODE_NULL;
279  childSa->encKeyLen = 0;
280  childSa->saltLen = 0;
281  childSa->ivLen = 0;
282 
283  //Select the relevant MAC algorithm
284  error = ahSelectAuthAlgo(childSa, childSa->authAlgoId);
285  //Any error to report?
286  if(error)
287  return error;
288  }
289  else
290 #endif
291 #if (ESP_SUPPORT == ENABLED)
292  //ESP protocol?
293  if(childSa->protocol == IPSEC_PROTOCOL_ESP)
294  {
295  //Select the relevant encryption algorithm
296  error = espSelectEncAlgo(childSa, childSa->encAlgoId, childSa->encKeyLen);
297  //Any error to report?
298  if(error)
299  return error;
300 
301  //AEAD encryption algorithm?
302  if(ikeIsAeadEncAlgo(childSa->encAlgoId))
303  {
304  //When an authenticated encryption algorithm is selected as the
305  //encryption algorithm for any IKE SA, an integrity algorithm must
306  //not be selected for that SA (refer to RFC 5282, section 8)
307  childSa->authHashAlgo = NULL;
308  childSa->authCipherAlgo = NULL;
309  }
310  else
311  {
312  //Select the relevant MAC algorithm
313  error = espSelectAuthAlgo(childSa, childSa->authAlgoId);
314  //Any error to report?
315  if(error)
316  return error;
317  }
318  }
319  else
320 #endif
321  //Invalid IPsec protocol?
322  {
323  //Report an error
324  return ERROR_INVALID_PROTOCOL;
325  }
326 
327  //Length of necessary keying material
328  keyMaterialLen = 2 * childSa->authKeyLen + 2 * (childSa->encKeyLen +
329  childSa->saltLen);
330 
331  //Make sure that the buffer is large enough
332  if(keyMaterialLen > IKE_MAX_CHILD_SA_KEY_MAT_LEN)
333  return ERROR_FAILURE;
334 
335  //Debug message
336  TRACE_DEBUG("Generating Child SA keying material...\r\n");
337  TRACE_DEBUG(" SK_d:\r\n");
338  TRACE_DEBUG_ARRAY(" ", sa->skd, sa->prfKeyLen);
339  TRACE_DEBUG(" Nonce (initiator):\r\n");
340  TRACE_DEBUG_ARRAY(" ", childSa->initiatorNonce, childSa->initiatorNonceLen);
341  TRACE_DEBUG(" Nonce (responder):\r\n");
342  TRACE_DEBUG_ARRAY(" ", childSa->responderNonce, childSa->responderNonceLen);
343 
344  //Ni and Nr are the nonces from the IKE_SA_INIT exchange if this request is
345  //the first Child SA created or the fresh Ni and Nr from the CREATE_CHILD_SA
346  //exchange if this is a subsequent creation (refer to RFC 7296, section 2.17)
347  osMemcpy(buffer, childSa->initiatorNonce, childSa->initiatorNonceLen);
348  bufferLen = childSa->initiatorNonceLen;
349  osMemcpy(buffer + bufferLen, childSa->responderNonce, childSa->responderNonceLen);
350  bufferLen += childSa->responderNonceLen;
351 
352  //Calculate KEYMAT = prf+(SK_d, Ni | Nr)
353  error = ikeComputePrfPlus(childSa->sa, sa->skd, sa->prfKeyLen, buffer,
354  bufferLen, childSa->keyMaterial, keyMaterialLen);
355  //Any error to report?
356  if(error)
357  return error;
358 
359  //Debug message
360  TRACE_DEBUG(" Keying material:\r\n");
361  TRACE_DEBUG_ARRAY(" ", childSa->keyMaterial, keyMaterialLen);
362 
363  //All keys for SAs carrying data from the initiator to the responder are
364  //taken before SAs going from the responder to the initiator. the encryption
365  //key must be taken from the first bits and the integrity key must be taken
366  //from the remaining bits (refer to RFC 7296, section 2.17)
367  childSa->skei = childSa->keyMaterial;
368  childSa->skai = childSa->skei + childSa->encKeyLen + childSa->saltLen;
369  childSa->sker = childSa->skai + childSa->authKeyLen;
370  childSa->skar = childSa->sker + childSa->encKeyLen + childSa->saltLen;
371 
372  //Debug message
373  TRACE_DEBUG(" SK_ei:\r\n");
374  TRACE_DEBUG_ARRAY(" ", childSa->skei, childSa->encKeyLen + childSa->saltLen);
375  TRACE_DEBUG(" SK_ai:\r\n");
376  TRACE_DEBUG_ARRAY(" ", childSa->skai, childSa->authKeyLen);
377  TRACE_DEBUG(" SK_er:\r\n");
378  TRACE_DEBUG_ARRAY(" ", childSa->sker, childSa->encKeyLen + childSa->saltLen);
379  TRACE_DEBUG(" SK_ar:\r\n");
380  TRACE_DEBUG_ARRAY(" ", childSa->skar, childSa->authKeyLen);
381 
382 #if (ESP_SUPPORT == ENABLED)
383  //Check ESP encryption mode
384  if(childSa->protocol == IPSEC_PROTOCOL_ESP &&
385  childSa->cipherMode != CIPHER_MODE_CBC)
386  {
387  IkeContext *context;
388 
389  //Point to the IKE context
390  context = childSa->context;
391 
392  //The IV must be chosen by the encryptor in a manner that ensures that
393  //the same IV value is used only once for a given key
394  error = context->prngAlgo->read(context->prngContext, childSa->iv, 8);
395  //Any error to report?
396  if(error)
397  return error;
398 
399  //Debug message
400  TRACE_DEBUG(" IV:\r\n");
401  TRACE_DEBUG_ARRAY(" ", childSa->iv, 8);
402  }
403 #endif
404 
405  //Successful processing
406  return NO_ERROR;
407 }
408 
409 
410 /**
411  * @brief Pseudorandom function (prf function)
412  * @param[in] sa Pointer to the IKE SA
413  * @param[in] k Pointer to the key
414  * @param[in] kLen Length of the key, in bytes
415  * @param[in] s Pointer to the data
416  * @param[in] sLen Length of the data, in bytes
417  * @param[in] output Pseudorandom output
418  * @return Error code
419  **/
420 
421 error_t ikeComputePrf(IkeSaEntry *sa, const uint8_t *k, size_t kLen,
422  const void *s, size_t sLen, uint8_t *output)
423 {
424  error_t error;
425 
426  //Initialize PRF calculation
427  error = ikeInitPrf(sa, k, kLen);
428 
429  //Check status code
430  if(!error)
431  {
432  //Update PRF calculation
433  ikeUpdatePrf(sa, s, sLen);
434 
435  //Finalize PRF calculation
436  error = ikeFinalizePrf(sa, output);
437  }
438 
439  //Return status code
440  return error;
441 }
442 
443 
444 /**
445  * @brief Function that outputs a pseudorandom stream (prf+ function)
446  * @param[in] sa Pointer to the IKE SA
447  * @param[in] k Pointer to the key
448  * @param[in] kLen Length of the key, in bytes
449  * @param[in] s Pointer to the data
450  * @param[in] sLen Length of the data, in bytes
451  * @param[out] output Pseudorandom output stream
452  * @param[in] outputLen Desired length of the pseudorandom output stream
453  * @return Error code
454  **/
455 
456 error_t ikeComputePrfPlus(IkeSaEntry *sa, const uint8_t *k, size_t kLen,
457  const uint8_t *s, size_t sLen, uint8_t *output, size_t outputLen)
458 {
459  error_t error;
460  uint8_t c;
461 
462  //Initialize status code
463  error = NO_ERROR;
464 
465  {
466  size_t n;
467  uint8_t t[IKE_MAX_DIGEST_SIZE];
468 
469  //Keying material will always be derived as the output of the negotiated
470  //PRF algorithm. Since the amount of keying material needed may be
471  //greater than the size of the output of the PRF, the PRF is used
472  //iteratively (refer to RFC 7296, section 2.13)
473  for(c = 1; outputLen > 0; c++)
474  {
475  //Initialize PRF calculation
476  error = ikeInitPrf(sa, k, kLen);
477  //Any error to report?
478  if(error)
479  break;
480 
481  //Digest T(n-1)
482  if(c > 1)
483  {
484  ikeUpdatePrf(sa, t, sa->prfKeyLen);
485  }
486 
487  //Compute T(n) = prf(K, T(n-1) | S | c)
488  ikeUpdatePrf(sa, s, sLen);
489  ikeUpdatePrf(sa, &c, sizeof(uint8_t));
490 
491  //Finalize PRF calculation
492  error = ikeFinalizePrf(sa, t);
493  //Any error to report?
494  if(error)
495  break;
496 
497  //Calculate the number of bytes to copy
498  n = MIN(outputLen, sa->prfKeyLen);
499  //Copy the output of the PRF
500  osMemcpy(output, t, n);
501 
502  //This process is repeated until enough key material is available
503  output += n;
504  outputLen -= n;
505  }
506  }
507 
508  //Return status code
509  return error;
510 }
511 
512 
513 /**
514  * @brief Initialize PRF calculation
515  * @param[in] sa Pointer to the IKE SA
516  * @param[in] vk Pointer to the variable-length key
517  * @param[in] vkLen Length of the key, in bytes
518  * @return Error code
519  **/
520 
521 error_t ikeInitPrf(IkeSaEntry *sa, const uint8_t *vk, size_t vkLen)
522 {
523  error_t error;
524 
525  //Initialize status code
526  error = NO_ERROR;
527 
528 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
529  //CMAC PRF algorithm?
530  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
531  sa->prfCipherAlgo != NULL)
532  {
533  CmacContext *cmacContext;
534  uint8_t k[16];
535 
536  //Point to the CMAC context
537  cmacContext = &sa->context->cmacContext;
538 
539  //Derive the 128-bit key K from the variable-length key VK
540  if(vkLen == 16)
541  {
542  //If the key VK is exactly 128 bits, then we use it as-is
543  osMemcpy(k, vk, vkLen);
544  }
545  else
546  {
547  //If the key VK is longer or shorter than 128 bits, then we derive the
548  //key K by applying the AES-CMAC algorithm using the 128-bit all-zero
549  //string as the key and VK as the input message (refer to RFC 4615,
550  //section 3)
551  osMemset(k, 0, 16);
552 
553  //Initialize CMAC calculation
554  error = cmacInit(cmacContext, sa->prfCipherAlgo, k, 16);
555 
556  //Check status code
557  if(!error)
558  {
559  //Compute K = AES-CMAC(0^128, VK, VKlen)
560  cmacUpdate(cmacContext, vk, vkLen);
561 
562  //Derive the 128-bit key K
563  error = cmacFinal(cmacContext, k, 16);
564  }
565  }
566 
567  //Check status code
568  if(!error)
569  {
570  //We apply the AES-CMAC algorithm using K as the key
571  error = cmacInit(cmacContext, sa->prfCipherAlgo, k, 16);
572  }
573  }
574  else
575 #endif
576 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
577  //HMAC PRF algorithm?
578  if(sa->prfHashAlgo != NULL)
579  {
580  //Initialize HMAC calculation
581  error = hmacInit(&sa->context->hmacContext, sa->prfHashAlgo, vk, vkLen);
582  }
583  else
584 #endif
585 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
586  //XCBC-MAC PRF algorithm?
587  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
588  sa->prfCipherAlgo != NULL)
589  {
590  XcbcMacContext *xcbcMacContext;
591  uint8_t k[16];
592 
593  //Point to the XCBC-MAC context
594  xcbcMacContext = &sa->context->xcbcMacContext;
595 
596  //Derive the 128-bit key K from the variable-length key VK
597  if(vkLen == 16)
598  {
599  //If the key is exactly 128 bits long, use it as-is
600  osMemcpy(k, vk, vkLen);
601  }
602  else if(vkLen < 16)
603  {
604  //If the key has fewer than 128 bits, lengthen it to exactly 128 bits
605  //by padding it on the right with zero bits
606  osMemcpy(k, vk, vkLen);
607  osMemset(k + vkLen, 0, 16 - vkLen);
608  }
609  else
610  {
611  //If the key is 129 bits or longer, shorten it to exactly 128 bits
612  //by performing the steps in AES-XCBC-PRF-128 (refer to RFC 4434,
613  //section 2)
614  osMemset(k, 0, 16);
615 
616  //The key is 128 zero bits
617  error = xcbcMacInit(xcbcMacContext, sa->prfCipherAlgo, k, 16);
618 
619  //Check status code
620  if(!error)
621  {
622  //The message is the too-long current key
623  xcbcMacUpdate(xcbcMacContext, vk, vkLen);
624 
625  //Derive the 128-bit key K
626  error = xcbcMacFinal(xcbcMacContext, k, 16);
627  }
628  }
629 
630  //Check status code
631  if(!error)
632  {
633  //We apply the XCBC-MAC algorithm using K as the key
634  error = xcbcMacInit(xcbcMacContext, sa->prfCipherAlgo, k, 16);
635  }
636  }
637  else
638 #endif
639  //Unknown PRF algorithm?
640  {
641  //Report an error
642  error = ERROR_FAILURE;
643  }
644 
645  //Return status code
646  return error;
647 }
648 
649 
650 /**
651  * @brief Update PRF calculation
652  * @param[in] sa Pointer to the IKE SA
653  * @param[in] s Pointer to the data
654  * @param[in] sLen Length of the data, in bytes
655  **/
656 
657 void ikeUpdatePrf(IkeSaEntry *sa, const uint8_t *s, size_t sLen)
658 {
659 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
660  //CMAC PRF algorithm?
661  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
662  sa->prfCipherAlgo != NULL)
663  {
664  //Update CMAC calculation
665  cmacUpdate(&sa->context->cmacContext, s, sLen);
666  }
667  else
668 #endif
669 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
670  //HMAC PRF algorithm?
671  if(sa->prfHashAlgo != NULL)
672  {
673  //Update HMAC calculation
674  hmacUpdate(&sa->context->hmacContext, s, sLen);
675  }
676  else
677 #endif
678 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
679  //XCBC-MAC PRF algorithm?
680  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
681  sa->prfCipherAlgo != NULL)
682  {
683  //Update XCBC-MAC calculation
684  xcbcMacUpdate(&sa->context->xcbcMacContext, s, sLen);
685  }
686  else
687 #endif
688  //Unknown PRF algorithm?
689  {
690  //Just for sanity
691  }
692 }
693 
694 
695 /**
696  * @brief Finalize PRF calculation
697  * @param[in] sa Pointer to the IKE SA
698  * @param[in] output Pseudorandom output
699  * @return Error code
700  **/
701 
702 error_t ikeFinalizePrf(IkeSaEntry *sa, uint8_t *output)
703 {
704  error_t error;
705 
706  //Initialize status code
707  error = NO_ERROR;
708 
709 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
710  //CMAC PRF algorithm?
711  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
712  sa->prfCipherAlgo != NULL)
713  {
714  //Finalize CMAC calculation
715  error = cmacFinal(&sa->context->cmacContext, output, sa->prfKeyLen);
716  }
717  else
718 #endif
719 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
720  //HMAC PRF algorithm?
721  if(sa->prfHashAlgo != NULL)
722  {
723  //Finalize HMAC calculation
724  hmacFinal(&sa->context->hmacContext, output);
725  }
726  else
727 #endif
728 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
729  //XCBC-MAC PRF algorithm?
730  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
731  sa->prfCipherAlgo != NULL)
732  {
733  //Finalize XCBC-MAC calculation
734  error = xcbcMacFinal(&sa->context->xcbcMacContext, output, sa->prfKeyLen);
735  }
736  else
737 #endif
738  //Unknown PRF algorithm?
739  {
740  //Report an error
741  error = ERROR_FAILURE;
742  }
743 
744  //Return status code
745  return error;
746 }
747 
748 #endif
AH algorithm negotiation.
error_t ikeSelectEncAlgo(IkeSaEntry *sa, uint16_t encAlgoId, size_t encKeyLen)
Select the relevant encryption algorithm.
XCBC-MAC algorithm context.
Definition: xcbc_mac.h:54
@ IKE_TRANSFORM_ID_PRF_AES128_CMAC
Definition: ike.h:962
@ CIPHER_MODE_CBC
Definition: crypto.h:1001
@ IPSEC_PROTOCOL_AH
Definition: ipsec.h:192
error_t ikeComputePrf(IkeSaEntry *sa, const uint8_t *k, size_t kLen, const void *s, size_t sLen, uint8_t *output)
Pseudorandom function (prf function)
#define IKE_MAX_SA_KEY_MAT_LEN
Definition: ike.h:712
uint8_t t
Definition: lldp_ext_med.h:212
ESP algorithm negotiation.
error_t ikeSelectPrfAlgo(IkeSaEntry *sa, uint16_t prfAlgoId)
Select the relevant PRF algorithm.
#define IKE_MAX_DIGEST_SIZE
Definition: ike.h:736
void xcbcMacUpdate(XcbcMacContext *context, const void *data, size_t dataLen)
Update the XCBC-MAC context with a portion of the message being hashed.
Definition: xcbc_mac.c:183
@ IPSEC_PROTOCOL_ESP
Definition: ipsec.h:193
#define IkeContext
Definition: ike.h:796
void ikeUpdatePrf(IkeSaEntry *sa, const uint8_t *s, size_t sLen)
Update PRF calculation.
error_t ikeSelectAuthAlgo(IkeSaEntry *sa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
error_t
Error codes.
Definition: error.h:43
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
Key material generation.
#define IKE_SPI_SIZE
Definition: ike.h:790
#define IKE_MAX_NONCE_SIZE
Definition: ike.h:201
error_t ikeComputePrfPlus(IkeSaEntry *sa, const uint8_t *k, size_t kLen, const uint8_t *s, size_t sLen, uint8_t *output, size_t outputLen)
Function that outputs a pseudorandom stream (prf+ function)
error_t espSelectEncAlgo(IkeChildSaEntry *childSa, uint16_t encAlgoId, size_t encKeyLen)
Select the relevant encryption algorithm.
error_t ahSelectAuthAlgo(IkeChildSaEntry *childSa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
Definition: ah_algorithms.c:94
@ IKE_TRANSFORM_ID_PRF_AES128_XCBC
Definition: ike.h:958
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
bool_t ikeIsAeadEncAlgo(uint16_t encAlgoId)
Test if the transform ID identifies an AEAD encryption algorithm.
#define MIN(a, b)
Definition: os_port.h:63
CMAC algorithm context.
Definition: cmac.h:54
IKEv2 (Internet Key Exchange Protocol)
__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
error_t xcbcMacInit(XcbcMacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize XCBC-MAC calculation.
Definition: xcbc_mac.c:107
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define IkeSaEntry
Definition: ike.h:800
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
error_t ikeGenerateChildSaKeyMaterial(IkeChildSaEntry *childSa)
Generate keying material for the Child SA.
uint8_t n
error_t ikeGenerateSaKeyMaterial(IkeSaEntry *sa, IkeSaEntry *oldSa)
Generate keying material for the IKE SA.
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
#define IKE_MAX_CHILD_SA_KEY_MAT_LEN
Definition: ike.h:719
error_t ikeInitPrf(IkeSaEntry *sa, const uint8_t *vk, size_t vkLen)
Initialize PRF calculation.
error_t cmacInit(CmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize CMAC calculation.
Definition: cmac.c:107
void cmacUpdate(CmacContext *context, const void *data, size_t dataLen)
Update the CMAC context with a portion of the message being hashed.
Definition: cmac.c:191
uint8_t s
Definition: igmp_common.h:234
error_t ikeFinalizePrf(IkeSaEntry *sa, uint8_t *output)
Finalize PRF calculation.
error_t xcbcMacFinal(XcbcMacContext *context, uint8_t *mac, size_t macLen)
Finish the XCBC-MAC calculation.
Definition: xcbc_mac.c:229
@ CIPHER_MODE_NULL
Definition: crypto.h:998
error_t espSelectAuthAlgo(IkeChildSaEntry *childSa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
#define osMemset(p, value, length)
Definition: os_port.h:138
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
#define IkeChildSaEntry
Definition: ike.h:804
error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
Finish the CMAC calculation.
Definition: cmac.c:237
IKEv2 algorithm negotiation.
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.