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-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_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  //Load EC parameters
122  error = ikeLoadEcdhParams(&sa->ecdhContext.params, sa->dhGroupNum);
123 
124  //Check status code
125  if(!error)
126  {
127  //Generate an ephemeral key pair
128  error = ecdhGenerateKeyPair(&sa->ecdhContext, context->prngAlgo,
129  context->prngContext);
130  }
131  }
132  else
133 #endif
134  //Unknown key exchange algorithm?
135  {
136  //Report an error
138  }
139 
140  //Return status code
141  return error;
142 }
143 
144 
145 /**
146  * @brief Compute Diffie-Hellman shared secret
147  * @param[in] sa Pointer to the IKE SA
148  * @return Error code
149  **/
150 
152 {
153  error_t error;
154 
155  //Debug message
156  TRACE_INFO("Computing Diffie-Hellman shared secret...\r\n");
157 
158 #if (IKE_DH_KE_SUPPORT == ENABLED)
159  //Diffie-Hellman key exchange algorithm?
160  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
161  {
162  //Let g^ir be the shared secret from the ephemeral Diffie-Hellman
163  //exchange
164  error = dhComputeSharedSecret(&sa->dhContext, sa->sharedSecret,
165  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
166  }
167  else
168 #endif
169 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
170  //ECDH key exchange algorithm?
171  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
172  {
173  //The Diffie-Hellman shared secret value consists of the x value of the
174  //Diffie-Hellman common value (refer to RFC 5903, section 7)
175  error = ecdhComputeSharedSecret(&sa->ecdhContext, sa->sharedSecret,
176  IKE_MAX_SHARED_SECRET_LEN, &sa->sharedSecretLen);
177  }
178  else
179 #endif
180  //Unknown key exchange algorithm?
181  {
182  //Report an error
184  }
185 
186  //Return status code
187  return error;
188 }
189 
190 
191 /**
192  * @brief Format Diffie-Hellman public key
193  * @param[in] sa Pointer to the IKE SA
194  * @param[out] p Buffer where to format the Diffie-Hellman public key
195  * @param[out] written Total number of bytes that have been written
196  * @return Error code
197  **/
198 
199 error_t ikeFormatDhPublicKey(IkeSaEntry *sa, uint8_t *p, size_t *written)
200 {
201  error_t error;
202 
203 #if (IKE_DH_KE_SUPPORT == ENABLED)
204  //Diffie-Hellman key exchange algorithm?
205  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
206  {
207  const IkeDhGroup *dhGroup;
208 
209  //Get the Diffie-Hellman group that matches the specified group number
210  dhGroup = ikeGetDhGroup(sa->dhGroupNum);
211 
212  //Valid Diffie-Hellman group?
213  if(dhGroup != NULL)
214  {
215  //A Key Exchange payload is constructed by copying one's Diffie-Hellman
216  //public value into the Key Exchange Data portion of the payload
217  error = mpiExport(&sa->dhContext.ya, p, dhGroup->pLen,
219  }
220  else
221  {
222  //Report an error
223  error = ERROR_UNSUPPORTED_TYPE;
224  }
225 
226  //Check status code
227  if(!error)
228  {
229  //The length of the Diffie-Hellman public value for MODP groups must
230  //be equal to the length of the prime modulus over which the
231  //exponentiation was performed, prepending zero bits to the value if
232  //necessary (refer to RFC 7296, section 3.4)
233  *written = dhGroup->pLen;
234  }
235  }
236  else
237 #endif
238 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
239  //ECDH key exchange algorithm?
240  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
241  {
242  const EcCurveInfo *curveInfo;
243 
244  //Get the elliptic curve that matches the specified group number
245  curveInfo = ikeGetEcdhCurveInfo(sa->dhGroupNum);
246 
247  //Valid elliptic curve?
248  if(curveInfo != NULL)
249  {
250  //Montgomery or Weierstrass curve?
251  if(sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE25519 ||
252  sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE448)
253  {
254  //Format public key
255  error = mpiExport(&sa->ecdhContext.qa.q.x, p, curveInfo->pLen,
257 
258  //Check status code
259  if(!error)
260  {
261  //The Key Exchange Data consists of 32 or 56 octets (refer to
262  //RFC 8031, section 3.1)
263  *written = curveInfo->pLen;
264  }
265  }
266  else
267  {
268  //In an ECP key exchange, the Diffie-Hellman public value passed in
269  //a KE payload consists of two components, x and y, corresponding to
270  //the coordinates of an elliptic curve point
271  error = mpiExport(&sa->ecdhContext.qa.q.x, p, curveInfo->pLen,
273 
274  //Check status code
275  if(!error)
276  {
277  //The Diffie-Hellman public value is obtained by concatenating
278  //the x and y values (refer to RFC 5903, section 7)
279  error = mpiExport(&sa->ecdhContext.qa.q.y, p + curveInfo->pLen,
280  curveInfo->pLen, MPI_FORMAT_BIG_ENDIAN);
281  }
282 
283  //Check status code
284  if(!error)
285  {
286  //Each component has a fixed bit length
287  *written = 2 * curveInfo->pLen;
288  }
289  }
290  }
291  else
292  {
293  //Report an error
294  error = ERROR_UNSUPPORTED_TYPE;
295  }
296  }
297  else
298 #endif
299  //Unknown key exchange algorithm?
300  {
301  //Report an error
303  }
304 
305  //Return status code
306  return error;
307 }
308 
309 
310 /**
311  * @brief Parse peer's Diffie-Hellman public key
312  * @param[in] sa Pointer to the IKE SA
313  * @param[out] p Pointer the Diffie-Hellman public key
314  * @param[out] length Length of the Diffie-Hellman public key, in bytes
315  * @return Error code
316  **/
317 
318 error_t ikeParseDhPublicKey(IkeSaEntry *sa, const uint8_t *p, size_t length)
319 {
320  error_t error;
321 
322 #if (IKE_DH_KE_SUPPORT == ENABLED)
323  //Diffie-Hellman key exchange algorithm?
324  if(ikeIsDhKeyExchangeAlgo(sa->dhGroupNum))
325  {
326  const IkeDhGroup *dhGroup;
327 
328  //Get the Diffie-Hellman group that matches the specified group number
329  dhGroup = ikeGetDhGroup(sa->dhGroupNum);
330 
331  //Valid Diffie-Hellman group?
332  if(dhGroup != NULL)
333  {
334  //The length of the Diffie-Hellman public value for MODP groups must
335  //be equal to the length of the prime modulus over which the
336  //exponentiation was performed, prepending zero bits to the value if
337  //necessary (refer to RFC 7296, section 3.4)
338  if(length == dhGroup->pLen)
339  {
340  //Load Diffie-Hellman parameters
341  error = ikeLoadDhParams(&sa->dhContext.params, sa->dhGroupNum);
342 
343  //Check status code
344  if(!error)
345  {
346  //Load peer's Diffie-Hellman public value
347  error = mpiImport(&sa->dhContext.yb, p, length,
349  }
350 
351  //Check status code
352  if(!error)
353  {
354  //Ensure the public key is acceptable
355  error = dhCheckPublicKey(&sa->dhContext.params,
356  &sa->dhContext.yb);
357  }
358  }
359  else
360  {
361  //Report an error
362  error = ERROR_INVALID_SYNTAX;
363  }
364  }
365  else
366  {
367  //Report an error
368  error = ERROR_INVALID_GROUP;
369  }
370  }
371  else
372 #endif
373 #if (IKE_ECDH_KE_SUPPORT == ENABLED)
374  //ECDH key exchange algorithm?
375  if(ikeIsEcdhKeyExchangeAlgo(sa->dhGroupNum))
376  {
377  const EcCurveInfo *curveInfo;
378 
379  //Get the elliptic curve that matches the specified group number
380  curveInfo = ikeGetEcdhCurveInfo(sa->dhGroupNum);
381 
382  //Valid elliptic curve?
383  if(curveInfo != NULL)
384  {
385  //Montgomery or Weierstrass curve?
386  if(sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE25519 ||
387  sa->dhGroupNum == IKE_TRANSFORM_ID_DH_GROUP_CURVE448)
388  {
389  //The Key Exchange Data consists of 32 or 56 octets (refer to
390  //RFC 8031, section 3.1)
391  if(length == curveInfo->pLen)
392  {
393  //Load public key
394  error = mpiImport(&sa->ecdhContext.qb.q.x, p, curveInfo->pLen,
396  }
397  else
398  {
399  //Report an error
400  error = ERROR_INVALID_SYNTAX;
401  }
402  }
403  else
404  {
405  //In an ECP key exchange, the Diffie-Hellman public value passed in
406  //a KE payload consists of two components, x and y, corresponding to
407  //the coordinates of an elliptic curve point
408  if(length == (2 * curveInfo->pLen))
409  {
410  //Load EC parameters
411  error = ikeLoadEcdhParams(&sa->ecdhContext.params,
412  sa->dhGroupNum);
413 
414  //Check status code
415  if(!error)
416  {
417  //Load x value
418  error = mpiImport(&sa->ecdhContext.qb.q.x, p, curveInfo->pLen,
420  }
421 
422  //Check status code
423  if(!error)
424  {
425  //Load y value
426  error = mpiImport(&sa->ecdhContext.qb.q.y, p + curveInfo->pLen,
427  curveInfo->pLen, MPI_FORMAT_BIG_ENDIAN);
428  }
429 
430  //Check status code
431  if(!error)
432  {
433  //Ensure the public key is acceptable
434  error = ecdhCheckPublicKey(&sa->ecdhContext.params,
435  &sa->ecdhContext.qb.q);
436  }
437  }
438  else
439  {
440  //Report an error
441  error = ERROR_INVALID_SYNTAX;
442  }
443  }
444  }
445  else
446  {
447  //Report an error
448  error = ERROR_INVALID_GROUP;
449  }
450  }
451  else
452 #endif
453  //Unknown key exchange algorithm?
454  {
455  //Report an error
456  error = ERROR_INVALID_GROUP;
457  }
458 
459  //Return status code
460  return error;
461 }
462 
463 #endif
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
Diffie-Hellman key pair generation.
Definition: dh.c:119
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute Diffie-Hellman shared secret.
Definition: dh.c:223
error_t dhCheckPublicKey(DhParameters *params, const Mpi *publicKey)
Check Diffie-Hellman public value.
Definition: dh.c:183
void dhFree(DhContext *context)
Release Diffie-Hellman context.
Definition: dh.c:71
error_t ecdhComputeSharedSecret(EcdhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute ECDH shared secret.
Definition: ecdh.c:340
void ecdhFree(EcdhContext *context)
Release ECDH context.
Definition: ecdh.c:65
error_t ecdhGenerateKeyPair(EcdhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
ECDH key pair generation.
Definition: ecdh.c:85
error_t ecdhCheckPublicKey(const EcDomainParameters *params, EcPoint *publicKey)
Check ECDH public key.
Definition: ecdh.c:227
void ecdhInit(EcdhContext *context)
Initialize ECDH context.
Definition: ecdh.c:48
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_TYPE
Definition: error.h:125
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
@ ERROR_INVALID_GROUP
Definition: error.h:274
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
IKEv2 (Internet Key Exchange Protocol)
#define IkeContext
Definition: ike.h:678
@ IKE_TRANSFORM_ID_DH_GROUP_CURVE25519
Curve25519.
Definition: ike.h:900
@ IKE_TRANSFORM_ID_DH_GROUP_CURVE448
Curve448.
Definition: ike.h:901
#define IkeSaEntry
Definition: ike.h:682
#define IKE_MAX_SHARED_SECRET_LEN
Definition: ike.h:656
bool_t ikeIsEcdhKeyExchangeAlgo(uint16_t groupNum)
Test if the group number identifies an ECDH key exchange algorithm.
bool_t ikeIsDhKeyExchangeAlgo(uint16_t groupNum)
Test if the group number identifies a DH key exchange algorithm.
const EcCurveInfo * ikeGetEcdhCurveInfo(uint16_t groupNum)
Get the elliptic curve that matches the specified group number.
error_t ikeLoadEcdhParams(EcDomainParameters *params, uint16_t groupNum)
Load the EC parameters that match the specified group number.
IKEv2 algorithm negotiation.
error_t ikeLoadDhParams(DhParameters *params, uint16_t groupNum)
Load Diffie-Hellman parameters.
const IkeDhGroup * ikeGetDhGroup(uint16_t groupNum)
Get the Diffie-Hellman group that matches the specified group number.
Diffie-Hellman groups.
void ikeInitDhContext(IkeSaEntry *sa)
Initialize Diffie-Hellman context.
error_t ikeComputeDhSharedSecret(IkeSaEntry *sa)
Compute Diffie-Hellman shared secret.
error_t ikeFormatDhPublicKey(IkeSaEntry *sa, uint8_t *p, size_t *written)
Format Diffie-Hellman public key.
void ikeFreeDhContext(IkeSaEntry *sa)
Release Diffie-Hellman context.
error_t ikeParseDhPublicKey(IkeSaEntry *sa, const uint8_t *p, size_t length)
Parse peer's Diffie-Hellman public key.
error_t ikeGenerateDhKeyPair(IkeSaEntry *sa)
Diffie-Hellman key pair generation.
Diffie-Hellman key exchange.
error_t mpiImport(Mpi *r, const uint8_t *data, uint_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:624
error_t mpiExport(const Mpi *a, uint8_t *data, uint_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:709
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:71
@ MPI_FORMAT_LITTLE_ENDIAN
Definition: mpi.h:70
uint8_t p
Definition: ndp.h:300
Elliptic curve parameters.
Definition: ec_curves.h:295
size_t pLen
Length of p.
Definition: ec_curves.h:301
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
uint8_t length
Definition: tcp.h:368