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