ike_auth.c
Go to the documentation of this file.
1 /**
2  * @file ike_auth.c
3  * @brief Authentication of the IKE SA
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2022-2026 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.6.6
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_auth.h"
37 #include "ike/ike_sign_generate.h"
38 #include "ike/ike_sign_verify.h"
39 #include "ike/ike_key_material.h"
40 #include "encoding/asn1.h"
41 #include "encoding/oid.h"
42 #include "kdf/ike_kdf.h"
43 #include "pkix/x509_cert_parse.h"
44 #include "debug.h"
45 
46 //Check IKEv2 library configuration
47 #if (IKE_SUPPORT == ENABLED)
48 
49 
50 /**
51  * @brief Generate signature or MAC
52  * @param[in] sa Pointer to the IKE SA
53  * @param[in] idPayload Pointer to the Identification payload
54  * @param[out] authMethod Authentication method
55  * @param[out] authData Pointer to the authentication data
56  * @param[out] authDataLen Length of the authentication data
57  * @return Error code
58  **/
59 
61  uint8_t *authMethod, uint8_t *authData, size_t *authDataLen)
62 {
63  error_t error;
64  size_t idLen;
65  const uint8_t *id;
66  IkeContext *context;
67 
68  //Point to the IKE context
69  context = sa->context;
70 
71  //Retrieve the length of the Identification payload
72  idLen = ntohs(idPayload->header.payloadLength);
73 
74  //Check the length of the payload
75  if(idLen >= sizeof(IkePayloadHeader))
76  {
77  //Point to the RestOfInitIDPayload field
78  id = (uint8_t *) idPayload + sizeof(IkePayloadHeader);
79  idLen -= sizeof(IkePayloadHeader);
80 
81 #if (IKE_CERT_AUTH_SUPPORT == ENABLED)
82  //Certificate authentication?
83  if(context->certChain != NULL && context->certChainLen > 0)
84  {
85  //Compute the signature using the entity's private key
86  error = ikeGenerateSignature(sa, id, idLen, authMethod, authData,
87  authDataLen);
88  }
89  else
90 #endif
91 #if (IKE_PSK_AUTH_SUPPORT == ENABLED)
92  //Pre-shared key authentication?
93  if(context->pskLen > 0)
94  {
95  //Set authentication method
97 
98  //Compute the MAC authentication code using the shared key
99  error = ikeComputeMacAuth(sa, context->psk, context->pskLen, id,
100  idLen, authData, sa->originalInitiator);
101 
102  //Check status code
103  if(!error)
104  {
105  //Length of the resulting MAC authentication code
106  *authDataLen = sa->prfKeyLen;
107  }
108  }
109  else
110 #endif
111  //Invalid authentication method?
112  {
113  //Report an error
115  }
116  }
117  else
118  {
119  //Malformed payload
120  error = ERROR_INVALID_MESSAGE;
121  }
122 
123  //Return status code
124  return error;
125 }
126 
127 
128 /**
129  * @brief Verify signature or MAC
130  * @param[in] sa Pointer to the IKE SA
131  * @param[in] padEntry Pointer to the PAD entry
132  * @param[in] idPayload Pointer to the Identification payload
133  * @param[in] certPayload Pointer to the Certificate payload
134  * @param[out] authPayload Pointer to the Authentication payload
135  * @return Error code
136  **/
137 
139  const IkeIdPayload *idPayload, const IkeCertPayload *certPayload,
140  const IkeAuthPayload *authPayload)
141 {
142  error_t error;
143  uint8_t authMethod;
144  size_t idLen;
145  size_t authDataLen;
146  const uint8_t *id;
147  const uint8_t *authData;
148 
149  //Retrieve the length of the Identification payload
150  idLen = ntohs(idPayload->header.payloadLength);
151  //Retrieve the length of the Authentication payload
152  authDataLen = ntohs(authPayload->header.payloadLength);
153 
154  //Check the length of the payloads
155  if(idLen >= sizeof(IkePayloadHeader) &&
156  authDataLen >= sizeof(IkeAuthPayload))
157  {
158  //Point to the RestOfInitIDPayload field
159  id = (uint8_t *) idPayload + sizeof(IkePayloadHeader);
160  idLen -= sizeof(IkePayloadHeader);
161 
162  //Point to the Authentication Data field
163  authData = authPayload->authData;
164  authDataLen -= sizeof(IkeAuthPayload);
165 
166  //Retrieve the authentication method used
167  authMethod = authPayload->authMethod;
168 
169 #if (IKE_CERT_AUTH_SUPPORT == ENABLED)
170  //Certificate authentication?
177  {
178  size_t certDataLen;
179  X509CertInfo *certInfo;
180 
181  //The first CERT payload holds the public key used to validate the
182  //sender's AUTH payload (refer to RFC7296, section 3.6)
183  if(certPayload != NULL)
184  {
185  //Retrieve the length of the CERT payload
186  certDataLen = ntohs(certPayload->header.payloadLength);
187 
188  //Check the length of the payload
189  if(certDataLen >= sizeof(IkeCertPayload))
190  {
191  //Determine the length of the Certificate Data field
192  certDataLen -= sizeof(IkeCertPayload);
193 
194  //Allocate a memory buffer to store X.509 certificate info
195  certInfo = ikeAllocMem(sizeof(X509CertInfo));
196 
197  //Successful memory allocation?
198  if(certInfo != NULL)
199  {
200  //Parse the DER-encoded X.509 certificate
201  error = x509ParseCertificate(certPayload->certData,
202  certDataLen, certInfo);
203 
204  //Check status code
205  if(!error)
206  {
207  //Display ASN.1 structure
208  error = asn1DumpObject(certPayload->certData,
209  certDataLen, 0);
210  }
211 
212  //Check status code
213  if(!error)
214  {
215  //Check whether the signature is correct
216  error = ikeVerifySignature(sa, id, idLen, authMethod,
218  authDataLen);
219  }
220  }
221  else
222  {
223  //Failed to allocate memory
224  error = ERROR_OUT_OF_MEMORY;
225  }
226  }
227  else
228  {
229  //Malformed payload
230  error = ERROR_INVALID_MESSAGE;
231  }
232  }
233  else
234  {
235  //The AUTH payload is not present
236  error = ERROR_INVALID_MESSAGE;
237  }
238  }
239  else
240 #endif
241 #if (IKE_PSK_AUTH_SUPPORT == ENABLED)
242  //Pre-shared key authentication?
244  {
245  uint8_t mac[IKE_MAX_DIGEST_SIZE];
246 
247  //The CERT payload must not be included
248  if(certPayload == NULL)
249  {
250  //Check the length of the MAC authentication code
251  if(authDataLen == sa->prfKeyLen)
252  {
253  //Compute the MAC authentication code using the shared key
254  error = ikeComputeMacAuth(sa, padEntry->psk, padEntry->pskLen, id,
255  idLen, mac, !sa->originalInitiator);
256 
257  //Check status code
258  if(!error)
259  {
260  //Check the MAC authentication code against the calculated value
261  if(osMemcmp(mac, authData, authDataLen) != 0)
262  {
264  }
265  }
266  }
267  else
268  {
269  //The length of the MAC authentication code is not valid
271  }
272  }
273  else
274  {
275  //Report an error
276  error = ERROR_INVALID_MESSAGE;
277  }
278  }
279  else
280 #endif
281  //Invalid authentication method?
282  {
283  //Report an error
285  }
286  }
287  else
288  {
289  //Malformed payload
290  error = ERROR_INVALID_MESSAGE;
291  }
292 
293  //Return status code
294  return error;
295 }
296 
297 
298 /**
299  * @brief Compute MAC authentication data
300  * @param[in] sa Pointer to the IKE SA
301  * @param[in] key Pre-shared key
302  * @param[in] keyLen Length of the pre-shared key
303  * @param[in] id MAC authentication data
304  * @param[in] idLen MAC authentication data
305  * @param[out] mac MAC authentication data
306  * @param[in] initiator Specifies whether the computation is performed at
307  * initiator or responder side
308  * @return Error code
309  **/
310 
311 error_t ikeComputeMacAuth(IkeSaEntry *sa, const uint8_t *key, size_t keyLen,
312  const uint8_t *id, size_t idLen, uint8_t *mac, bool_t initiator)
313 {
314 #if (IKE_PSK_AUTH_SUPPORT == ENABLED)
315  error_t error;
316  uint8_t macId[IKE_MAX_DIGEST_SIZE];
317  uint8_t macKey[IKE_MAX_DIGEST_SIZE];
318  DataFrag dataFrags[3];
319 
320  //Derive the shared secret from the password
321  error = ikePrf(sa->prfMacAlgo, sa->prfHashAlgo, sa->prfCipherAlgo, key,
322  keyLen, "Key Pad for IKEv2", 17, macKey);
323 
324  //Check whether the calculation is performed at initiator side
325  if(initiator)
326  {
327  //Check status code
328  if(!error)
329  {
330  //Compute prf(SK_pi, IDi')
331  error = ikePrf(sa->prfMacAlgo, sa->prfHashAlgo, sa->prfCipherAlgo,
332  sa->skpi, sa->prfKeyLen, id, idLen, macId);
333  }
334 
335  //Check status code
336  if(!error)
337  {
338  //The initiator signs the first message (IKE_SA_INIT request), starting
339  //with the first octet of the first SPI in the header and ending with
340  //the last octet of the last payload. Appended to this (for purposes of
341  //computing the signature) are the responder's nonce Nr, and the value
342  //prf(SK_pi, IDi')
343  dataFrags[0].buffer = sa->initiatorSaInit;
344  dataFrags[0].length = sa->initiatorSaInitLen;
345  dataFrags[1].buffer = sa->responderNonce;
346  dataFrags[1].length = sa->responderNonceLen;
347  dataFrags[2].buffer = macId;
348  dataFrags[2].length = sa->prfKeyLen;
349 
350  //Compute the AUTH value
351  error = ikePrfEx(sa->prfMacAlgo, sa->prfHashAlgo, sa->prfCipherAlgo,
352  macKey, sa->prfKeyLen, dataFrags, arraysize(dataFrags), mac);
353  }
354  }
355  else
356  {
357  //Check status code
358  if(!error)
359  {
360  //Compute prf(SK_pr, IDr')
361  error = ikePrf(sa->prfMacAlgo, sa->prfHashAlgo, sa->prfCipherAlgo,
362  sa->skpr, sa->prfKeyLen, id, idLen, macId);
363  }
364 
365  //Check status code
366  if(!error)
367  {
368  //For the responder, the octets to be signed start with the first octet
369  //of the first SPI in the header of the second message (IKE_SA_INIT
370  //response) and end with the last octet of the last payload in the
371  //second message. Appended to this (for purposes of computing the
372  //signature) are the initiator's nonce Ni, and the value prf(SK_pr, IDr')
373  dataFrags[0].buffer = sa->responderSaInit;
374  dataFrags[0].length = sa->responderSaInitLen;
375  dataFrags[1].buffer = sa->initiatorNonce;
376  dataFrags[1].length = sa->initiatorNonceLen;
377  dataFrags[2].buffer = macId;
378  dataFrags[2].length = sa->prfKeyLen;
379 
380  //Compute the AUTH value
381  error = ikePrfEx(sa->prfMacAlgo, sa->prfHashAlgo, sa->prfCipherAlgo,
382  macKey, sa->prfKeyLen, dataFrags, arraysize(dataFrags), mac);
383  }
384  }
385 
386  //Return status code
387  return error;
388 #else
389  //Pre-shared key authentication is not supported
390  return ERROR_NOT_IMPLEMENTED;
391 #endif
392 }
393 
394 #endif
const void * buffer
Definition: crypto.h:1165
error_t ikePrf(MacAlgo macAlgo, const HashAlgo *hashAlgo, const CipherAlgo *cipherAlgo, const uint8_t *key, size_t keyLen, const uint8_t *data, size_t dataLen, uint8_t *output)
Pseudorandom function (prf function)
Definition: ike_kdf.c:55
X.509 certificate parsing.
int bool_t
Definition: compiler_port.h:63
Authentication of the IKE SA.
X509TbsCertificate tbsCert
Definition: x509_common.h:1196
error_t ikeGenerateSignature(IkeSaEntry *sa, const uint8_t *id, size_t idLen, uint8_t *authMethod, uint8_t *signature, size_t *signatureLen)
Signature generation.
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
OID (Object Identifier)
@ IKE_AUTH_METHOD_ECDSA_P521_SHA512
ECDSA with SHA-512 on the P-521 curve.
Definition: ike.h:1169
error_t x509ParseCertificate(const uint8_t *data, size_t length, X509CertInfo *certInfo)
Parse a X.509 certificate.
@ IKE_AUTH_METHOD_RSA
RSA Digital Signature.
Definition: ike.h:1164
size_t pskLen
Length of the pre-shared key, in bytes.
Definition: ipsec.h:418
IkePayloadHeader
Definition: ike.h:1477
error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level)
Display an ASN.1 data object.
Definition: asn1.c:999
#define osMemcmp(p1, p2, length)
Definition: os_port.h:159
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
error_t ikeVerifySignature(IkeSaEntry *sa, const uint8_t *id, size_t idLen, uint8_t authMethod, const X509SubjectPublicKeyInfo *publicKeyInfo, const uint8_t *signature, size_t signatureLen)
Signature verification.
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
#define IKE_MAX_DIGEST_SIZE
Definition: ike.h:764
RSA/DSA/ECDSA/EdDSA signature generation.
error_t ikeGenerateAuth(IkeSaEntry *sa, const IkeIdPayload *idPayload, uint8_t *authMethod, uint8_t *authData, size_t *authDataLen)
Generate signature or MAC.
Definition: ike_auth.c:60
Peer Authorization Database (PAD) entry.
Definition: ipsec.h:412
#define IkeContext
Definition: ike.h:832
IkeAuthPayload
Definition: ike.h:1596
error_t ikePrfEx(MacAlgo macAlgo, const HashAlgo *hashAlgo, const CipherAlgo *cipherAlgo, const uint8_t *key, size_t keyLen, const DataFrag *dataFrags, uint_t dataNumFrags, uint8_t *output)
Pseudorandom function (prf function)
Definition: ike_kdf.c:92
X.509 certificate.
Definition: x509_common.h:1194
error_t
Error codes.
Definition: error.h:43
IkeIdPayload
Definition: ike.h:1559
@ IKE_AUTH_METHOD_DIGITAL_SIGN
Digital Signature.
Definition: ike.h:1172
Key material generation.
Data fragment descriptor.
Definition: crypto.h:1164
error_t ikeVerifyAuth(IkeSaEntry *sa, IpsecPadEntry *padEntry, const IkeIdPayload *idPayload, const IkeCertPayload *certPayload, const IkeAuthPayload *authPayload)
Verify signature or MAC.
Definition: ike_auth.c:138
uint8_t authMethod
Definition: ike.h:1593
size_t length
Definition: crypto.h:1166
IKEv2 key derivation functions.
@ IKE_AUTH_METHOD_SHARED_KEY
Shared Key Message Integrity Code.
Definition: ike.h:1165
IKEv2 (Internet Key Exchange Protocol)
#define ntohs(value)
Definition: cpu_endian.h:421
#define IkeSaEntry
Definition: ike.h:836
IkeCertPayload
Definition: ike.h:1571
@ ERROR_AUTHENTICATION_FAILED
Definition: error.h:69
error_t ikeComputeMacAuth(IkeSaEntry *sa, const uint8_t *key, size_t keyLen, const uint8_t *id, size_t idLen, uint8_t *mac, bool_t initiator)
Compute MAC authentication data.
Definition: ike_auth.c:311
uint8_t authData[]
Definition: ipv6.h:375
@ IKE_AUTH_METHOD_DSS
DSS Digital Signature.
Definition: ike.h:1166
@ IKE_AUTH_METHOD_ECDSA_P256_SHA256
ECDSA with SHA-256 on the P-256 curve.
Definition: ike.h:1167
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1184
@ IKE_AUTH_METHOD_ECDSA_P384_SHA384
ECDSA with SHA-384 on the P-384 curve.
Definition: ike.h:1168
RSA/DSA/ECDSA/EdDSA signature verification.
uint8_t psk[IPSEC_MAX_PSK_LEN]
Pre-shared key.
Definition: ipsec.h:417
Debugging facilities.
#define ikeAllocMem(size)
Definition: ike.h:754
ASN.1 (Abstract Syntax Notation One)
#define arraysize(a)
Definition: os_port.h:71