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.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_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  sa->ecdhContext.curve = curve;
131 
132  //Generate an ephemeral key pair
133  error = ecdhGenerateKeyPair(&sa->ecdhContext, context->prngAlgo,
134  context->prngContext);
135  }
136  else
137  {
138  //Report an error
139  error = ERROR_UNSUPPORTED_TYPE;
140  }
141  }
142  else
143 #endif
144  //Unknown key exchange algorithm?
145  {
146  //Report an error
148  }
149 
150  //Return status code
151  return error;
152 }
153 
154 
155 /**
156  * @brief Compute Diffie-Hellman shared secret
157  * @param[in] sa Pointer to the IKE SA
158  * @return Error code
159  **/
160 
162 {
163  error_t error;
164 
165  //Debug message
166  TRACE_INFO("Computing Diffie-Hellman shared secret...\r\n");
167 
168 #if (IKE_DH_KE_SUPPORT == ENABLED)
169  //Diffie-Hellman key exchange algorithm?
170  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
171  {
172  //Let g^ir be the shared secret from the ephemeral Diffie-Hellman
173  //exchange
174  error = dhComputeSharedSecret(&sa->dhContext, sa->sharedSecret,
175  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
176  }
177  else
178 #endif
179 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
180  //ECDH key exchange algorithm?
181  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
182  {
183  //The Diffie-Hellman shared secret value consists of the x value of the
184  //Diffie-Hellman common value (refer to RFC 5903, section 7)
185  error = ecdhComputeSharedSecret(&sa->ecdhContext, sa->sharedSecret,
186  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
187  }
188  else
189 #endif
190  //Unknown key exchange algorithm?
191  {
192  //Report an error
194  }
195 
196  //Return status code
197  return error;
198 }
199 
200 
201 /**
202  * @brief Format Diffie-Hellman public key
203  * @param[in] sa Pointer to the IKE SA
204  * @param[out] p Buffer where to format the Diffie-Hellman public key
205  * @param[out] written Total number of bytes that have been written
206  * @return Error code
207  **/
208 
209 error_t ikeFormatDhPublicKey(IkeSaEntry *sa, uint8_t *p, size_t *written)
210 {
211  error_t error;
212 
213 #if (IKE_DH_KE_SUPPORT == ENABLED)
214  //Diffie-Hellman key exchange algorithm?
215  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
216  {
217  const IkeDhGroup *dhGroup;
218 
219  //Get the Diffie-Hellman group that matches the specified group number
220  dhGroup = ikeGetDhGroup(sa->dhGroupNum);
221 
222  //Valid Diffie-Hellman group?
223  if(dhGroup != NULL)
224  {
225  //A Key Exchange payload is constructed by copying one's Diffie-Hellman
226  //public value into the Key Exchange Data portion of the payload
227  error = mpiExport(&sa->dhContext.ya, p, dhGroup->pLen,
229  }
230  else
231  {
232  //Report an error
233  error = ERROR_UNSUPPORTED_TYPE;
234  }
235 
236  //Check status code
237  if(!error)
238  {
239  //The length of the Diffie-Hellman public value for MODP groups must
240  //be equal to the length of the prime modulus over which the
241  //exponentiation was performed, prepending zero bits to the value if
242  //necessary (refer to RFC 7296, section 3.4)
243  *written = dhGroup->pLen;
244  }
245  }
246  else
247 #endif
248 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
249  //ECDH key exchange algorithm?
250  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
251  {
252  const EcCurve *curve;
253 
254  //Get the elliptic curve that matches the specified group number
255  curve = ikeGetEcdhCurve(sa->dhGroupNum);
256 
257  //Valid elliptic curve?
258  if(curve != NULL)
259  {
260  //Montgomery or Weierstrass curve?
261  if(sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE25519 ||
262  sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE448)
263  {
264  //The Key Exchange Data consists of 32 or 56 octets (refer to
265  //RFC 8031, section 3.1)
266  error = ecExportPublicKey(&sa->ecdhContext.da.q, p, written,
268  }
269  else
270  {
271  //The Diffie-Hellman public value is obtained by concatenating the
272  //x and y values (refer to RFC 5903, section 7)
273  error = ecExportPublicKey(&sa->ecdhContext.da.q, p, written,
275  }
276  }
277  else
278  {
279  //Report an error
280  error = ERROR_UNSUPPORTED_TYPE;
281  }
282  }
283  else
284 #endif
285  //Unknown key exchange algorithm?
286  {
287  //Report an error
289  }
290 
291  //Return status code
292  return error;
293 }
294 
295 
296 /**
297  * @brief Parse peer's Diffie-Hellman public key
298  * @param[in] sa Pointer to the IKE SA
299  * @param[out] p Pointer the Diffie-Hellman public key
300  * @param[out] length Length of the Diffie-Hellman public key, in bytes
301  * @return Error code
302  **/
303 
304 error_t ikeParseDhPublicKey(IkeSaEntry *sa, const uint8_t *p, size_t length)
305 {
306  error_t error;
307 
308 #if (IKE_DH_KE_SUPPORT == ENABLED)
309  //Diffie-Hellman key exchange algorithm?
310  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
311  {
312  const IkeDhGroup *dhGroup;
313 
314  //Get the Diffie-Hellman group that matches the specified group number
315  dhGroup = ikeGetDhGroup(sa->dhGroupNum);
316 
317  //Valid Diffie-Hellman group?
318  if(dhGroup != NULL)
319  {
320  //The length of the Diffie-Hellman public value for MODP groups must
321  //be equal to the length of the prime modulus over which the
322  //exponentiation was performed, prepending zero bits to the value if
323  //necessary (refer to RFC 7296, section 3.4)
324  if(length == dhGroup->pLen)
325  {
326  //Load Diffie-Hellman parameters
327  error = ikeLoadDhParams(&sa->dhContext.params, sa->dhGroupNum);
328 
329  //Check status code
330  if(!error)
331  {
332  //Load peer's Diffie-Hellman public value
333  error = mpiImport(&sa->dhContext.yb, p, length,
335  }
336 
337  //Check status code
338  if(!error)
339  {
340  //Ensure the public key is acceptable
341  error = dhCheckPublicKey(&sa->dhContext, &sa->dhContext.yb);
342  }
343  }
344  else
345  {
346  //Report an error
347  error = ERROR_INVALID_SYNTAX;
348  }
349  }
350  else
351  {
352  //Report an error
353  error = ERROR_INVALID_GROUP;
354  }
355  }
356  else
357 #endif
358 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
359  //ECDH key exchange algorithm?
360  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
361  {
362  const EcCurve *curve;
363 
364  //Get the elliptic curve that matches the specified group number
365  curve = ikeGetEcdhCurve(sa->dhGroupNum);
366 
367  //Valid elliptic curve?
368  if(curve != NULL)
369  {
370  //Save elliptic curve parameters
371  sa->ecdhContext.curve = curve;
372 
373  //Montgomery or Weierstrass curve?
374  if(sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE25519 ||
375  sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE448)
376  {
377  //The Key Exchange Data consists of 32 or 56 octets (refer to
378  //RFC 8031, section 3.1)
379  error = ecImportPublicKey(&sa->ecdhContext.qb, curve, p, length,
381  }
382  else
383  {
384  //In an ECP key exchange, the Diffie-Hellman public value passed in
385  //a KE payload consists of two components, x and y, corresponding to
386  //the coordinates of an elliptic curve point
387  error = ecImportPublicKey(&sa->ecdhContext.qb, curve, p, length,
389 
390  //Check status code
391  if(!error)
392  {
393  //Ensure the public key is acceptable
394  error = ecdhCheckPublicKey(&sa->ecdhContext,
395  &sa->ecdhContext.qb);
396  }
397  }
398  }
399  else
400  {
401  //Report an error
402  error = ERROR_INVALID_GROUP;
403  }
404  }
405  else
406 #endif
407  //Unknown key exchange algorithm?
408  {
409  //Report an error
410  error = ERROR_INVALID_GROUP;
411  }
412 
413  //Return status code
414  return error;
415 }
416 
417 #endif
@ IKE_TRANSFORM_ID_DH_GROUP_CURVE448
curve448
Definition: ike.h:1019
@ ERROR_UNSUPPORTED_TYPE
Definition: error.h:125
Diffie-Hellman key exchange.
error_t ecImportPublicKey(EcPublicKey *key, const EcCurve *curve, const uint8_t *data, size_t length, EcPublicKeyFormat format)
Import an EC public key.
Definition: ec.c:263
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
@ IKE_TRANSFORM_ID_DH_GROUP_CURVE25519
curve25519
Definition: ike.h:1018
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:226
error_t ikeComputeDhSharedSecret(IkeSaEntry *sa)
Compute Diffie-Hellman shared secret.
error_t ecdhCheckPublicKey(EcdhContext *context, const EcPublicKey *publicKey)
Check ECDH public key.
Definition: ecdh.c:224
void ikeInitDhContext(IkeSaEntry *sa)
Initialize Diffie-Hellman context.
error_t
Error codes.
Definition: error.h:43
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
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 dhCheckPublicKey(DhContext *context, const Mpi *publicKey)
Check Diffie-Hellman public value.
Definition: dh.c:183
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:809
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
error_t ikeGenerateDhKeyPair(IkeSaEntry *sa)
Diffie-Hellman key pair generation.
error_t ecExportPublicKey(const EcPublicKey *key, uint8_t *data, size_t *length, EcPublicKeyFormat format)
Export an EC public key.
Definition: ec.c:378
error_t ecdhComputeSharedSecret(EcdhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute ECDH shared secret.
Definition: ecdh.c:338
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
IKEv2 (Internet Key Exchange Protocol)
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.
#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
IKEv2 algorithm negotiation.
Debugging facilities.
error_t ecdhGenerateKeyPair(EcdhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
ECDH key pair generation.
Definition: ecdh.c:84
void ikeFreeDhContext(IkeSaEntry *sa)
Release Diffie-Hellman context.