2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include "psk_authenticator.h"
24 #include <credentials/auth_info.h>
27 * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
29 #define IKEV2_KEY_PAD "Key Pad for IKEv2"
30 #define IKEV2_KEY_PAD_LENGTH 17
33 typedef struct private_psk_authenticator_t private_psk_authenticator_t
;
36 * Private data of an psk_authenticator_t object.
38 struct private_psk_authenticator_t
{
41 * Public authenticator_t interface.
43 psk_authenticator_t
public;
52 * Builds the octets to be signed as described in section 2.15 of RFC 4306
54 chunk_t
build_tbs_octets(chunk_t ike_sa_init
, chunk_t nonce
,
55 identification_t
*id
, prf_t
*prf
)
57 u_int8_t id_header_buf
[] = {0x00, 0x00, 0x00, 0x00};
58 chunk_t id_header
= chunk_from_buf(id_header_buf
);
59 chunk_t id_with_header
, id_prfd
, id_encoding
;
61 id_header_buf
[0] = id
->get_type(id
);
62 id_encoding
= id
->get_encoding(id
);
64 id_with_header
= chunk_cat("cc", id_header
, id_encoding
);
65 prf
->allocate_bytes(prf
, id_with_header
, &id_prfd
);
66 chunk_free(&id_with_header
);
68 return chunk_cat("ccm", ike_sa_init
, nonce
, id_prfd
);
72 * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
74 chunk_t
build_shared_key_signature(chunk_t ike_sa_init
, chunk_t nonce
,
75 chunk_t secret
, identification_t
*id
,
76 chunk_t skp
, prf_t
*prf
)
78 chunk_t key_pad
, key
, auth_data
, octets
;
80 prf
->set_key(prf
, skp
);
81 octets
= build_tbs_octets(ike_sa_init
, nonce
, id
, prf
);
82 /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
83 key_pad
.ptr
= IKEV2_KEY_PAD
;
84 key_pad
.len
= IKEV2_KEY_PAD_LENGTH
;
85 prf
->set_key(prf
, secret
);
86 prf
->allocate_bytes(prf
, key_pad
, &key
);
87 prf
->set_key(prf
, key
);
88 prf
->allocate_bytes(prf
, octets
, &auth_data
);
89 DBG3(DBG_IKE
, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets
);
90 DBG3(DBG_IKE
, "secret %B", &secret
);
91 DBG3(DBG_IKE
, "keypad %B", &key_pad
);
92 DBG3(DBG_IKE
, "prf(secret, keypad) %B", &key
);
93 DBG3(DBG_IKE
, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data
);
101 * Implementation of authenticator_t.verify.
103 static status_t
verify(private_psk_authenticator_t
*this, chunk_t ike_sa_init
,
104 chunk_t my_nonce
, auth_payload_t
*auth_payload
)
106 chunk_t auth_data
, recv_auth_data
;
107 identification_t
*my_id
, *other_id
;
108 shared_key_t
*shared_key
;
109 enumerator_t
*enumerator
;
110 bool authenticated
= FALSE
;
113 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
114 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
115 enumerator
= charon
->credentials
->create_shared_enumerator(
116 charon
->credentials
, SHARED_IKE
, my_id
, other_id
);
117 while (!authenticated
&& enumerator
->enumerate(enumerator
, &shared_key
, NULL
, NULL
))
120 auth_data
= build_shared_key_signature(ike_sa_init
, my_nonce
,
121 shared_key
->get_key(shared_key
), other_id
,
122 this->ike_sa
->get_skp_verify(this->ike_sa
),
123 this->ike_sa
->get_prf(this->ike_sa
));
124 recv_auth_data
= auth_payload
->get_data(auth_payload
);
125 if (auth_data
.len
== recv_auth_data
.len
&&
126 memeq(auth_data
.ptr
, recv_auth_data
.ptr
, auth_data
.len
))
128 DBG1(DBG_IKE
, "authentication of '%D' with %N successful",
129 other_id
, auth_method_names
, AUTH_PSK
);
130 authenticated
= TRUE
;
132 chunk_free(&auth_data
);
134 enumerator
->destroy(enumerator
);
140 DBG1(DBG_IKE
, "no shared key found for '%D' - '%D'", my_id
, other_id
);
143 DBG1(DBG_IKE
, "tried %d shared key%s for '%D' - '%D', but MAC mismatched",
144 keys_found
, keys_found
== 1 ?
"" : "s", my_id
, other_id
);
151 * Implementation of authenticator_t.build.
153 static status_t
build(private_psk_authenticator_t
*this, chunk_t ike_sa_init
,
154 chunk_t other_nonce
, auth_payload_t
**auth_payload
)
156 shared_key_t
*shared_key
;
158 identification_t
*my_id
, *other_id
;
160 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
161 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
162 DBG1(DBG_IKE
, "authentication of '%D' (myself) with %N",
163 my_id
, auth_method_names
, AUTH_PSK
);
164 shared_key
= charon
->credentials
->get_shared(charon
->credentials
, SHARED_IKE
,
166 if (shared_key
== NULL
)
168 DBG1(DBG_IKE
, "no shared key found for '%D' - '%D'", my_id
, other_id
);
171 auth_data
= build_shared_key_signature(ike_sa_init
, other_nonce
,
172 shared_key
->get_key(shared_key
), my_id
,
173 this->ike_sa
->get_skp_build(this->ike_sa
),
174 this->ike_sa
->get_prf(this->ike_sa
));
175 shared_key
->destroy(shared_key
);
176 DBG2(DBG_IKE
, "successfully created shared key MAC");
177 *auth_payload
= auth_payload_create();
178 (*auth_payload
)->set_auth_method(*auth_payload
, AUTH_PSK
);
179 (*auth_payload
)->set_data(*auth_payload
, auth_data
);
181 chunk_free(&auth_data
);
186 * Implementation of authenticator_t.destroy.
188 static void destroy(private_psk_authenticator_t
*this)
194 * Described in header.
196 psk_authenticator_t
*psk_authenticator_create(ike_sa_t
*ike_sa
)
198 private_psk_authenticator_t
*this = malloc_thing(private_psk_authenticator_t
);
200 /* public functions */
201 this->public.authenticator_interface
.verify
= (status_t(*)(authenticator_t
*,chunk_t
,chunk_t
,auth_payload_t
*))verify
;
202 this->public.authenticator_interface
.build
= (status_t(*)(authenticator_t
*,chunk_t
,chunk_t
,auth_payload_t
**))build
;
203 this->public.authenticator_interface
.destroy
= (void(*)(authenticator_t
*))destroy
;
206 this->ike_sa
= ike_sa
;
208 return &this->public;