Fixed return value if SIG payload missing
[strongswan.git] / src / libcharon / sa / authenticators / pubkey_v1_authenticator.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pubkey_v1_authenticator.h"
17
18 #include <daemon.h>
19 #include <sa/keymat_v1.h>
20 #include <encoding/payloads/hash_payload.h>
21
22 typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t;
23
24 /**
25 * Private data of an pubkey_v1_authenticator_t object.
26 */
27 struct private_pubkey_v1_authenticator_t {
28
29 /**
30 * Public authenticator_t interface.
31 */
32 pubkey_v1_authenticator_t public;
33
34 /**
35 * Assigned IKE_SA
36 */
37 ike_sa_t *ike_sa;
38
39 /**
40 * TRUE if we are initiator
41 */
42 bool initiator;
43
44 /**
45 * DH key exchange
46 */
47 diffie_hellman_t *dh;
48
49 /**
50 * Others DH public value
51 */
52 chunk_t dh_value;
53
54 /**
55 * Encoded SA payload, without fixed header
56 */
57 chunk_t sa_payload;
58
59 /**
60 * Encoded ID payload, without fixed header
61 */
62 chunk_t id_payload;
63 };
64
65 METHOD(authenticator_t, build, status_t,
66 private_pubkey_v1_authenticator_t *this, message_t *message)
67 {
68 hash_payload_t *sig_payload;
69 chunk_t hash, sig, dh;
70 keymat_v1_t *keymat;
71 status_t status;
72 private_key_t *private;
73 identification_t *id;
74 auth_cfg_t *auth;
75 key_type_t type;
76 signature_scheme_t scheme;
77
78 /* TODO-IKEv1: other key types */
79 type = KEY_RSA;
80 scheme = SIGN_RSA_EMSA_PKCS1_NULL;
81
82 id = this->ike_sa->get_my_id(this->ike_sa);
83 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
84 private = lib->credmgr->get_private(lib->credmgr, type, id, auth);
85 if (!private)
86 {
87 DBG1(DBG_IKE, "no private key found for '%Y'", id);
88 return NOT_FOUND;
89 }
90
91 this->dh->get_my_public_value(this->dh, &dh);
92 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
93 hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
94 this->ike_sa->get_id(this->ike_sa), this->sa_payload,
95 this->id_payload);
96 free(dh.ptr);
97
98 if (private->sign(private, scheme, hash, &sig))
99 {
100 sig_payload = hash_payload_create(SIGNATURE_V1);
101 sig_payload->set_hash(sig_payload, sig);
102 free(sig.ptr);
103 message->add_payload(message, &sig_payload->payload_interface);
104 status = SUCCESS;
105 DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id);
106 }
107 else
108 {
109 DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
110 status = FAILED;
111 }
112 private->destroy(private);
113 free(hash.ptr);
114
115 return status;
116 }
117
118 METHOD(authenticator_t, process, status_t,
119 private_pubkey_v1_authenticator_t *this, message_t *message)
120 {
121 chunk_t hash, sig, dh;
122 keymat_v1_t *keymat;
123 public_key_t *public;
124 hash_payload_t *sig_payload;
125 auth_cfg_t *auth, *current_auth;
126 enumerator_t *enumerator;
127 status_t status = NOT_FOUND;
128 key_type_t type;
129 signature_scheme_t scheme;
130 identification_t *id;
131
132 /* TODO-IKEv1: currently RSA only */
133 type = KEY_RSA;
134 scheme = SIGN_RSA_EMSA_PKCS1_NULL;
135
136 sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1);
137 if (!sig_payload)
138 {
139 DBG1(DBG_IKE, "SIG payload missing in message");
140 return FAILED;
141 }
142
143 id = this->ike_sa->get_other_id(this->ike_sa);
144 this->dh->get_my_public_value(this->dh, &dh);
145 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
146 hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
147 this->ike_sa->get_id(this->ike_sa), this->sa_payload,
148 this->id_payload);
149 free(dh.ptr);
150
151 sig = sig_payload->get_hash(sig_payload);
152 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
153 enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, type,
154 id, auth);
155 while (enumerator->enumerate(enumerator, &public, &current_auth))
156 {
157 if (public->verify(public, scheme, hash, sig))
158 {
159 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
160 id, key_type_names, type);
161 status = SUCCESS;
162 auth->merge(auth, current_auth, FALSE);
163 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
164 break;
165 }
166 else
167 {
168 DBG1(DBG_IKE, "signature validation failed, looking for another key");
169 status = FAILED;
170 }
171 }
172 enumerator->destroy(enumerator);
173 free(hash.ptr);
174 if (status != SUCCESS)
175 {
176 DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
177 key_type_names, type, id);
178 }
179 return status;
180 }
181
182 METHOD(authenticator_t, destroy, void,
183 private_pubkey_v1_authenticator_t *this)
184 {
185 chunk_free(&this->id_payload);
186 free(this);
187 }
188
189 /*
190 * Described in header.
191 */
192 pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
193 bool initiator, diffie_hellman_t *dh,
194 chunk_t dh_value, chunk_t sa_payload,
195 chunk_t id_payload)
196 {
197 private_pubkey_v1_authenticator_t *this;
198
199 INIT(this,
200 .public = {
201 .authenticator = {
202 .build = _build,
203 .process = _process,
204 .is_mutual = (void*)return_false,
205 .destroy = _destroy,
206 },
207 },
208 .ike_sa = ike_sa,
209 .initiator = initiator,
210 .dh = dh,
211 .dh_value = dh_value,
212 .sa_payload = sa_payload,
213 .id_payload = id_payload,
214 );
215
216 return &this->public;
217 }