2 * @file authenticator.c
4 * @brief Implementation of authenticator.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include "authenticator.h"
25 #include <utils/allocator.h>
29 * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
31 #define IKE_V2_KEY_PAD "Key Pad for IKEv2"
34 * Length of key pad in bytes.
36 #define IKE_V2_KEY_PAD_LEN strlen(IKE_V2_KEY_PAD)
38 typedef struct private_authenticator_t private_authenticator_t
;
41 * Private data of an authenticator_t object.
43 struct private_authenticator_t
{
46 * Public authenticator_t interface.
48 authenticator_t
public;
51 * Assigned IKE_SA. Needed to get objects of type prf_t, sa_config_t and logger_t.
53 protected_ike_sa_t
*ike_sa
;
56 * PRF taken from the IKE_SA.
63 * Using logger of IKE_SA.
68 * Creates the octets which are signed (RSA) or MACed (shared secret) as described in section
71 * @param this calling object
72 * @param last_message the last message to include in created octets
73 * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response)
74 * @param other_nonce Nonce data received from other peer
75 * @param my_id id_payload_t object representing an ID payload
76 * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise
77 * @return octets as described in section 2.15. Memory gets allocated and has to get
78 * destroyed by caller.
80 chunk_t (*allocate_octets
) (private_authenticator_t
*this,chunk_t last_message
, chunk_t other_nonce
,id_payload_t
*my_id
, bool initiator
);
83 * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
85 * @param this calling object
86 * @param last_message the last message
87 * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response)
88 * @param nonce Nonce data to include in auth data compution
89 * @param id_payload id_payload_t object representing an ID payload
90 * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise
91 * @param shared_secret shared secret as chunk_t. If shared secret is a string, the NULL termination is not included.
92 * @return AUTH data as dscribed in section 2.15 for AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
93 * Memory gets allocated and has to get destroyed by caller.
95 chunk_t (*allocate_auth_data_with_preshared_secret
) (private_authenticator_t
*this,chunk_t last_message
, chunk_t nonce
,id_payload_t
*id_payload
, bool initiator
,chunk_t preshared_secret
);
99 * Implementation of private_authenticator_t.allocate_octets.
101 static chunk_t
allocate_octets(private_authenticator_t
*this,chunk_t last_message
, chunk_t other_nonce
,id_payload_t
*my_id
, bool initiator
)
103 chunk_t id_chunk
= my_id
->get_data(my_id
);
104 u_int8_t id_with_header
[4 + id_chunk
.len
];
105 chunk_t id_with_header_chunk
= {ptr
:id_with_header
, len
: sizeof(id_with_header
) };
106 u_int8_t
*current_pos
;
109 id_with_header
[0] = my_id
->get_id_type(my_id
);
111 * Reserved bytes are not in any case zero.
113 id_with_header
[1] = 0x00;
114 id_with_header
[2] = 0x00;
115 id_with_header
[3] = 0x00;
116 memcpy(id_with_header
+ 4,id_chunk
.ptr
,id_chunk
.len
);
120 this->prf
->set_key(this->prf
,this->ike_sa
->get_key_pi(this->ike_sa
));
124 this->prf
->set_key(this->prf
,this->ike_sa
->get_key_pr(this->ike_sa
));
127 /* 4 bytes are id type and reserved fields of id payload */
128 octets
.len
= last_message
.len
+ other_nonce
.len
+ this->prf
->get_block_size(this->prf
);
129 octets
.ptr
= allocator_alloc(octets
.len
);
130 current_pos
= octets
.ptr
;
131 memcpy(current_pos
,last_message
.ptr
,last_message
.len
);
132 current_pos
+= last_message
.len
;
133 memcpy(current_pos
,other_nonce
.ptr
,other_nonce
.len
);
134 current_pos
+= other_nonce
.len
;
135 this->prf
->get_bytes(this->prf
,id_with_header_chunk
,current_pos
);
137 this->logger
->log_chunk(this->logger
,RAW
| MOST
, "Octets (Mesage + Nonce + prf(Sk_px,Idx)",&octets
);
142 * Implementation of private_authenticator_t.allocate_auth_data_with_preshared_secret.
144 static chunk_t
allocate_auth_data_with_preshared_secret (private_authenticator_t
*this,chunk_t last_message
, chunk_t nonce
,id_payload_t
*id_payload
, bool initiator
,chunk_t preshared_secret
)
146 chunk_t key_pad
= {ptr
: IKE_V2_KEY_PAD
, len
:IKE_V2_KEY_PAD_LEN
};
147 u_int8_t key_buffer
[this->prf
->get_block_size(this->prf
)];
148 chunk_t key
= {ptr
: key_buffer
, len
: sizeof(key_buffer
)};
151 chunk_t octets
= this->allocate_octets(this,last_message
,nonce
,id_payload
,initiator
);
154 * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>)
157 this->prf
->set_key(this->prf
,preshared_secret
);
158 this->prf
->get_bytes(this->prf
,key_pad
,key_buffer
);
159 this->prf
->set_key(this->prf
,key
);
160 this->prf
->allocate_bytes(this->prf
,octets
,&auth_data
);
161 allocator_free_chunk(&octets
);
162 this->logger
->log_chunk(this->logger
,RAW
| MOST
, "Authenticated data",&auth_data
);
168 * Implementation of authenticator_t.verify_auth_data.
170 static status_t
verify_auth_data (private_authenticator_t
*this,auth_payload_t
*auth_payload
, chunk_t last_received_packet
,chunk_t my_nonce
,id_payload_t
*other_id_payload
,bool initiator
,bool *verified
)
172 switch(auth_payload
->get_auth_method(auth_payload
))
174 case SHARED_KEY_MESSAGE_INTEGRITY_CODE
:
177 identification_t
*other_id
= other_id_payload
->get_identification(other_id_payload
);
178 chunk_t auth_data
= auth_payload
->get_data(auth_payload
);
179 chunk_t preshared_secret
;
182 status
= charon
->configuration_manager
->get_shared_secret(charon
->configuration_manager
,other_id
,&preshared_secret
);
183 other_id
->destroy(other_id
);
184 if (status
!= SUCCESS
)
189 chunk_t my_auth_data
= this->allocate_auth_data_with_preshared_secret(this,last_received_packet
,my_nonce
,other_id_payload
,initiator
,preshared_secret
);
191 if (auth_data
.len
!= my_auth_data
.len
)
194 allocator_free_chunk(&my_auth_data
);
197 if (memcmp(auth_data
.ptr
,my_auth_data
.ptr
,my_auth_data
.len
) == 0)
205 allocator_free_chunk(&my_auth_data
);
208 case RSA_DIGITAL_SIGNATURE
:
210 identification_t
*other_id
= other_id_payload
->get_identification(other_id_payload
);
211 rsa_public_key_t
*public_key
;
213 chunk_t octets
, auth_data
;
215 auth_data
= auth_payload
->get_data(auth_payload
);
217 status
= charon
->configuration_manager
->get_rsa_public_key(charon
->configuration_manager
, other_id
, &public_key
);
218 other_id
->destroy(other_id
);
219 if (status
!= SUCCESS
)
224 octets
= this->allocate_octets(this,last_received_packet
,my_nonce
,other_id_payload
,initiator
);
226 status
= public_key
->verify_emsa_pkcs1_signature(public_key
, octets
, auth_data
);
227 if (status
== SUCCESS
)
236 allocator_free_chunk(&octets
);
241 return NOT_SUPPORTED
;
247 * Implementation of authenticator_t.compute_auth_data.
249 static status_t
compute_auth_data (private_authenticator_t
*this,auth_payload_t
**auth_payload
, chunk_t last_sent_packet
,chunk_t other_nonce
,id_payload_t
*my_id_payload
,bool initiator
)
251 sa_config_t
*sa_config
= this->ike_sa
->get_sa_config(this->ike_sa
);
253 switch(sa_config
->get_auth_method(sa_config
))
255 case SHARED_KEY_MESSAGE_INTEGRITY_CODE
:
257 identification_t
*my_id
=my_id_payload
->get_identification(my_id_payload
);
258 chunk_t preshared_secret
;
261 status
= charon
->configuration_manager
->get_shared_secret(charon
->configuration_manager
,my_id
,&preshared_secret
);
263 my_id
->destroy(my_id
);
264 if (status
!= SUCCESS
)
269 chunk_t auth_data
= this->allocate_auth_data_with_preshared_secret(this,last_sent_packet
,other_nonce
,my_id_payload
,initiator
,preshared_secret
);
271 *auth_payload
= auth_payload_create();
272 (*auth_payload
)->set_auth_method((*auth_payload
),SHARED_KEY_MESSAGE_INTEGRITY_CODE
);
273 (*auth_payload
)->set_data((*auth_payload
),auth_data
);
275 allocator_free_chunk(&auth_data
);
278 case RSA_DIGITAL_SIGNATURE
:
280 identification_t
*my_id
= my_id_payload
->get_identification(my_id_payload
);
281 rsa_private_key_t
*private_key
;
283 chunk_t octets
, auth_data
;
285 status
= charon
->configuration_manager
->get_rsa_private_key(charon
->configuration_manager
, my_id
, &private_key
);
286 my_id
->destroy(my_id
);
287 if (status
!= SUCCESS
)
292 octets
= this->allocate_octets(this,last_sent_packet
,other_nonce
,my_id_payload
,initiator
);
294 status
= private_key
->build_emsa_pkcs1_signature(private_key
, HASH_SHA1
, octets
, &auth_data
);
295 allocator_free_chunk(&octets
);
296 if (status
!= SUCCESS
)
301 *auth_payload
= auth_payload_create();
302 (*auth_payload
)->set_auth_method((*auth_payload
), RSA_DIGITAL_SIGNATURE
);
303 (*auth_payload
)->set_data((*auth_payload
),auth_data
);
305 allocator_free_chunk(&auth_data
);
310 return NOT_SUPPORTED
;
316 * Implementation of authenticator_t.destroy.
318 static void destroy (private_authenticator_t
*this)
320 allocator_free(this);
324 * Described in header.
326 authenticator_t
*authenticator_create(protected_ike_sa_t
*ike_sa
)
328 private_authenticator_t
*this = allocator_alloc_thing(private_authenticator_t
);
330 /* Public functions */
331 this->public.destroy
= (void(*)(authenticator_t
*))destroy
;
332 this->public.verify_auth_data
= (status_t (*) (authenticator_t
*,auth_payload_t
*, chunk_t
,chunk_t
,id_payload_t
*,bool,bool *)) verify_auth_data
;
333 this->public.compute_auth_data
= (status_t (*) (authenticator_t
*,auth_payload_t
**, chunk_t
,chunk_t
,id_payload_t
*,bool)) compute_auth_data
;
335 /* private functions */
336 this->allocate_octets
= allocate_octets
;
337 this->allocate_auth_data_with_preshared_secret
= allocate_auth_data_with_preshared_secret
;
340 this->ike_sa
= ike_sa
;
341 this->prf
= this->ike_sa
->get_prf(this->ike_sa
);
342 this->logger
= this->ike_sa
->get_logger(this->ike_sa
);
344 return &(this->public);