ike_message_decrypt.c
Go to the documentation of this file.
1 /**
2  * @file ike_message_decrypt.c
3  * @brief IKE message decryption
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"
37 #include "ike/ike_payload_parse.h"
38 #include "ike/ike_debug.h"
41 #include "aead/aead_algorithms.h"
42 #include "debug.h"
43 
44 //Check IKEv2 library configuration
45 #if (IKE_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Decrypt an incoming IKE message
50  * @param[in] sa Pointer to the IKE SA
51  * @param[in,out] message IKE message to be decrypted
52  * @param[in,out] messageLen Actual length of the IKE message
53  * @return Error code
54  **/
55 
56 error_t ikeDecryptMessage(IkeSaEntry *sa, uint8_t *message, size_t *messageLen)
57 {
58  error_t error;
59  size_t n;
60  size_t length;
61  uint8_t *iv;
62  uint8_t *data;
63  uint8_t *icv;
64  IkeHeader *ikeHeader;
65  IkeEncryptedPayload *encryptedPayload;
66  const uint8_t *encKey;
67  const CipherAlgo *cipherAlgo;
68 
69  //Malformed IKE message?
70  if(*messageLen < sizeof(IkeHeader))
71  return ERROR_INVALID_MESSAGE;
72 
73  //Point to the IKE header
74  ikeHeader = (IkeHeader *) message;
75  //Retrieve the length of the IKE message
76  n = ntohl(ikeHeader->length);
77 
78  //Malformed IKE message?
79  if(n < sizeof(IkeHeader) || n > *messageLen)
80  return ERROR_INVALID_MESSAGE;
81 
82  //Cipher algorithm used to decrypt the packet
83  cipherAlgo = sa->cipherAlgo;
84 
85  //The encryption key is obtained from the SK_ei or SK_er key, whichever
86  //is appropriate
87  if(sa->originalInitiator)
88  {
89  encKey = sa->sker;
90  }
91  else
92  {
93  encKey = sa->skei;
94  }
95 
96  //The Encrypted payload is often the only payload in the message
97  encryptedPayload = (IkeEncryptedPayload *) ikeGetPayload(message, n,
99  //Encrypted payload not found?
100  if(encryptedPayload == NULL)
101  return ERROR_INVALID_MESSAGE;
102 
103  //The Payload Length field of the Encrypted payload header includes the
104  //lengths of the header, initialization vector (IV), encrypted IKE payloads,
105  //Padding, Pad Length, and Integrity Checksum Value (ICV)
106  length = ntohs(encryptedPayload->header.payloadLength);
107 
108  //The Encrypted payload, if present in a message, must be the last payload
109  //in the message (refer to RFC 7296, section 3.14)
110  if(((uint8_t *) encryptedPayload + length) != (message + n))
111  return ERROR_INVALID_MESSAGE;
112 
113  //Check the length of the Encrypted payload
114  if(length < (sizeof(IkeEncryptedPayload) + sa->ivLen + sa->icvLen + 1))
115  return ERROR_INVALID_MESSAGE;
116 
117  //Determine the length of the ciphertext
118  length -= sizeof(IkeEncryptedPayload) + sa->ivLen + sa->icvLen;
119 
120  //Point to the initialization vector (IV)
121  iv = encryptedPayload->iv;
122  //Point to the ciphertext
123  data = iv + sa->ivLen;
124  //Point to the Integrity Checksum Value (ICV)
125  icv = data + length;
126 
127 #if (IKE_CBC_SUPPORT == ENABLED)
128  //CBC cipher mode?
129  if(sa->cipherMode == CIPHER_MODE_CBC)
130  {
131  //The length of the ciphertext must be a multiple of the block size
132  if((length % cipherAlgo->blockSize) != 0)
133  return ERROR_INVALID_MESSAGE;
134 
135  //Verify checksum value
136  error = ikeVerifyChecksum(sa, message, n - sa->icvLen, icv);
137  //Any error to report?
138  if(error)
139  return error;
140 
141  //Initialize cipher context
142  error = cipherAlgo->init(&sa->cipherContext, encKey, sa->encKeyLen);
143  //Any error to report?
144  if(error)
145  return error;
146 
147  //Perform CBC decryption
148  error = cbcDecrypt(cipherAlgo, &sa->cipherContext, iv, data, data,
149  length);
150  //Any error to report?
151  if(error)
152  return error;
153  }
154  else
155 #endif
156 #if (IKE_CTR_SUPPORT == ENABLED)
157  //CTR cipher mode?
158  if(sa->cipherMode == CIPHER_MODE_CTR)
159  {
160  uint8_t counter[16];
161 
162  //The counter block is 128 bits, including a 4-octet nonce, 8-octet IV,
163  //and 4-octet block counter, in that order (refer to RFC 5930, section 2)
164  osMemcpy(counter, encKey + sa->encKeyLen, 4);
165  osMemcpy(counter + 4, iv, 8);
166 
167  //The block counter begins with the value of one and increments by one
168  //to generate the next portion of the key stream
169  STORE32BE(1, counter + 12);
170 
171  //Verify checksum value
172  error = ikeVerifyChecksum(sa, message, n - sa->icvLen, icv);
173  //Any error to report?
174  if(error)
175  return error;
176 
177  //Initialize cipher context
178  error = cipherAlgo->init(&sa->cipherContext, encKey, sa->encKeyLen);
179  //Any error to report?
180  if(error)
181  return error;
182 
183  //Perform CTR decryption
184  error = ctrDecrypt(cipherAlgo, &sa->cipherContext,
185  cipherAlgo->blockSize * 8, counter, data, data, length);
186  //Any error to report?
187  if(error)
188  return error;
189  }
190  else
191 #endif
192 #if (IKE_CCM_8_SUPPORT == ENABLED || IKE_CCM_12_SUPPORT == ENABLED || \
193  IKE_CCM_16_SUPPORT == ENABLED)
194  //CCM AEAD cipher?
195  if(sa->cipherMode == CIPHER_MODE_CCM)
196  {
197  size_t aadLen;
198  uint8_t *aad;
199  uint8_t nonce[11];
200 
201  //Construct the nonce by concatenating the salt with the IV, in that
202  //order (refer to RFC 5282, section 4)
203  osMemcpy(nonce, encKey + sa->encKeyLen, 3);
204  osMemcpy(nonce + 3, iv, 8);
205 
206  //The associated data must consist of the partial contents of the IKEv2
207  //message, starting from the first octet of the fixed IKE header through
208  //the last octet of the Encrypted payload header (refer to RFC 5282,
209  //section 5.1)
210  aad = message;
211  aadLen = encryptedPayload->iv - message;
212 
213  //Initialize cipher context
214  error = cipherAlgo->init(&sa->cipherContext, encKey, sa->encKeyLen);
215  //Any error to report?
216  if(error)
217  return error;
218 
219  //Authenticated decryption using CCM
220  error = ccmDecrypt(sa->cipherAlgo, &sa->cipherContext, nonce, 11, aad,
221  aadLen, data, data, length, icv, sa->icvLen);
222  //Any error to report?
223  if(error)
224  return error;
225  }
226  else
227 #endif
228 #if (IKE_GCM_8_SUPPORT == ENABLED || IKE_GCM_12_SUPPORT == ENABLED || \
229  IKE_GCM_16_SUPPORT == ENABLED)
230  //GCM AEAD cipher?
231  if(sa->cipherMode == CIPHER_MODE_GCM)
232  {
233  size_t aadLen;
234  uint8_t *aad;
235  uint8_t nonce[12];
236  GcmContext gcmContext;
237 
238  //Construct the nonce by concatenating the salt with the IV, in that
239  //order (refer to RFC 5282, section 4)
240  osMemcpy(nonce, encKey + sa->encKeyLen, 4);
241  osMemcpy(nonce + 4, iv, 8);
242 
243  //The associated data must consist of the partial contents of the IKEv2
244  //message, starting from the first octet of the fixed IKE header through
245  //the last octet of the Encrypted payload header (refer to RFC 5282,
246  //section 5.1)
247  aad = message;
248  aadLen = encryptedPayload->iv - message;
249 
250  //Initialize cipher context
251  error = cipherAlgo->init(&sa->cipherContext, encKey, sa->encKeyLen);
252  //Any error to report?
253  if(error)
254  return error;
255 
256  //Initialize GCM context
257  error = gcmInit(&gcmContext, sa->cipherAlgo, &sa->cipherContext);
258  //Any error to report?
259  if(error)
260  return error;
261 
262  //Authenticated decryption using GCM
263  error = gcmDecrypt(&gcmContext, nonce, 12, aad, aadLen, data, data,
264  length, icv, sa->icvLen);
265  //Any error to report?
266  if(error)
267  return error;
268  }
269  else
270 #endif
271 #if (IKE_CHACHA20_POLY1305_SUPPORT == ENABLED)
272  //ChaCha20Poly1305 AEAD cipher?
273  if(sa->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
274  {
275  size_t aadLen;
276  uint8_t *aad;
277  uint8_t nonce[12];
278 
279  //The 96-bit nonce is formed from a concatenation of the 32-bit salt and
280  //the 64-bit IV (refer to RFC 7634, section 2)
281  osMemcpy(nonce, encKey + sa->encKeyLen, 4);
282  osMemcpy(nonce + 4, iv, 8);
283 
284  //The associated data must consist of the partial contents of the IKEv2
285  //message, starting from the first octet of the fixed IKE header through
286  //the last octet of the Encrypted payload header (refer to RFC 5282,
287  //section 5.1)
288  aad = message;
289  aadLen = encryptedPayload->iv - message;
290 
291  //Authenticated decryption using ChaCha20Poly1305
292  error = chacha20Poly1305Decrypt(encKey, sa->encKeyLen, nonce, 12, aad,
293  aadLen, data, data, length, icv, sa->icvLen);
294  }
295  else
296 #endif
297  //Invalid cipher mode?
298  {
299  //The specified cipher mode is not supported
301  }
302 
303  //The Pad Length field is the length of the Padding field
304  n = data[length - 1];
305 
306  //Malformed padding?
307  if((n + 1) > length)
309 
310  //Strip padding bytes from the message
311  length -= n + 1;
312 
313  //Total length of the resulting IKE message
314  *messageLen = sizeof(IkeHeader) + length;
315 
316  //Fix the Next Payload and Length fields of the IKE header
317  ikeHeader->nextPayload = encryptedPayload->header.nextPayload;
318  ikeHeader->length = htonl(*messageLen);
319 
320  //Strip the Encrypted payload header from the message
321  osMemmove(message + sizeof(IkeHeader), data, length);
322 
323  //Debug message
324  TRACE_DEBUG("Decrypted IKE message (%" PRIuSIZE " bytes):\r\n", *messageLen);
325  //Dump IKE message for debugging purpose
326  ikeDumpMessage(message, *messageLen);
327 
328  //Successful processing
329  return NO_ERROR;
330 }
331 
332 
333 /**
334  * @brief Verify ICV checksum
335  * @param[in] sa Pointer to the IKE SA
336  * @param[in] message Pointer to the message
337  * @param[in] length Length of the message, in bytes
338  * @param[in] icv Integrity Checksum Value (ICV)
339  * @return Error code
340  **/
341 
343  size_t length, const uint8_t *icv)
344 {
345  size_t i;
346  uint8_t mask;
347  error_t error;
348  const uint8_t *authKey;
350 
351  //The integrity protection key key is obtained from the SK_ai or SK_ar
352  //key, whichever is appropriate
353  if(sa->originalInitiator)
354  {
355  authKey = sa->skar;
356  }
357  else
358  {
359  authKey = sa->skai;
360  }
361 
362 #if (IKE_HMAC_AUTH_SUPPORT == ENABLED)
363  //HMAC integrity algorithm?
364  if(sa->authHashAlgo != NULL)
365  {
366  HmacContext *hmacContext;
367 
368  //Point to the HMAC context
369  hmacContext = &sa->context->hmacContext;
370 
371  //Initialize HMAC calculation
372  error = hmacInit(hmacContext, sa->authHashAlgo, authKey, sa->authKeyLen);
373 
374  //Check status code
375  if(!error)
376  {
377  //The checksum must be computed over the encrypted message. Its length
378  //is determined by the integrity algorithm negotiated
379  hmacUpdate(hmacContext, message, length);
380  hmacFinal(hmacContext, checksum);
381  }
382  }
383  else
384 #endif
385 #if (IKE_CMAC_AUTH_SUPPORT == ENABLED)
386  //CMAC integrity algorithm?
387  if(sa->authAlgoId == IKE_TRANSFORM_ID_AUTH_AES_CMAC_96 &&
388  sa->authCipherAlgo != NULL)
389  {
390  CmacContext *cmacContext;
391 
392  //Point to the CMAC context
393  cmacContext = &sa->context->cmacContext;
394 
395  //Initialize CMAC calculation
396  error = cmacInit(cmacContext, sa->authCipherAlgo, authKey,
397  sa->authKeyLen);
398 
399  //Check status code
400  if(!error)
401  {
402  //The checksum must be computed over the encrypted message. Its length
403  //is determined by the integrity algorithm negotiated
404  cmacUpdate(cmacContext, message, length);
405  cmacFinal(cmacContext, checksum, sa->icvLen);
406  }
407  }
408  else
409 #endif
410 #if (IKE_XCBC_MAC_AUTH_SUPPORT == ENABLED)
411  //XCBC-MAC integrity algorithm?
412  if(sa->authAlgoId == IKE_TRANSFORM_ID_AUTH_AES_XCBC_96 &&
413  sa->authCipherAlgo != NULL)
414  {
415  XcbcMacContext *xcbcMacContext;
416 
417  //Point to the XCBC-MAC context
418  xcbcMacContext = &sa->context->xcbcMacContext;
419 
420  //Initialize XCBC-MAC calculation
421  error = xcbcMacInit(xcbcMacContext, sa->authCipherAlgo, authKey,
422  sa->authKeyLen);
423 
424  //Check status code
425  if(!error)
426  {
427  //The checksum must be computed over the encrypted message. Its length
428  //is determined by the integrity algorithm negotiated
429  xcbcMacUpdate(xcbcMacContext, message, length);
430  xcbcMacFinal(xcbcMacContext, checksum, sa->icvLen);
431  }
432  }
433  else
434 #endif
435  //Unknown integrity algorithm?
436  {
437  //Report an error
438  error = ERROR_DECRYPTION_FAILED;
439  }
440 
441  //Check status code
442  if(!error)
443  {
444  //The calculated checksum is bitwise compared to the received ICV
445  for(mask = 0, i = 0; i < sa->icvLen; i++)
446  {
447  mask |= checksum[i] ^ icv[i];
448  }
449 
450  //The message is authenticated if and only if the checksums match
451  error = (mask == 0) ? NO_ERROR : ERROR_DECRYPTION_FAILED;
452  }
453 
454  //Return status code
455  return error;
456 }
457 
458 #endif
uint8_t icv[]
Definition: ah.h:145
__weak_func error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
Definition: cbc.c:108
__weak_func error_t ccmDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using CCM.
Definition: ccm.c:208
error_t chacha20Poly1305Decrypt(const uint8_t *k, size_t kLen, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using ChaCha20Poly1305.
uint8_t message[]
Definition: chap.h:154
Collection of AEAD algorithms.
Block cipher modes of operation.
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
#define PRIuSIZE
#define ntohl(value)
Definition: cpu_endian.h:422
#define htonl(value)
Definition: cpu_endian.h:414
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define ntohs(value)
Definition: cpu_endian.h:421
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:951
@ CIPHER_MODE_CCM
Definition: crypto.h:949
@ CIPHER_MODE_CBC
Definition: crypto.h:945
@ CIPHER_MODE_CTR
Definition: crypto.h:948
@ CIPHER_MODE_GCM
Definition: crypto.h:950
error_t ctrDecrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *c, uint8_t *p, size_t length)
CTR decryption.
Definition: ctr.c:129
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_DECRYPTION_FAILED
Definition: error.h:241
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_UNSUPPORTED_CIPHER_MODE
Definition: error.h:128
uint8_t data[]
Definition: ethernet.h:222
__weak_func error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:99
__weak_func error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using GCM.
Definition: gcm.c:361
#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)
uint8_t iv[]
Definition: ike.h:1502
@ IKE_TRANSFORM_ID_AUTH_AES_CMAC_96
Definition: ike.h:863
@ IKE_TRANSFORM_ID_AUTH_AES_XCBC_96
Definition: ike.h:860
IkeEncryptedPayload
Definition: ike.h:1503
#define IKE_CBC_SUPPORT
Definition: ike.h:229
@ IKE_PAYLOAD_TYPE_SK
Encrypted and Authenticated.
Definition: ike.h:741
#define IkeSaEntry
Definition: ike.h:682
IkeHeader
Definition: ike.h:1266
void ikeDumpMessage(const uint8_t *message, size_t length)
Dump IKE message.
Definition: ike_debug.c:379
Data logging functions for debugging purpose (IKEv2)
error_t ikeDecryptMessage(IkeSaEntry *sa, uint8_t *message, size_t *messageLen)
Decrypt an incoming IKE message.
error_t ikeVerifyChecksum(IkeSaEntry *sa, const uint8_t *message, size_t length, const uint8_t *icv)
Verify ICV checksum.
IKE message decryption.
const IkePayloadHeader * ikeGetPayload(const uint8_t *message, size_t length, uint8_t type, uint_t index)
Search an IKE message for a given payload type.
IKE payload parsing.
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define ENABLED
Definition: os_port.h:37
Common interface for encryption algorithms.
Definition: crypto.h:1036
size_t blockSize
Definition: crypto.h:1040
CipherAlgoInit init
Definition: crypto.h:1041
CMAC algorithm context.
Definition: cmac.h:54
GCM context.
Definition: gcm.h:64
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: gcm.h:65
HMAC algorithm context.
Definition: hmac.h:59
XCBC-MAC algorithm context.
Definition: xcbc_mac.h:54
uint8_t length
Definition: tcp.h:368
uint16_t checksum
Definition: tcp.h:355
uint8_t mask
Definition: web_socket.h:319
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