ike_key_exchange.c
Go to the documentation of this file.
1 /**
2  * @file ike_key_exchange.c
3  * @brief Diffie-Hellman key exchange
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.2
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_algorithms.h"
38 #include "ike/ike_dh_groups.h"
39 #include "debug.h"
40 
41 //Check IKEv2 library configuration
42 #if (IKE_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Initialize Diffie-Hellman context
47  * @param[in] sa Pointer to the IKE SA
48  **/
49 
51 {
52 #if (IKE_DH_KE_SUPPORT == ENABLED)
53  //Initialize Diffie-Hellman context
54  dhInit(&sa->dhContext);
55 #endif
56 
57 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
58  //Initialize ECDH context
59  ecdhInit(&sa->ecdhContext);
60 #endif
61 }
62 
63 
64 /**
65  * @brief Release Diffie-Hellman context
66  * @param[in] sa Pointer to the IKE SA
67  **/
68 
70 {
71 #if (IKE_DH_KE_SUPPORT == ENABLED)
72  //Release Diffie-Hellman context
73  dhFree(&sa->dhContext);
74 #endif
75 
76 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
77  //Release ECDH context
78  ecdhFree(&sa->ecdhContext);
79 #endif
80 }
81 
82 
83 /**
84  * @brief Diffie-Hellman key pair generation
85  * @param[in] sa Pointer to the IKE SA
86  * @return Error code
87  **/
88 
90 {
91  error_t error;
92  IkeContext *context;
93 
94  //Point to the IKE context
95  context = sa->context;
96 
97  //Debug message
98  TRACE_INFO("Generating Diffie-Hellman key pair...\r\n");
99 
100 #if (IKE_DH_KE_SUPPORT == ENABLED)
101  //Diffie-Hellman key exchange algorithm?
102  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
103  {
104  //Load Diffie-Hellman parameters
105  error = ikeLoadDhParams(&sa->dhContext.params, sa->dhGroupNum);
106 
107  //Check status code
108  if(!error)
109  {
110  //Generate an ephemeral key pair
111  error = dhGenerateKeyPair(&sa->dhContext, context->prngAlgo,
112  context->prngContext);
113  }
114  }
115  else
116 #endif
117 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
118  //ECDH key exchange algorithm?
119  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
120  {
121  const EcCurve *curve;
122 
123  //Get the elliptic curve that matches the specified group number
124  curve = ikeGetEcdhCurve(sa->dhGroupNum);
125 
126  //Valid elliptic curve?
127  if(curve != NULL)
128  {
129  //Save elliptic curve parameters
130  error = ecdhSetCurve(&sa->ecdhContext, curve);
131 
132  //Check status code
133  if(!error)
134  {
135  //Generate an ephemeral key pair
136  error = ecdhGenerateKeyPair(&sa->ecdhContext, context->prngAlgo,
137  context->prngContext);
138  }
139  }
140  else
141  {
142  //Report an error
143  error = ERROR_UNSUPPORTED_TYPE;
144  }
145  }
146  else
147 #endif
148  //Unknown key exchange algorithm?
149  {
150  //Report an error
152  }
153 
154  //Return status code
155  return error;
156 }
157 
158 
159 /**
160  * @brief Compute Diffie-Hellman shared secret
161  * @param[in] sa Pointer to the IKE SA
162  * @return Error code
163  **/
164 
166 {
167  error_t error;
168 
169  //Debug message
170  TRACE_INFO("Computing Diffie-Hellman shared secret...\r\n");
171 
172 #if (IKE_DH_KE_SUPPORT == ENABLED)
173  //Diffie-Hellman key exchange algorithm?
174  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
175  {
176  //Let g^ir be the shared secret from the ephemeral Diffie-Hellman
177  //exchange
178  error = dhComputeSharedSecret(&sa->dhContext, sa->sharedSecret,
179  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
180  }
181  else
182 #endif
183 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
184  //ECDH key exchange algorithm?
185  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
186  {
187  //The Diffie-Hellman shared secret value consists of the x value of the
188  //Diffie-Hellman common value (refer to RFC 5903, section 7)
189  error = ecdhComputeSharedSecret(&sa->ecdhContext, sa->sharedSecret,
190  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
191  }
192  else
193 #endif
194  //Unknown key exchange algorithm?
195  {
196  //Report an error
198  }
199 
200  //Return status code
201  return error;
202 }
203 
204 
205 /**
206  * @brief Format Diffie-Hellman public key
207  * @param[in] sa Pointer to the IKE SA
208  * @param[out] p Buffer where to format the Diffie-Hellman public key
209  * @param[out] written Total number of bytes that have been written
210  * @return Error code
211  **/
212 
213 error_t ikeFormatDhPublicKey(IkeSaEntry *sa, uint8_t *p, size_t *written)
214 {
215  error_t error;
216 
217 #if (IKE_DH_KE_SUPPORT == ENABLED)
218  //Diffie-Hellman key exchange algorithm?
219  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
220  {
221  //The length of the Diffie-Hellman public value for MODP groups must be
222  //equal to the length of the prime modulus over which the exponentiation
223  //was performed, prepending zero bits to the value if necessary (refer
224  //to RFC 7296, section 3.4)
225  error = dhExportPublicKey(&sa->dhContext, p, written,
227  }
228  else
229 #endif
230 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
231  //ECDH key exchange algorithm?
232  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
233  {
234  //The Diffie-Hellman public value is obtained by concatenating the x and
235  //y values (refer to RFC 5903, section 7)
236  error = ecdhExportPublicKey(&sa->ecdhContext, p, written,
238  }
239  else
240 #endif
241  //Unknown key exchange algorithm?
242  {
243  //Report an error
245  }
246 
247  //Return status code
248  return error;
249 }
250 
251 
252 /**
253  * @brief Parse peer's Diffie-Hellman public key
254  * @param[in] sa Pointer to the IKE SA
255  * @param[out] p Pointer the Diffie-Hellman public key
256  * @param[out] length Length of the Diffie-Hellman public key, in bytes
257  * @return Error code
258  **/
259 
260 error_t ikeParseDhPublicKey(IkeSaEntry *sa, const uint8_t *p, size_t length)
261 {
262  error_t error;
263 
264 #if (IKE_DH_KE_SUPPORT == ENABLED)
265  //Diffie-Hellman key exchange algorithm?
266  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
267  {
268  const IkeDhGroup *dhGroup;
269 
270  //Get the Diffie-Hellman group that matches the specified group number
271  dhGroup = ikeGetDhGroup(sa->dhGroupNum);
272 
273  //Valid Diffie-Hellman group?
274  if(dhGroup != NULL)
275  {
276  //The length of the Diffie-Hellman public value for MODP groups must
277  //be equal to the length of the prime modulus over which the
278  //exponentiation was performed, prepending zero bits to the value if
279  //necessary (refer to RFC 7296, section 3.4)
280  if(length == dhGroup->pLen)
281  {
282  //Load Diffie-Hellman parameters
283  error = ikeLoadDhParams(&sa->dhContext.params, sa->dhGroupNum);
284 
285  //Check status code
286  if(!error)
287  {
288  //Load peer's Diffie-Hellman public value
289  error = dhImportPeerPublicKey(&sa->dhContext, p, length,
291  }
292  }
293  else
294  {
295  //Report an error
296  error = ERROR_INVALID_SYNTAX;
297  }
298  }
299  else
300  {
301  //Report an error
302  error = ERROR_INVALID_GROUP;
303  }
304  }
305  else
306 #endif
307 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
308  //ECDH key exchange algorithm?
309  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
310  {
311  const EcCurve *curve;
312 
313  //Get the elliptic curve that matches the specified group number
314  curve = ikeGetEcdhCurve(sa->dhGroupNum);
315 
316  //Valid elliptic curve?
317  if(curve != NULL)
318  {
319  //Save elliptic curve parameters
320  error = ecdhSetCurve(&sa->ecdhContext, curve);
321 
322  //Check status code
323  if(!error)
324  {
325  //In an ECP key exchange, the Diffie-Hellman public value passed in
326  //a KE payload consists of two components, x and y, corresponding to
327  //the coordinates of an elliptic curve point
328  error = ecdhImportPeerPublicKey(&sa->ecdhContext, p, length,
330  }
331  }
332  else
333  {
334  //Report an error
335  error = ERROR_INVALID_GROUP;
336  }
337  }
338  else
339 #endif
340  //Unknown key exchange algorithm?
341  {
342  //Report an error
343  error = ERROR_INVALID_GROUP;
344  }
345 
346  //Return status code
347  return error;
348 }
349 
350 #endif
@ ERROR_UNSUPPORTED_TYPE
Definition: error.h:125
Diffie-Hellman key exchange.
error_t ikeParseDhPublicKey(IkeSaEntry *sa, const uint8_t *p, size_t length)
Parse peer's Diffie-Hellman public key.
uint8_t p
Definition: ndp.h:300
void ecdhFree(EcdhContext *context)
Release ECDH context.
Definition: ecdh.c:65
Diffie-Hellman group.
Definition: ike_dh_groups.h:49
size_t pLen
Length of the prime modulus, in bytes.
Definition: ike_dh_groups.h:52
#define IKE_MAX_SHARED_SECRET_LEN
Definition: ike.h:774
#define IkeContext
Definition: ike.h:796
@ ERROR_INVALID_GROUP
Definition: error.h:276
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute Diffie-Hellman shared secret.
Definition: dh.c:289
error_t ikeComputeDhSharedSecret(IkeSaEntry *sa)
Compute Diffie-Hellman shared secret.
void ikeInitDhContext(IkeSaEntry *sa)
Initialize Diffie-Hellman context.
error_t
Error codes.
Definition: error.h:43
void dhFree(DhContext *context)
Release Diffie-Hellman context.
Definition: dh.c:71
bool_t ikeIsDhKeyExchangeAlgo(uint16_t groupNum)
Test if the group number identifies a DH key exchange algorithm.
@ EC_PUBLIC_KEY_FORMAT_RAW
Definition: ec.h:387
error_t dhImportPeerPublicKey(DhContext *context, const uint8_t *input, size_t length, MpiFormat format)
Import peer's public key.
Definition: dh.c:218
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
error_t dhExportPublicKey(DhContext *context, uint8_t *output, size_t *written, MpiFormat format)
Export our own public key.
Definition: dh.c:185
error_t ikeGenerateDhKeyPair(IkeSaEntry *sa)
Diffie-Hellman key pair generation.
error_t ecdhComputeSharedSecret(EcdhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute ECDH shared secret.
Definition: ecdh.c:415
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
IKEv2 (Internet Key Exchange Protocol)
error_t ecdhImportPeerPublicKey(EcdhContext *context, const uint8_t *input, size_t length, EcPublicKeyFormat format)
Import peer's public key.
Definition: ecdh.c:274
void ecdhInit(EcdhContext *context)
Initialize ECDH context.
Definition: ecdh.c:49
error_t ikeLoadDhParams(DhParameters *params, uint16_t groupNum)
Load Diffie-Hellman parameters.
#define IkeSaEntry
Definition: ike.h:800
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
error_t ikeFormatDhPublicKey(IkeSaEntry *sa, uint8_t *p, size_t *written)
Format Diffie-Hellman public key.
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
const EcCurve * ikeGetEcdhCurve(uint16_t groupNum)
Get the elliptic curve that matches the specified group number.
error_t ecdhSetCurve(EcdhContext *context, const EcCurve *curve)
Specify the elliptic curve to use.
Definition: ecdh.c:83
#define EcCurve
Definition: ec.h:346
error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
Diffie-Hellman key pair generation.
Definition: dh.c:119
bool_t ikeIsEcdhKeyExchangeAlgo(uint16_t groupNum)
Test if the group number identifies an ECDH key exchange algorithm.
Diffie-Hellman groups.
const IkeDhGroup * ikeGetDhGroup(uint16_t groupNum)
Get the Diffie-Hellman group that matches the specified group number.
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
error_t ecdhExportPublicKey(EcdhContext *context, uint8_t *output, size_t *written, EcPublicKeyFormat format)
Export our own public key.
Definition: ecdh.c:257
IKEv2 algorithm negotiation.
Debugging facilities.
error_t ecdhGenerateKeyPair(EcdhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
ECDH key pair generation.
Definition: ecdh.c:115
void ikeFreeDhContext(IkeSaEntry *sa)
Release Diffie-Hellman context.