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-2024 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.4.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[MAX_HASH_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  size_t n;
461  uint8_t c;
462  uint8_t t[MAX_HASH_DIGEST_SIZE];
463 
464  //Initialize status code
465  error = NO_ERROR;
466 
467  //Keying material will always be derived as the output of the negotiated
468  //PRF algorithm. Since the amount of keying material needed may be greater
469  //than the size of the output of the PRF, the PRF is used iteratively
470  for(c = 1; outputLen > 0; c++)
471  {
472  //Initialize PRF calculation
473  error = ikeInitPrf(sa, k, kLen);
474  //Any error to report?
475  if(error)
476  break;
477 
478  //Digest T(n-1)
479  if(c > 1)
480  {
481  ikeUpdatePrf(sa, t, sa->prfKeyLen);
482  }
483 
484  //Compute T(n) = prf(K, T(n-1) | S | c)
485  ikeUpdatePrf(sa, s, sLen);
486  ikeUpdatePrf(sa, &c, sizeof(uint8_t));
487 
488  //Finalize PRF calculation
489  error = ikeFinalizePrf(sa, t);
490  //Any error to report?
491  if(error)
492  break;
493 
494  //Calculate the number of bytes to copy
495  n = MIN(outputLen, sa->prfKeyLen);
496  //Copy the output of the PRF
497  osMemcpy(output, t, n);
498 
499  //This process is repeated until enough key material is available
500  output += n;
501  outputLen -= n;
502  }
503 
504  //Return status code
505  return error;
506 }
507 
508 
509 /**
510  * @brief Initialize PRF calculation
511  * @param[in] sa Pointer to the IKE SA
512  * @param[in] vk Pointer to the variable-length key
513  * @param[in] vkLen Length of the key, in bytes
514  * @return Error code
515  **/
516 
517 error_t ikeInitPrf(IkeSaEntry *sa, const uint8_t *vk, size_t vkLen)
518 {
519  error_t error;
520 
521  //Initialize status code
522  error = NO_ERROR;
523 
524 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
525  //HMAC PRF algorithm?
526  if(sa->prfHashAlgo != NULL)
527  {
528  //Initialize HMAC calculation
529  error = hmacInit(&sa->context->hmacContext, sa->prfHashAlgo, vk, vkLen);
530  }
531  else
532 #endif
533 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
534  //CMAC PRF algorithm?
535  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
536  sa->prfCipherAlgo != NULL)
537  {
538  CmacContext *cmacContext;
539  uint8_t k[16];
540 
541  //Point to the CMAC context
542  cmacContext = &sa->context->cmacContext;
543 
544  //Derive the 128-bit key K from the variable-length key VK
545  if(vkLen == 16)
546  {
547  //If the key VK is exactly 128 bits, then we use it as-is
548  osMemcpy(k, vk, vkLen);
549  }
550  else
551  {
552  //If the key VK is longer or shorter than 128 bits, then we derive the
553  //key K by applying the AES-CMAC algorithm using the 128-bit all-zero
554  //string as the key and VK as the input message (refer to RFC 4615,
555  //section 3)
556  osMemset(k, 0, 16);
557 
558  //Initialize CMAC calculation
559  error = cmacInit(cmacContext, sa->prfCipherAlgo, k, 16);
560 
561  //Check status code
562  if(!error)
563  {
564  //Compute K = AES-CMAC(0^128, VK, VKlen)
565  cmacUpdate(cmacContext, vk, vkLen);
566 
567  //Derive the 128-bit key K
568  error = cmacFinal(cmacContext, k, 16);
569  }
570  }
571 
572  //Check status code
573  if(!error)
574  {
575  //We apply the AES-CMAC algorithm using K as the key
576  error = cmacInit(cmacContext, sa->prfCipherAlgo, k, 16);
577  }
578  }
579  else
580 #endif
581 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
582  //XCBC-MAC PRF algorithm?
583  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
584  sa->prfCipherAlgo != NULL)
585  {
586  XcbcMacContext *xcbcMacContext;
587  uint8_t k[16];
588 
589  //Point to the XCBC-MAC context
590  xcbcMacContext = &sa->context->xcbcMacContext;
591 
592  //Derive the 128-bit key K from the variable-length key VK
593  if(vkLen == 16)
594  {
595  //If the key is exactly 128 bits long, use it as-is
596  osMemcpy(k, vk, vkLen);
597  }
598  else if(vkLen < 16)
599  {
600  //If the key has fewer than 128 bits, lengthen it to exactly 128 bits
601  //by padding it on the right with zero bits
602  osMemcpy(k, vk, vkLen);
603  osMemset(k + vkLen, 0, 16 - vkLen);
604  }
605  else
606  {
607  //If the key is 129 bits or longer, shorten it to exactly 128 bits
608  //by performing the steps in AES-XCBC-PRF-128 (refer to RFC 4434,
609  //section 2)
610  osMemset(k, 0, 16);
611 
612  //The key is 128 zero bits
613  error = xcbcMacInit(xcbcMacContext, sa->prfCipherAlgo, k, 16);
614 
615  //Check status code
616  if(!error)
617  {
618  //The message is the too-long current key
619  xcbcMacUpdate(xcbcMacContext, vk, vkLen);
620 
621  //Derive the 128-bit key K
622  error = xcbcMacFinal(xcbcMacContext, k, 16);
623  }
624  }
625 
626  //Check status code
627  if(!error)
628  {
629  //We apply the XCBC-MAC algorithm using K as the key
630  error = xcbcMacInit(xcbcMacContext, sa->prfCipherAlgo, k, 16);
631  }
632  }
633  else
634 #endif
635  //Unknown PRF algorithm?
636  {
637  //Report an error
638  error = ERROR_FAILURE;
639  }
640 
641  //Return status code
642  return error;
643 }
644 
645 
646 /**
647  * @brief Update PRF calculation
648  * @param[in] sa Pointer to the IKE SA
649  * @param[in] s Pointer to the data
650  * @param[in] sLen Length of the data, in bytes
651  **/
652 
653 void ikeUpdatePrf(IkeSaEntry *sa, const uint8_t *s, size_t sLen)
654 {
655 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
656  //HMAC PRF algorithm?
657  if(sa->prfHashAlgo != NULL)
658  {
659  //Update HMAC calculation
660  hmacUpdate(&sa->context->hmacContext, s, sLen);
661  }
662  else
663 #endif
664 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
665  //CMAC PRF algorithm?
666  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
667  sa->prfCipherAlgo != NULL)
668  {
669  //Update CMAC calculation
670  cmacUpdate(&sa->context->cmacContext, s, sLen);
671  }
672  else
673 #endif
674 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
675  //XCBC-MAC PRF algorithm?
676  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
677  sa->prfCipherAlgo != NULL)
678  {
679  //Update XCBC-MAC calculation
680  xcbcMacUpdate(&sa->context->xcbcMacContext, s, sLen);
681  }
682  else
683 #endif
684  //Unknown PRF algorithm?
685  {
686  //Just for sanity
687  }
688 }
689 
690 
691 /**
692  * @brief Finalize PRF calculation
693  * @param[in] sa Pointer to the IKE SA
694  * @param[in] output Pseudorandom output
695  * @return Error code
696  **/
697 
698 error_t ikeFinalizePrf(IkeSaEntry *sa, uint8_t *output)
699 {
700  error_t error;
701 
702  //Initialize status code
703  error = NO_ERROR;
704 
705 #if (IKE_HMAC_PRF_SUPPORT == ENABLED)
706  //HMAC PRF algorithm?
707  if(sa->prfHashAlgo != NULL)
708  {
709  //Finalize HMAC calculation
710  hmacFinal(&sa->context->hmacContext, output);
711  }
712  else
713 #endif
714 #if (IKE_CMAC_PRF_SUPPORT == ENABLED)
715  //CMAC PRF algorithm?
716  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC &&
717  sa->prfCipherAlgo != NULL)
718  {
719  //Finalize CMAC calculation
720  error = cmacFinal(&sa->context->cmacContext, output, sa->prfKeyLen);
721  }
722  else
723 #endif
724 #if (IKE_XCBC_MAC_PRF_SUPPORT == ENABLED)
725  //XCBC-MAC PRF algorithm?
726  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_XCBC &&
727  sa->prfCipherAlgo != NULL)
728  {
729  //Finalize XCBC-MAC calculation
730  error = xcbcMacFinal(&sa->context->xcbcMacContext, output, sa->prfKeyLen);
731  }
732  else
733 #endif
734  //Unknown PRF algorithm?
735  {
736  //Report an error
737  error = ERROR_FAILURE;
738  }
739 
740  //Return status code
741  return error;
742 }
743 
744 #endif
error_t ahSelectAuthAlgo(IkeChildSaEntry *childSa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
Definition: ah_algorithms.c:94
AH algorithm negotiation.
error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
Finish the CMAC calculation.
Definition: cmac.c:237
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
error_t cmacInit(CmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize CMAC calculation.
Definition: cmac.c:107
@ CIPHER_MODE_CBC
Definition: crypto.h:945
@ CIPHER_MODE_NULL
Definition: crypto.h:942
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
error_t espSelectAuthAlgo(IkeChildSaEntry *childSa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
error_t espSelectEncAlgo(IkeChildSaEntry *childSa, uint16_t encAlgoId, size_t encKeyLen)
Select the relevant encryption algorithm.
ESP algorithm negotiation.
#define MAX_HASH_DIGEST_SIZE
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
__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
IKEv2 (Internet Key Exchange Protocol)
#define IkeChildSaEntry
Definition: ike.h:686
#define IkeContext
Definition: ike.h:678
#define IKE_MAX_CHILD_SA_KEY_MAT_LEN
Definition: ike.h:621
#define IKE_MAX_SA_KEY_MAT_LEN
Definition: ike.h:614
#define IkeSaEntry
Definition: ike.h:682
#define IKE_SPI_SIZE
Definition: ike.h:672
#define IKE_MAX_NONCE_SIZE
Definition: ike.h:201
@ IKE_TRANSFORM_ID_PRF_AES128_CMAC
Definition: ike.h:844
@ IKE_TRANSFORM_ID_PRF_AES128_XCBC
Definition: ike.h:840
bool_t ikeIsAeadEncAlgo(uint16_t encAlgoId)
Test if the transform ID identifies an AEAD encryption algorithm.
error_t ikeSelectAuthAlgo(IkeSaEntry *sa, uint16_t authAlgoId)
Select the relevant MAC algorithm.
error_t ikeSelectEncAlgo(IkeSaEntry *sa, uint16_t encAlgoId, size_t encKeyLen)
Select the relevant encryption algorithm.
error_t ikeSelectPrfAlgo(IkeSaEntry *sa, uint16_t prfAlgoId)
Select the relevant PRF algorithm.
IKEv2 algorithm negotiation.
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)
error_t ikeGenerateSaKeyMaterial(IkeSaEntry *sa, IkeSaEntry *oldSa)
Generate keying material for the IKE SA.
void ikeUpdatePrf(IkeSaEntry *sa, const uint8_t *s, size_t sLen)
Update PRF calculation.
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 ikeGenerateChildSaKeyMaterial(IkeChildSaEntry *childSa)
Generate keying material for the Child SA.
error_t ikeFinalizePrf(IkeSaEntry *sa, uint8_t *output)
Finalize PRF calculation.
error_t ikeInitPrf(IkeSaEntry *sa, const uint8_t *vk, size_t vkLen)
Initialize PRF calculation.
Key material generation.
@ IPSEC_PROTOCOL_ESP
Definition: ipsec.h:193
@ IPSEC_PROTOCOL_AH
Definition: ipsec.h:192
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t c
Definition: ndp.h:514
uint8_t s
Definition: ndp.h:345
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
CMAC algorithm context.
Definition: cmac.h:54
XCBC-MAC algorithm context.
Definition: xcbc_mac.h:54
error_t xcbcMacFinal(XcbcMacContext *context, uint8_t *mac, size_t macLen)
Finish the XCBC-MAC calculation.
Definition: xcbc_mac.c:229
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
error_t xcbcMacInit(XcbcMacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize XCBC-MAC calculation.
Definition: xcbc_mac.c:107