ike_misc.c
Go to the documentation of this file.
1 /**
2  * @file ike_misc.c
3  * @brief Helper functions for IKEv2
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_exchange.h"
37 #include "ike/ike_payload_parse.h"
38 #include "ike/ike_misc.h"
39 #include "ike/ike_debug.h"
40 #include "ipsec/ipsec_misc.h"
41 #include "debug.h"
42 
43 //Check IKEv2 library configuration
44 #if (IKE_SUPPORT == ENABLED)
45 
46 //Invalid IKE SPI value
47 const uint8_t IKE_INVALID_SPI[8] = {0};
48 
49 
50 /**
51  * @brief Retransmit IKE request message
52  * @param[in] sa Pointer to the IKE SA
53  * @return Error code
54  **/
55 
57 {
58  error_t error;
59  IkeContext *context;
60 
61  //Point to the IKE context
62  context = sa->context;
63 
64  //Debug message
65  TRACE_INFO("Retransmitting IKE request (%" PRIuSIZE " bytes)...\r\n",
66  sa->requestLen);
67 
68  //Dump IKE message for debugging purpose
69  ikeDumpMessage(sa->request, sa->requestLen);
70 
71  //A retransmission from the initiator must be bitwise identical to the
72  //original request (refer to RFC 7296, section 2.1)
73  error = socketSendTo(context->socket, &sa->remoteIpAddr, sa->remotePort,
74  sa->request, sa->requestLen, NULL, 0);
75 
76  //Retransmission times must increase exponentially to avoid flooding the
77  //network and making an existing congestion situation worse (refer to
78  //RFC 7296, section 2.4)
79  sa->timeout = MIN(sa->timeout * 2, IKE_MAX_TIMEOUT);
80 
81  //Save the time at which the message was sent
82  sa->timestamp = osGetSystemTime();
83 
84  //Increment retransmission counter
85  sa->retransmitCount++;
86 
87  //Return status code
88  return error;
89 }
90 
91 
92 /**
93  * @brief Retransmit IKE response message
94  * @param[in] sa Pointer to the IKE SA
95  * @return Error code
96  **/
97 
99 {
100  error_t error;
101  IkeContext *context;
102 
103  //Initialize status code
104  error = NO_ERROR;
105 
106  //Point to the IKE context
107  context = sa->context;
108 
109  //In order to allow saving memory, responders are allowed to forget the
110  //response after a timeout of several minutes
111  if(sa->responseLen > 0)
112  {
113  //Debug message
114  TRACE_INFO("Retransmitting IKE response (%" PRIuSIZE " bytes)...\r\n",
115  sa->responseLen);
116 
117  //Dump IKE message for debugging purpose
118  ikeDumpMessage(sa->response, sa->responseLen);
119 
120  //Retransmit the response
121  error = socketSendTo(context->socket, &context->remoteIpAddr,
122  context->remotePort, sa->response, sa->responseLen, NULL, 0);
123  }
124 
125  //Return status code
126  return error;
127 }
128 
129 
130 /**
131  * @brief Create a new IKE Security Association
132  * @param[in] context Pointer to the IKE context
133  * @return Pointer to the newly created IKE SA
134  **/
135 
137 {
138  uint_t i;
139  IkeSaEntry *sa;
140 
141  //Loop through IKE SA entries
142  for(i = 0; i < context->numSaEntries; i++)
143  {
144  //Point to the current IKE SA
145  sa = &context->sa[i];
146 
147  //Check whether the current IKE SA is free
148  if(sa->state == IKE_SA_STATE_CLOSED)
149  {
150  //Clear IKE SA entry
151  osMemset(sa, 0, sizeof(IkeSaEntry));
152 
153  //Attach IKE context
154  sa->context = context;
155 
156  //Initialize IKE SA parameters
157  sa->txMessageId = UINT32_MAX;
158  sa->rxMessageId = UINT32_MAX;
159 
160  //Initialize Diffie-Hellman context
161  ikeInitDhContext(sa);
162 
163  //Default state
164  sa->state = IKE_SA_STATE_RESERVED;
165 
166  //Return a pointer to the newly created IKE SA
167  return sa;
168  }
169  }
170 
171  //The IKE SA table runs out of space
172  return NULL;
173 }
174 
175 
176 /**
177  * @brief Find an IKE SA that matches an incoming IKE message
178  * @param[in] context Pointer to the IKE context
179  * @param[in] ikeHeader Pointer to the IKE header
180  * @return Pointer to the matching IKE SA, if any
181  **/
182 
183 IkeSaEntry *ikeFindSaEntry(IkeContext *context, const IkeHeader *ikeHeader)
184 {
185  uint_t i;
186  const uint8_t *spi;
187  IkeSaEntry *sa;
188 
189  //The I bit is used by the recipient to determine which eight octets of the
190  //SPI were generated by the recipient (refer to RFC 7296, section 3.1)
191  if((ikeHeader->flags & IKE_FLAGS_I) != 0)
192  {
193  spi = ikeHeader->responderSpi;
194  }
195  else
196  {
197  spi = ikeHeader->initiatorSpi;
198  }
199 
200  //Loop through IKE SA entries
201  for(i = 0; i < context->numSaEntries; i++)
202  {
203  //Point to the current IKE SA
204  sa = &context->sa[i];
205 
206  //Check whether the current IKE SA is active
207  if(sa->state != IKE_SA_STATE_CLOSED)
208  {
209  //Check whether the entity is the original initiator of the IKE SA
210  if(sa->originalInitiator)
211  {
212  //Compare SPIs
213  if(osMemcmp(sa->initiatorSpi, spi, IKE_SPI_SIZE) == 0)
214  {
215  //A matching IKE SA has been found
216  return sa;
217  }
218  }
219  else
220  {
221  //Compare SPIs
222  if(osMemcmp(sa->responderSpi, spi, IKE_SPI_SIZE) == 0)
223  {
224  //A matching IKE SA has been found
225  return sa;
226  }
227  }
228  }
229  }
230 
231  //The incoming IKE message does not match any IKE SA
232  return NULL;
233 }
234 
235 
236 /**
237  * @brief Find an half-open IKE SA that matches an incoming IKE_SA_INIT request
238  * @param[in] context Pointer to the IKE context
239  * @param[in] ikeHeader Pointer to the IKE header
240  * @param[in] noncePayload Pointer to the Ni payload
241  * @return Pointer to the matching IKE SA, if any
242  **/
243 
245  const IkeHeader *ikeHeader, const IkeNoncePayload *noncePayload)
246 {
247  uint_t i;
248  size_t n;
249  IkeSaEntry *sa;
250 
251  //Retrieve the length of the Ni payload
252  n = ntohs(noncePayload->header.payloadLength);
253 
254  //Check the length of the Ni payload
255  if(n >= sizeof(IkeNoncePayload))
256  {
257  //Determine the length of the nonce
258  n -= sizeof(IkeNoncePayload);
259 
260  //Loop through IKE SA entries
261  for(i = 0; i < context->numSaEntries; i++)
262  {
263  //Point to the current IKE SA
264  sa = &context->sa[i];
265 
266  //Check whether the current IKE SA is active
267  if(sa->state != IKE_SA_STATE_CLOSED)
268  {
269  //Compare SPIs
270  if(osMemcmp(sa->initiatorSpi, ikeHeader->initiatorSpi,
271  IKE_SPI_SIZE) == 0)
272  {
273  //It is not sufficient to use the initiator's SPI to lookup the
274  //IKE SA. Instead, a robust responder will do the IKE SA lookup
275  //using the whole packet, its hash, or the Ni payload (refer to
276  //RFC 7296, section 2.1)
277  if(sa->initiatorNonceLen == n && osMemcmp(sa->initiatorNonce,
278  noncePayload->nonceData, n) == 0)
279  {
280  //A matching IKE SA has been found
281  return sa;
282  }
283  }
284  }
285  }
286  }
287 
288  //The incoming IKE_SA_INIT request does not match any half-open IKE SA
289  return NULL;
290 }
291 
292 
293 /**
294  * @brief Delete an IKE Security Association
295  * @param[in] sa Pointer to the IKE SA
296  **/
297 
299 {
300  uint_t i;
301  IkeContext *context;
302  IkeChildSaEntry *childSa;
303 
304  //Debug message
305  TRACE_INFO("Deleting IKE SA...\r\n");
306 
307  //Point to the IKE context
308  context = sa->context;
309 
310  //Achieving perfect forward secrecy requires that when a connection is
311  //closed, each endpoint must forget not only the keys used by the
312  //connection but also any information that could be used to recompute
313  //those keys (refer to RFC 7296, section 2.12)
314  ikeFreeDhContext(sa);
315 
316  //Loop through Child SA entries
317  for(i = 0; i < context->numChildSaEntries; i++)
318  {
319  //Point to the current Child SA
320  childSa = &context->childSa[i];
321 
322  //Check the state of the Child SA
323  if(childSa->state != IKE_CHILD_SA_STATE_CLOSED)
324  {
325  //Deleting an IKE SA implicitly closes any remaining Child SAs
326  //negotiated under it (refer to RFC 7296, section 1.4.1)
327  if(childSa->sa == sa)
328  {
329  ikeDeleteChildSaEntry(childSa);
330  }
331  }
332  }
333 
334  //Check whether reauthentication is on-going
335  if(sa->oldSa != NULL && sa->oldSa->state != IKE_SA_STATE_CLOSED)
336  {
337  //Close the old IKE SA since reauthentication has failed
338  sa->oldSa->deleteRequest = TRUE;
339  //Notify the IKE context that the IKE SA should be closed
340  osSetEvent(&context->event);
341  }
342 
343  //Mark the IKE SA as closed
344  sa->state = IKE_SA_STATE_CLOSED;
345 }
346 
347 
348 /**
349  * @brief Delete an duplicate IKE Security Associations
350  * @param[in] sa Pointer to the currently active IKE SA
351  **/
352 
354 {
355  uint_t i;
356  IkeContext *context;
357  IkeSaEntry *entry;
358 
359  //Debug message
360  TRACE_INFO("Deleting duplicate IKE SAs...\r\n");
361 
362  //Point to the IKE context
363  context = sa->context;
364 
365  //Loop through IKE SA entries
366  for(i = 0; i < context->numSaEntries; i++)
367  {
368  //Point to the current IKE SA
369  entry = &context->sa[i];
370 
371  //Check the state of the IKE SA
372  if(entry != sa && entry->state != IKE_SA_STATE_CLOSED)
373  {
374  //Different IKE SA with same authenticated identity?
375  if(entry->peerIdType == sa->peerIdType &&
376  entry->peerIdLen == sa->peerIdLen &&
377  osMemcmp(entry->peerId, sa->peerId, sa->peerIdLen) == 0)
378  {
379  //The recipient of an INITIAL_CONTACT notification may use this
380  //information to delete any other IKE SAs it has to the same
381  //authenticated identity without waiting for a timeout (refer to
382  //RFC 7296, section 2.4)
383  ikeDeleteSaEntry(entry);
384  }
385  }
386  }
387 }
388 
389 
390 /**
391  * @brief Create a new Child Security Association
392  * @param[in] context Pointer to the IKE context
393  * @return Pointer to the newly created Child SA
394  **/
395 
397 {
398  uint_t i;
399  IkeChildSaEntry *childSa;
400 
401  //Loop through Child SA entries
402  for(i = 0; i < context->numChildSaEntries; i++)
403  {
404  //Point to the current Child SA
405  childSa = &context->childSa[i];
406 
407  //Check whether the current Child SA is free
408  if(childSa->state == IKE_CHILD_SA_STATE_CLOSED)
409  {
410  //Clear Child SA entry
411  osMemset(childSa, 0, sizeof(IkeChildSaEntry));
412 
413  //Attach IKE context
414  childSa->context = context;
415 
416  //Allocate inbound SAD entry
417  childSa->inboundSa = ipsecAllocateSadEntry(netContext.ipsecContext);
418 
419  //Failed to allocated SAD entry?
420  if(childSa->inboundSa < 0)
421  {
422  //The SAD database runs out of space
423  return NULL;
424  }
425 
426  //Allocate outbound SAD entry
427  childSa->outboundSa = ipsecAllocateSadEntry(netContext.ipsecContext);
428 
429  //Failed to allocated SAD entry?
430  if(childSa->outboundSa < 0)
431  {
432  //Clean up side effects
433  ipsecClearSadEntry(netContext.ipsecContext, childSa->inboundSa);
434  //The SAD database runs out of space
435  return NULL;
436  }
437 
438  //Default state
439  childSa->state = IKE_CHILD_SA_STATE_RESERVED;
440 
441  //Return a pointer to the newly created Child SA
442  return childSa;
443  }
444  }
445 
446  //The Child SA table runs out of space
447  return NULL;
448 }
449 
450 
451 /**
452  * @brief Find an Child SA that matches the specified SPI
453  * @param[in] sa Pointer to the IKE SA
454  * @param[in] protocolId Protocol identifier (AH or ESP)
455  * @param[in] spi Security parameter index
456  * @return Pointer to the matching Child SA, if any
457  **/
458 
460  const uint8_t *spi)
461 {
462  uint_t i;
463  IkeContext *context;
464  IkeChildSaEntry *childSa;
465 
466  //Point to the IKE context
467  context = sa->context;
468 
469  //Loop through Child SA entries
470  for(i = 0; i < context->numChildSaEntries; i++)
471  {
472  //Point to the current Child SA
473  childSa = &context->childSa[i];
474 
475  //Check the state of the Child SA
476  if(childSa->state != IKE_CHILD_SA_STATE_CLOSED)
477  {
478  //Matching IKE SA and protocol identifier?
479  if(childSa->sa == sa && childSa->protocol == protocolId)
480  {
481  //Compare SPIs
482  if(osMemcmp(childSa->remoteSpi, spi, IPSEC_SPI_SIZE) == 0)
483  {
484  //A matching Child SA has been found
485  return childSa;
486  }
487  }
488  }
489  }
490 
491  //The specified SPI does not match any Child SA
492  return NULL;
493 }
494 
495 
496 /**
497  * @brief Delete a Child Security Association
498  * @param[in] childSa Pointer to the Child SA
499  **/
500 
502 {
503  //Debug message
504  TRACE_INFO("Deleting Child SA...\r\n");
505 
506  //Close inbound SAD entry
507  if(childSa->inboundSa >= 0)
508  {
509  ipsecClearSadEntry(netContext.ipsecContext, childSa->inboundSa);
510  }
511 
512  //Close outbound SAD entry
513  if(childSa->outboundSa >= 0)
514  {
515  ipsecClearSadEntry(netContext.ipsecContext, childSa->outboundSa);
516  }
517 
518  //Mark the Child SA as closed
519  childSa->state = IKE_CHILD_SA_STATE_CLOSED;
520 }
521 
522 
523 /**
524  * @brief Generate a new IKE SA SPI
525  * @param[in] sa Pointer to the IKE SA
526  * @param[out] spi Pointer to the buffer where to store the resulting SPI
527  * @return Error code
528  **/
529 
531 {
532  error_t error;
533  uint_t i;
534  IkeContext *context;
535  IkeSaEntry *entry;
536 
537  //Debug message
538  TRACE_INFO("Generating new IKE SA SPI (%u bytes)...\r\n", IKE_SPI_SIZE);
539 
540  //Point to the IKE context
541  context = sa->context;
542 
543  //Each endpoint chooses one of the two SPIs and must choose them so as to
544  //be unique identifiers of an IKE SA (refer to RFC 7296, section 2.6)
545  do
546  {
547  //Generate an arbitrary 8-octet value
548  error = context->prngAlgo->read(context->prngContext, spi, IKE_SPI_SIZE);
549 
550  //Check status code
551  if(!error)
552  {
553  //Non-zero SPI value?
555  {
556  //Loop through IKE SA entries
557  for(i = 0; i < context->numSaEntries && !error; i++)
558  {
559  //Point to the current IKE SA
560  entry = &context->sa[i];
561 
562  //Check the state of the IKE SA
563  if(entry != sa && entry->state != IKE_SA_STATE_CLOSED)
564  {
565  //Check whether the entity is the original initiator of the
566  //IKE SA
567  if(entry->originalInitiator)
568  {
569  //Test whether the SPI is a duplicate
570  if(osMemcmp(spi, entry->initiatorSpi, IKE_SPI_SIZE) == 0)
571  {
572  error = ERROR_INVALID_SPI;
573  }
574  }
575  else
576  {
577  //Test whether the SPI is a duplicate
578  if(osMemcmp(spi, entry->responderSpi, IKE_SPI_SIZE) == 0)
579  {
580  error = ERROR_INVALID_SPI;
581  }
582  }
583  }
584  }
585  }
586  else
587  {
588  //The SPI value must not be zero (refer to RFC 7296, section 3.1)
589  error = ERROR_INVALID_SPI;
590  }
591  }
592 
593  //Repeat as necessary until a unique SPI is generated
594  } while(error == ERROR_INVALID_SPI);
595 
596  //Check status code
597  if(!error)
598  {
599  //Debug message
601  }
602 
603  //Return status code
604  return error;
605 }
606 
607 
608 /**
609  * @brief Generate a new Child SA SPI
610  * @param[in] childSa Pointer to the Child SA
611  * @param[out] spi Pointer to the buffer where to store the resulting SPI
612  * @return Error code
613  **/
614 
616 {
617  error_t error;
618  uint_t i;
619  IkeContext *context;
620  IkeChildSaEntry *entry;
621 
622  //Debug message
623  TRACE_INFO("Generating new Child SA SPI (%u bytes)...\r\n", IKE_SPI_SIZE);
624 
625  //Point to the IKE context
626  context = childSa->context;
627 
628  //Generate a unique SPI value
629  do
630  {
631  //Generate an arbitrary 4-octet value
632  error = context->prngAlgo->read(context->prngContext, spi,
634 
635  //Check status code
636  if(!error)
637  {
638  //Non-zero SPI value?
640  {
641  //Loop through Child SA entries
642  for(i = 0; i < context->numChildSaEntries && !error; i++)
643  {
644  //Point to the current Child SA
645  entry = &context->childSa[i];
646 
647  //Check the state of the Child SA
648  if(entry != childSa && entry->state != IKE_CHILD_SA_STATE_CLOSED)
649  {
650  //Test whether the SPI is a duplicate
651  if(osMemcmp(spi, entry->localSpi, IPSEC_SPI_SIZE) == 0)
652  {
653  error = ERROR_INVALID_SPI;
654  }
655  }
656  }
657  }
658  else
659  {
660  //The SPI value of zero is reserved and must not be sent on the
661  //wire (refer to RFC 4302, section 2.4 and RFC 4303, section 2.1)
662  error = ERROR_INVALID_SPI;
663  }
664  }
665 
666  //Repeat as necessary until a unique SPI is generated
667  } while(error == ERROR_INVALID_SPI);
668 
669  //Check status code
670  if(!error)
671  {
672  //Debug message
674  }
675 
676  //Return status code
677  return error;
678 }
679 
680 
681 /**
682  * @brief Generate a new nonce
683  * @param[in] context Pointer to the IKE context
684  * @param[out] nonce Pointer to the buffer where to store the resulting nonce
685  * @param[in] length Length of the nonce, in bytes
686  * @return Error code
687  **/
688 
689 error_t ikeGenerateNonce(IkeContext *context, uint8_t *nonce, size_t *length)
690 {
691  error_t error;
692 
693  //Debug message
694  TRACE_INFO("Generating new nonce (%u bytes)...\r\n", IKE_DEFAULT_NONCE_SIZE);
695 
696  //Nonces used in IKEv2 must be randomly chosen and must be at least 128 bits
697  //in size (refer to RFC 7296, section 2.10)
698  error = context->prngAlgo->read(context->prngContext, nonce,
700 
701  //Check status code
702  if(!error)
703  {
704  //Set the length of the nonce
706 
707  //Debug message
709  }
710 
711  //Return status code
712  return error;
713 }
714 
715 
716 /**
717  * @brief Apply random jitter to a time interval
718  * @param[in] context Pointer to the IKE context
719  * @param[out] delay Time interval to be randomized
720  * @return Randomized time interval
721  **/
722 
724 {
725  error_t error;
728 
729  //Maximum jitter to be applied to the time interval
730  delta = (delay * IKE_RANDOM_JITTER) / 100;
731 
732  //Sanity check
733  if(delta > 0)
734  {
735  //Generate a random value
736  error = context->prngAlgo->read(context->prngContext, (uint8_t *) &value,
737  sizeof(value));
738 
739  //Check status code
740  if(!error)
741  {
742  //Apply random jitter to the time interval
743  delay -= value % delta;
744  }
745  }
746 
747  //Return the randomized time interval
748  return delay;
749 }
750 
751 
752 /**
753  * @brief Traffic selector selection
754  * @param[in] childSa Pointer to the Child SA
755  * @param[in] tsiPayload Pointer to the TSi payload
756  * @param[in] tsrPayload Pointer to the TSr payload
757  * @return Error code
758  **/
759 
760 error_t ikeSelectTs(IkeChildSaEntry *childSa, const IkeTsPayload *tsiPayload,
761  const IkeTsPayload *tsrPayload)
762 {
763  error_t error;
764  size_t n;
765  IkeTsParams localTsParams;
766  IkeTsParams remoteTsParams;
767  IpsecSpdEntry *spdEntry;
768  IpsecSelector selector;
769 
770  //Get the length of the TSi payload
771  n = ntohs(tsiPayload->header.payloadLength);
772 
773  //Malformed TSi payload?
774  if(n < sizeof(IkeTsPayload))
775  return ERROR_INVALID_MESSAGE;
776 
777  //Check the number of traffic selectors
778  if(tsiPayload->numTs < 1)
779  return ERROR_INVALID_MESSAGE;
780 
781  //Parse the first Traffic Selector substructure of the TSi payload
782  error = ikeParseTs(tsiPayload->trafficSelectors, n - sizeof(IkeTsPayload),
783  &remoteTsParams);
784  //Any error to report?
785  if(error)
786  return error;
787 
788  //Get the length of the TSr payload
789  n = ntohs(tsrPayload->header.payloadLength);
790 
791  //Malformed TSi payload?
792  if(n < sizeof(IkeTsPayload))
793  return ERROR_INVALID_MESSAGE;
794 
795  //Check the number of traffic selectors
796  if(tsrPayload->numTs < 1)
797  return ERROR_INVALID_MESSAGE;
798 
799  //Parse the first Traffic Selector substructure of the TSr payload
800  error = ikeParseTs(tsrPayload->trafficSelectors, n - sizeof(IkeTsPayload),
801  &localTsParams);
802  //Any error to report?
803  if(error)
804  return error;
805 
806  //Make sure the IP Protocol ID fields are consistent
807  if(localTsParams.ipProtocolId != remoteTsParams.ipProtocolId)
808  return ERROR_INVALID_PROTOCOL;
809 
810  //Retrieve selector parameters
811  selector.localIpAddr.start = localTsParams.startAddr;
812  selector.localIpAddr.end = localTsParams.endAddr;
813  selector.remoteIpAddr.start = remoteTsParams.startAddr;
814  selector.remoteIpAddr.end = remoteTsParams.endAddr;
815  selector.nextProtocol = localTsParams.ipProtocolId;
816  selector.localPort.start = localTsParams.startPort;
817  selector.localPort.end = localTsParams.endPort;
818  selector.remotePort.start = remoteTsParams.startPort;
819  selector.remotePort.end = remoteTsParams.endPort;
820 
821  //A responder uses the traffic selector proposals it receives via an SA
822  //management protocol to select an appropriate entry in its SPD (refer to
823  //RFC 4301, section 4.4.1)
825  IPSEC_POLICY_ACTION_PROTECT, &selector);
826  //No matching SPD entry?
827  if(spdEntry == NULL)
828  return ERROR_INVALID_SELECTOR;
829 
830  //IKEv2 allows the responder to choose a subset of the traffic proposed by
831  //the initiator (refer to RFC 7296, section 2.9)
832  if(!ipsecIntersectSelectors(&spdEntry->selector, &selector,
833  &childSa->selector))
834  {
835  return ERROR_INVALID_SELECTOR;
836  }
837 
838  //The SPD entry specifies the security protocol (AH or ESP) to employ
839  childSa->protocol = spdEntry->protocol;
840 
841  //Successful processing
842  return NO_ERROR;
843 }
844 
845 
846 /**
847  * @brief Check whether the selected traffic selectors are acceptable
848  * @param[in] childSa Pointer to the Child SA
849  * @param[in] tsiPayload Pointer to the TSi payload
850  * @param[in] tsrPayload Pointer to the TSr payload
851  * @return Error code
852  **/
853 
854 error_t ikeCheckTs(IkeChildSaEntry *childSa, const IkeTsPayload *tsiPayload,
855  const IkeTsPayload *tsrPayload)
856 {
857  error_t error;
858  size_t n;
859  IpsecSelector selector;
860  IkeTsParams localTsParams;
861  IkeTsParams remoteTsParams;
862 
863  //Get the length of the TSi payload
864  n = ntohs(tsiPayload->header.payloadLength);
865 
866  //Malformed TSi payload?
867  if(n < sizeof(IkeTsPayload))
868  return ERROR_INVALID_MESSAGE;
869 
870  //Check the number of traffic selectors
871  if(tsiPayload->numTs < 1)
872  return ERROR_INVALID_MESSAGE;
873 
874  //Parse the first Traffic Selector substructure of the TSi payload
875  error = ikeParseTs(tsiPayload->trafficSelectors, n - sizeof(IkeTsPayload),
876  &localTsParams);
877  //Any error to report?
878  if(error)
879  return error;
880 
881  //Get the length of the TSr payload
882  n = ntohs(tsrPayload->header.payloadLength);
883 
884  //Malformed TSi payload?
885  if(n < sizeof(IkeTsPayload))
886  return ERROR_INVALID_MESSAGE;
887 
888  //Check the number of traffic selectors
889  if(tsrPayload->numTs < 1)
890  return ERROR_INVALID_MESSAGE;
891 
892  //Parse the first Traffic Selector substructure of the TSr payload
893  error = ikeParseTs(tsrPayload->trafficSelectors, n - sizeof(IkeTsPayload),
894  &remoteTsParams);
895  //Any error to report?
896  if(error)
897  return error;
898 
899  //Make sure the IP Protocol ID fields are consistent
900  if(localTsParams.ipProtocolId != remoteTsParams.ipProtocolId)
901  return ERROR_INVALID_PROTOCOL;
902 
903  //Retrieve selector parameters
904  selector.localIpAddr.start = localTsParams.startAddr;
905  selector.localIpAddr.end = localTsParams.endAddr;
906  selector.remoteIpAddr.start = remoteTsParams.startAddr;
907  selector.remoteIpAddr.end = remoteTsParams.endAddr;
908  selector.nextProtocol = localTsParams.ipProtocolId;
909  selector.localPort.start = localTsParams.startPort;
910  selector.localPort.end = localTsParams.endPort;
911  selector.remotePort.start = remoteTsParams.startPort;
912  selector.remotePort.end = remoteTsParams.endPort;
913 
914  //IKEv2 allows the responder to choose a subset of the traffic proposed by
915  //the initiator (refer to RFC 7296, section 2.9)
916  if(!ipsecIsSubsetSelector(&selector, &childSa->selector))
917  return ERROR_INVALID_SELECTOR;
918 
919  //Save traffic selector
920  childSa->selector = selector;
921 
922  //The selected traffic selectors are acceptable
923  return NO_ERROR;
924 }
925 
926 
927 /**
928  * @brief Check the length of the nonce
929  * @param[in] sa Pointer to the IKE SA
930  * @param[in] nonceLen Length of the nonce, in bytes
931  * @return Error code
932  **/
933 
935 {
936  size_t prfKeyLen;
937 
938 #if (IKE_CMAC_PRF_SUPPORT == ENABLED && IKE_AES_128_SUPPORT == ENABLED)
939  //AES-CMAC-96 PRF algorithm?
940  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_AES128_CMAC)
941  {
942  prfKeyLen = 16;
943  }
944  else
945 #endif
946 #if (IKE_HMAC_PRF_SUPPORT == ENABLED && IKE_MD5_SUPPORT == ENABLED)
947  //HMAC-MD5 PRF algorithm?
948  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_HMAC_MD5)
949  {
950  prfKeyLen = MD5_DIGEST_SIZE;
951  }
952  else
953 #endif
954 #if (IKE_HMAC_PRF_SUPPORT == ENABLED && IKE_SHA1_SUPPORT == ENABLED)
955  //HMAC-SHA1 PRF algorithm?
956  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_HMAC_SHA1)
957  {
958  prfKeyLen = SHA1_DIGEST_SIZE;
959  }
960  else
961 #endif
962 #if (IKE_HMAC_PRF_SUPPORT == ENABLED && IKE_SHA256_SUPPORT == ENABLED)
963  //HMAC-SHA256 PRF algorithm?
964  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_HMAC_SHA2_256)
965  {
966  prfKeyLen = SHA256_DIGEST_SIZE;
967  }
968  else
969 #endif
970 #if (IKE_HMAC_PRF_SUPPORT == ENABLED && IKE_SHA384_SUPPORT == ENABLED)
971  //HMAC-SHA384 PRF algorithm?
972  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_HMAC_SHA2_384)
973  {
974  prfKeyLen = SHA384_DIGEST_SIZE;
975  }
976  else
977 #endif
978 #if (IKE_HMAC_PRF_SUPPORT == ENABLED && IKE_SHA512_SUPPORT == ENABLED)
979  //HMAC-SHA512 PRF algorithm?
980  if(sa->prfAlgoId == IKE_TRANSFORM_ID_PRF_HMAC_SHA2_512)
981  {
982  prfKeyLen = SHA512_DIGEST_SIZE;
983  }
984  else
985 #endif
986  //Unknown PRF algorithm?
987  {
988  prfKeyLen = 0;
989  }
990 
991  //Nonces used in IKEv2 must be at least half the key size of the negotiated
992  //pseudorandom function (refer to RFC 7296, section 2.10)
993  if(nonceLen >= (prfKeyLen / 2))
994  {
995  return NO_ERROR;
996  }
997  else
998  {
999  return ERROR_INVALID_LENGTH;
1000  }
1001 }
1002 
1003 
1004 /**
1005  * @brief Create AH or ESP SA pair
1006  * @param[in] childSa Pointer to the Child SA
1007  * @return Error code
1008  **/
1009 
1011 {
1012  error_t error;
1013  IpsecSadEntry sadEntry;
1014 
1015  //Debug message
1016  TRACE_INFO("Creating IPsec SA pair...\r\n");
1017  TRACE_INFO(" Outbound SPI = 0x%08" PRIX32 "\r\n", LOAD32BE(childSa->remoteSpi));
1018  TRACE_INFO(" Inbound SPI = 0x%08" PRIX32 "\r\n", LOAD32BE(childSa->localSpi));
1019 
1020  //Set SAD entry parameters (outbound traffic)
1021  osMemset(&sadEntry, 0, sizeof(IpsecSadEntry));
1022  sadEntry.direction = IPSEC_DIR_OUTBOUND;
1023  sadEntry.mode = childSa->mode;
1024  sadEntry.protocol = childSa->protocol;
1025  sadEntry.selector = childSa->selector;
1026  sadEntry.spi = LOAD32BE(childSa->remoteSpi);
1027  sadEntry.authCipherAlgo = childSa->authCipherAlgo;
1028  sadEntry.authHashAlgo = childSa->authHashAlgo;
1029  sadEntry.authKeyLen = childSa->authKeyLen;
1030  sadEntry.icvLen = childSa->icvLen;
1031  sadEntry.esn = (childSa->esn == IKE_TRANSFORM_ID_ESN_YES) ? TRUE : FALSE;
1032  sadEntry.seqNum = 0;
1033  sadEntry.antiReplayEnabled = TRUE;
1034 
1035  //Set integrity protection key
1036  if(childSa->initiator)
1037  {
1038  osMemcpy(sadEntry.authKey, childSa->skai, childSa->authKeyLen);
1039  }
1040  else
1041  {
1042  osMemcpy(sadEntry.authKey, childSa->skar, childSa->authKeyLen);
1043  }
1044 
1045 #if (ESP_SUPPORT == ENABLED)
1046  //Set encryption parameters
1047  sadEntry.cipherMode = childSa->cipherMode;
1048  sadEntry.cipherAlgo = childSa->cipherAlgo;
1049  sadEntry.encKeyLen = childSa->encKeyLen;
1050  sadEntry.saltLen = childSa->saltLen;
1051  sadEntry.ivLen = childSa->ivLen;
1052 
1053  //Set encryption key
1054  if(childSa->initiator)
1055  {
1056  osMemcpy(sadEntry.encKey, childSa->skei, childSa->encKeyLen +
1057  childSa->saltLen);
1058  }
1059  else
1060  {
1061  osMemcpy(sadEntry.encKey, childSa->sker, childSa->encKeyLen +
1062  childSa->saltLen);
1063  }
1064 #endif
1065 
1066  //Update SAD entry (outbound traffic)
1067  error = ipsecSetSadEntry(netContext.ipsecContext, childSa->outboundSa,
1068  &sadEntry);
1069 
1070  //Check status code
1071  if(!error)
1072  {
1073  //Set SAD entry parameters (inbound traffic)
1074  osMemset(&sadEntry, 0, sizeof(IpsecSadEntry));
1075  sadEntry.direction = IPSEC_DIR_INBOUND;
1076  sadEntry.mode = childSa->mode;
1077  sadEntry.protocol = childSa->protocol;
1078  sadEntry.selector = childSa->selector;
1079  sadEntry.spi = LOAD32BE(childSa->localSpi);
1080  sadEntry.authCipherAlgo = childSa->authCipherAlgo;
1081  sadEntry.authHashAlgo = childSa->authHashAlgo;
1082  sadEntry.authKeyLen = childSa->authKeyLen;
1083  sadEntry.icvLen = childSa->icvLen;
1084  sadEntry.esn = (childSa->esn == IKE_TRANSFORM_ID_ESN_YES) ? TRUE : FALSE;
1085  sadEntry.seqNum = 0;
1086  sadEntry.antiReplayEnabled = TRUE;
1087 
1088  //Set integrity protection key
1089  if(childSa->initiator)
1090  {
1091  osMemcpy(sadEntry.authKey, childSa->skar, childSa->authKeyLen);
1092  }
1093  else
1094  {
1095  osMemcpy(sadEntry.authKey, childSa->skai, childSa->authKeyLen);
1096  }
1097 
1098  #if (ESP_SUPPORT == ENABLED)
1099  //Set encryption parameters
1100  sadEntry.cipherMode = childSa->cipherMode;
1101  sadEntry.cipherAlgo = childSa->cipherAlgo;
1102  sadEntry.encKeyLen = childSa->encKeyLen;
1103  sadEntry.saltLen = childSa->saltLen;
1104  sadEntry.ivLen = childSa->ivLen;
1105 
1106  //Set encryption key
1107  if(childSa->initiator)
1108  {
1109  osMemcpy(sadEntry.encKey, childSa->sker, childSa->encKeyLen +
1110  childSa->saltLen);
1111  }
1112  else
1113  {
1114  osMemcpy(sadEntry.encKey, childSa->skei, childSa->encKeyLen +
1115  childSa->saltLen);
1116  }
1117  #endif
1118 
1119  //Update SAD entry (inbound traffic)
1120  error = ipsecSetSadEntry(netContext.ipsecContext, childSa->inboundSa,
1121  &sadEntry);
1122  }
1123 
1124  //Return status code
1125  return error;
1126 }
1127 
1128 
1129 /**
1130  * @brief Test if the IKE SA is the only currently active with a given peer
1131  * @param[in] sa Pointer to the IKE SA
1132  * @return TRUE if this IKE SA is the only IKE SA currently active between the
1133  * authenticated identities, else FALSE
1134  **/
1135 
1137 {
1138  uint_t i;
1139  IkeContext *context;
1140  IkeSaEntry *entry;
1141 
1142  //Point to the IKE context
1143  context = sa->context;
1144 
1145  //Loop through IKE SA entries
1146  for(i = 0; i < context->numSaEntries; i++)
1147  {
1148  //Point to the current IKE SA
1149  entry = &context->sa[i];
1150 
1151  //Check the state of the IKE SA
1152  if(entry != sa && entry->state != IKE_SA_STATE_CLOSED)
1153  {
1154  //Check whether another IKE SA exists between the authenticated
1155  //identities
1156  if(ipCompAddr(&entry->remoteIpAddr, &sa->remoteIpAddr))
1157  {
1158  return FALSE;
1159  }
1160  }
1161  }
1162 
1163  //This IKE SA is the only IKE SA currently active between the authenticated
1164  //identities
1165  return TRUE;
1166 }
1167 
1168 #endif
uint32_t spi
Definition: ah.h:143
uint8_t delta
Definition: coap_common.h:196
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
int bool_t
Definition: compiler_port.h:53
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_SPI
Definition: error.h:296
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_INVALID_SELECTOR
Definition: error.h:300
IKEv2 (Internet Key Exchange Protocol)
@ IKE_CHILD_SA_STATE_CLOSED
Definition: ike.h:1194
@ IKE_CHILD_SA_STATE_RESERVED
Definition: ike.h:1195
@ IKE_TRANSFORM_ID_ESN_YES
Extended Sequence Numbers.
Definition: ike.h:914
#define IkeChildSaEntry
Definition: ike.h:686
#define IkeContext
Definition: ike.h:678
#define IKE_RANDOM_JITTER
Definition: ike.h:159
IkeTsPayload
Definition: ike.h:1477
IkeNoncePayload
Definition: ike.h:1425
@ IKE_SA_STATE_CLOSED
Definition: ike.h:1164
@ IKE_SA_STATE_RESERVED
Definition: ike.h:1165
#define IKE_DEFAULT_NONCE_SIZE
Definition: ike.h:194
#define IKE_MAX_TIMEOUT
Definition: ike.h:145
#define IkeSaEntry
Definition: ike.h:682
IkeHeader
Definition: ike.h:1266
#define IKE_SPI_SIZE
Definition: ike.h:672
@ IKE_TRANSFORM_ID_PRF_AES128_CMAC
Definition: ike.h:844
@ IKE_TRANSFORM_ID_PRF_HMAC_SHA2_256
Definition: ike.h:841
@ IKE_TRANSFORM_ID_PRF_HMAC_SHA2_512
Definition: ike.h:843
@ IKE_TRANSFORM_ID_PRF_HMAC_SHA1
Definition: ike.h:838
@ IKE_TRANSFORM_ID_PRF_HMAC_MD5
Definition: ike.h:837
@ IKE_TRANSFORM_ID_PRF_HMAC_SHA2_384
Definition: ike.h:842
@ IKE_FLAGS_I
Initiator flag.
Definition: ike.h:717
void ikeDumpMessage(const uint8_t *message, size_t length)
Dump IKE message.
Definition: ike_debug.c:379
Data logging functions for debugging purpose (IKEv2)
void ikeInitDhContext(IkeSaEntry *sa)
Initialize Diffie-Hellman context.
void ikeFreeDhContext(IkeSaEntry *sa)
Release Diffie-Hellman context.
Diffie-Hellman key exchange.
error_t ikeSelectTs(IkeChildSaEntry *childSa, const IkeTsPayload *tsiPayload, const IkeTsPayload *tsrPayload)
Traffic selector selection.
Definition: ike_misc.c:760
IkeSaEntry * ikeFindHalfOpenSaEntry(IkeContext *context, const IkeHeader *ikeHeader, const IkeNoncePayload *noncePayload)
Find an half-open IKE SA that matches an incoming IKE_SA_INIT request.
Definition: ike_misc.c:244
error_t ikeRetransmitRequest(IkeSaEntry *sa)
Retransmit IKE request message.
Definition: ike_misc.c:56
error_t ikeGenerateSaSpi(IkeSaEntry *sa, uint8_t *spi)
Generate a new IKE SA SPI.
Definition: ike_misc.c:530
void ikeDeleteSaEntry(IkeSaEntry *sa)
Delete an IKE Security Association.
Definition: ike_misc.c:298
void ikeDeleteChildSaEntry(IkeChildSaEntry *childSa)
Delete a Child Security Association.
Definition: ike_misc.c:501
error_t ikeGenerateChildSaSpi(IkeChildSaEntry *childSa, uint8_t *spi)
Generate a new Child SA SPI.
Definition: ike_misc.c:615
error_t ikeGenerateNonce(IkeContext *context, uint8_t *nonce, size_t *length)
Generate a new nonce.
Definition: ike_misc.c:689
IkeChildSaEntry * ikeCreateChildSaEntry(IkeContext *context)
Create a new Child Security Association.
Definition: ike_misc.c:396
void ikeDeleteDuplicateSaEntries(IkeSaEntry *sa)
Delete an duplicate IKE Security Associations.
Definition: ike_misc.c:353
systime_t ikeRandomizeDelay(IkeContext *context, systime_t delay)
Apply random jitter to a time interval.
Definition: ike_misc.c:723
IkeSaEntry * ikeFindSaEntry(IkeContext *context, const IkeHeader *ikeHeader)
Find an IKE SA that matches an incoming IKE message.
Definition: ike_misc.c:183
error_t ikeRetransmitResponse(IkeSaEntry *sa)
Retransmit IKE response message.
Definition: ike_misc.c:98
error_t ikeCreateIpsecSaPair(IkeChildSaEntry *childSa)
Create AH or ESP SA pair.
Definition: ike_misc.c:1010
const uint8_t IKE_INVALID_SPI[8]
Definition: ike_misc.c:47
IkeSaEntry * ikeCreateSaEntry(IkeContext *context)
Create a new IKE Security Association.
Definition: ike_misc.c:136
bool_t ikeIsInitialContact(IkeSaEntry *sa)
Test if the IKE SA is the only currently active with a given peer.
Definition: ike_misc.c:1136
IkeChildSaEntry * ikeFindChildSaEntry(IkeSaEntry *sa, uint8_t protocolId, const uint8_t *spi)
Find an Child SA that matches the specified SPI.
Definition: ike_misc.c:459
error_t ikeCheckTs(IkeChildSaEntry *childSa, const IkeTsPayload *tsiPayload, const IkeTsPayload *tsrPayload)
Check whether the selected traffic selectors are acceptable.
Definition: ike_misc.c:854
error_t ikeCheckNonceLength(IkeSaEntry *sa, size_t nonceLen)
Check the length of the nonce.
Definition: ike_misc.c:934
Helper functions for IKEv2.
error_t ikeParseTs(const uint8_t *p, size_t length, IkeTsParams *tsParams)
Parse Traffic Selector substructure.
IKE payload parsing.
bool_t ipCompAddr(const IpAddr *ipAddr1, const IpAddr *ipAddr2)
Compare IP addresses.
Definition: ip.c:315
error_t ipsecSetSadEntry(IpsecContext *context, uint_t index, IpsecSadEntry *params)
Set entry at specified index in SAD database.
Definition: ipsec.c:185
error_t ipsecClearSadEntry(IpsecContext *context, uint_t index)
Clear entry at specified index in SAD database.
Definition: ipsec.c:260
#define IPSEC_SPI_SIZE
Definition: ipsec.h:138
#define IpsecSadEntry
Definition: ipsec.h:36
@ IPSEC_POLICY_ACTION_PROTECT
Definition: ipsec.h:233
@ IPSEC_DIR_OUTBOUND
Definition: ipsec.h:168
@ IPSEC_DIR_INBOUND
Definition: ipsec.h:167
int_t ipsecAllocateSadEntry(IpsecContext *context)
Allocate a new entry in the SAD database.
Definition: ipsec_misc.c:96
bool_t ipsecIntersectSelectors(const IpsecSelector *selector1, const IpsecSelector *selector2, IpsecSelector *result)
Calculate the intersection of two selectors.
Definition: ipsec_misc.c:545
const uint8_t IPSEC_INVALID_SPI[4]
Definition: ipsec_misc.c:40
IpsecSpdEntry * ipsecFindSpdEntry(IpsecContext *context, IpsecPolicyAction policyAction, const IpsecSelector *selector)
Search the SPD database for a matching entry.
Definition: ipsec_misc.c:51
bool_t ipsecIsSubsetSelector(const IpsecSelector *selector1, const IpsecSelector *selector2)
Test if a selector is a subset of another selector.
Definition: ipsec_misc.c:362
Helper routines for IPsec.
uint8_t protocolId[]
#define MD5_DIGEST_SIZE
Definition: md5.h:45
NetContext netContext
Definition: net.c:75
#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
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
systime_t osGetSystemTime(void)
Retrieve system time.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
uint32_t systime_t
System time.
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
#define SHA384_DIGEST_SIZE
Definition: sha384.h:41
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
error_t socketSendTo(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written, uint_t flags)
Send a datagram to a specific destination.
Definition: socket.c:967
Traffic selector parameters.
Definition: ike.h:1608
IpAddr endAddr
Definition: ike.h:1610
uint8_t ipProtocolId
Definition: ike.h:1611
uint16_t startPort
Definition: ike.h:1612
uint16_t endPort
Definition: ike.h:1613
IpAddr startAddr
Definition: ike.h:1609
IpAddr start
Definition: ipsec.h:281
IpAddr end
Definition: ipsec.h:282
uint16_t start
Definition: ipsec.h:292
uint16_t end
Definition: ipsec.h:293
IPsec selector.
Definition: ipsec.h:302
IpsecPortRange localPort
Local port range.
Definition: ipsec.h:306
IpsecAddrRange localIpAddr
Local IP address range.
Definition: ipsec.h:303
IpsecAddrRange remoteIpAddr
Remote IP address range.
Definition: ipsec.h:304
uint8_t nextProtocol
Next layer protocol.
Definition: ipsec.h:305
IpsecPortRange remotePort
Remote port range.
Definition: ipsec.h:307
Security Policy Database (SPD) entry.
Definition: ipsec.h:344
IpsecProtocol protocol
Security protocol (AH or ESP)
Definition: ipsec.h:349
IpsecSelector selector
Traffic selector.
Definition: ipsec.h:347
void * ipsecContext
IPsec context.
Definition: net.h:329
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369