payload: Use common prefixes for all payload type identifiers
[strongswan.git] / src / libcharon / sa / ikev1 / 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/ikev1/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 * Key type to use
66 */
67 key_type_t type;
68 };
69
70 METHOD(authenticator_t, build, status_t,
71 private_pubkey_v1_authenticator_t *this, message_t *message)
72 {
73 hash_payload_t *sig_payload;
74 chunk_t hash, sig, dh;
75 keymat_v1_t *keymat;
76 status_t status;
77 private_key_t *private;
78 identification_t *id;
79 auth_cfg_t *auth;
80 signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL;
81
82 if (this->type == KEY_ECDSA)
83 {
84 scheme = SIGN_ECDSA_WITH_NULL;
85 }
86
87 id = this->ike_sa->get_my_id(this->ike_sa);
88 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
89 private = lib->credmgr->get_private(lib->credmgr, this->type, id, auth);
90 if (!private)
91 {
92 DBG1(DBG_IKE, "no %N private key found for '%Y'",
93 key_type_names, this->type, id);
94 return NOT_FOUND;
95 }
96
97 this->dh->get_my_public_value(this->dh, &dh);
98 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
99 if (!keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
100 this->ike_sa->get_id(this->ike_sa), this->sa_payload,
101 this->id_payload, &hash))
102 {
103 private->destroy(private);
104 free(dh.ptr);
105 return FAILED;
106 }
107 free(dh.ptr);
108
109 if (private->sign(private, scheme, hash, &sig))
110 {
111 sig_payload = hash_payload_create(PLV1_SIGNATURE);
112 sig_payload->set_hash(sig_payload, sig);
113 free(sig.ptr);
114 message->add_payload(message, &sig_payload->payload_interface);
115 status = SUCCESS;
116 DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id);
117 }
118 else
119 {
120 DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
121 status = FAILED;
122 }
123 private->destroy(private);
124 free(hash.ptr);
125
126 return status;
127 }
128
129 METHOD(authenticator_t, process, status_t,
130 private_pubkey_v1_authenticator_t *this, message_t *message)
131 {
132 chunk_t hash, sig, dh;
133 keymat_v1_t *keymat;
134 public_key_t *public;
135 hash_payload_t *sig_payload;
136 auth_cfg_t *auth, *current_auth;
137 enumerator_t *enumerator;
138 status_t status = NOT_FOUND;
139 identification_t *id;
140 signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL;
141
142 if (this->type == KEY_ECDSA)
143 {
144 scheme = SIGN_ECDSA_WITH_NULL;
145 }
146
147 sig_payload = (hash_payload_t*)message->get_payload(message, PLV1_SIGNATURE);
148 if (!sig_payload)
149 {
150 DBG1(DBG_IKE, "SIG payload missing in message");
151 return FAILED;
152 }
153
154 id = this->ike_sa->get_other_id(this->ike_sa);
155 this->dh->get_my_public_value(this->dh, &dh);
156 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
157 if (!keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
158 this->ike_sa->get_id(this->ike_sa), this->sa_payload,
159 this->id_payload, &hash))
160 {
161 free(dh.ptr);
162 return FAILED;
163 }
164 free(dh.ptr);
165
166 sig = sig_payload->get_hash(sig_payload);
167 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
168 enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, this->type,
169 id, auth);
170 while (enumerator->enumerate(enumerator, &public, &current_auth))
171 {
172 if (public->verify(public, scheme, hash, sig))
173 {
174 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
175 id, key_type_names, this->type);
176 status = SUCCESS;
177 auth->merge(auth, current_auth, FALSE);
178 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
179 break;
180 }
181 else
182 {
183 DBG1(DBG_IKE, "signature validation failed, looking for another key");
184 status = FAILED;
185 }
186 }
187 enumerator->destroy(enumerator);
188 free(hash.ptr);
189 if (status != SUCCESS)
190 {
191 DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
192 key_type_names, this->type, id);
193 }
194 return status;
195 }
196
197 METHOD(authenticator_t, destroy, void,
198 private_pubkey_v1_authenticator_t *this)
199 {
200 chunk_free(&this->id_payload);
201 free(this);
202 }
203
204 /*
205 * Described in header.
206 */
207 pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
208 bool initiator, diffie_hellman_t *dh,
209 chunk_t dh_value, chunk_t sa_payload,
210 chunk_t id_payload, key_type_t type)
211 {
212 private_pubkey_v1_authenticator_t *this;
213
214 INIT(this,
215 .public = {
216 .authenticator = {
217 .build = _build,
218 .process = _process,
219 .is_mutual = (void*)return_false,
220 .destroy = _destroy,
221 },
222 },
223 .ike_sa = ike_sa,
224 .initiator = initiator,
225 .dh = dh,
226 .dh_value = dh_value,
227 .sa_payload = sa_payload,
228 .id_payload = id_payload,
229 .type = type,
230 );
231
232 return &this->public;
233 }