Migrated ike_cert_post to INIT/METHOD macros
[strongswan.git] / src / libcharon / sa / tasks / ike_cert_post.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2006-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 */
16
17 #include "ike_cert_post.h"
18
19 #include <daemon.h>
20 #include <sa/ike_sa.h>
21 #include <encoding/payloads/cert_payload.h>
22 #include <encoding/payloads/certreq_payload.h>
23 #include <encoding/payloads/auth_payload.h>
24 #include <credentials/certificates/x509.h>
25
26
27 typedef struct private_ike_cert_post_t private_ike_cert_post_t;
28
29 /**
30 * Private members of a ike_cert_post_t task.
31 */
32 struct private_ike_cert_post_t {
33
34 /**
35 * Public methods and task_t interface.
36 */
37 ike_cert_post_t public;
38
39 /**
40 * Assigned IKE_SA.
41 */
42 ike_sa_t *ike_sa;
43
44 /**
45 * Are we the initiator?
46 */
47 bool initiator;
48 };
49
50 /**
51 * Generates the cert payload, if possible with "Hash and URL"
52 */
53 static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
54 certificate_t *cert)
55 {
56 hasher_t *hasher;
57 identification_t *id;
58 chunk_t hash, encoded ;
59 enumerator_t *enumerator;
60 char *url;
61 cert_payload_t *payload = NULL;
62
63 if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
64 {
65 return cert_payload_create_from_cert(cert);
66 }
67
68 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
69 if (!hasher)
70 {
71 DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
72 return cert_payload_create_from_cert(cert);
73 }
74
75 if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
76 {
77 DBG1(DBG_IKE, "encoding certificate for cert payload failed");
78 hasher->destroy(hasher);
79 return NULL;
80 }
81 hasher->allocate_hash(hasher, encoded, &hash);
82 chunk_free(&encoded);
83 hasher->destroy(hasher);
84 id = identification_create_from_encoding(ID_KEY_ID, hash);
85
86 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id);
87 if (enumerator->enumerate(enumerator, &url))
88 {
89 payload = cert_payload_create_from_hash_and_url(hash, url);
90 DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url);
91 }
92 else
93 {
94 payload = cert_payload_create_from_cert(cert);
95 }
96 enumerator->destroy(enumerator);
97 chunk_free(&hash);
98 id->destroy(id);
99 return payload;
100 }
101
102 /**
103 * add certificates to message
104 */
105 static void build_certs(private_ike_cert_post_t *this, message_t *message)
106 {
107 peer_cfg_t *peer_cfg;
108 auth_payload_t *payload;
109
110 payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
111 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
112 if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK)
113 { /* no CERT payload for EAP/PSK */
114 return;
115 }
116
117 switch (peer_cfg->get_cert_policy(peer_cfg))
118 {
119 case CERT_NEVER_SEND:
120 break;
121 case CERT_SEND_IF_ASKED:
122 if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN))
123 {
124 break;
125 }
126 /* FALL */
127 case CERT_ALWAYS_SEND:
128 {
129 cert_payload_t *payload;
130 enumerator_t *enumerator;
131 certificate_t *cert;
132 auth_rule_t type;
133 auth_cfg_t *auth;
134
135 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
136
137 /* get subject cert first, then issuing certificates */
138 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
139 if (!cert)
140 {
141 break;
142 }
143 payload = build_cert_payload(this, cert);
144 if (!payload)
145 {
146 break;
147 }
148 DBG1(DBG_IKE, "sending end entity cert \"%Y\"",
149 cert->get_subject(cert));
150 message->add_payload(message, (payload_t*)payload);
151
152 enumerator = auth->create_enumerator(auth);
153 while (enumerator->enumerate(enumerator, &type, &cert))
154 {
155 if (type == AUTH_RULE_IM_CERT)
156 {
157 payload = cert_payload_create_from_cert(cert);
158 if (payload)
159 {
160 DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
161 cert->get_subject(cert));
162 message->add_payload(message, (payload_t*)payload);
163 }
164 }
165 }
166 enumerator->destroy(enumerator);
167 }
168 }
169 }
170
171 METHOD(task_t, build_i, status_t,
172 private_ike_cert_post_t *this, message_t *message)
173 {
174 build_certs(this, message);
175
176 return NEED_MORE;
177 }
178
179 METHOD(task_t, process_r, status_t,
180 private_ike_cert_post_t *this, message_t *message)
181 {
182 return NEED_MORE;
183 }
184
185 METHOD(task_t, build_r, status_t,
186 private_ike_cert_post_t *this, message_t *message)
187 {
188 build_certs(this, message);
189
190 if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
191 { /* stay alive, we might have additional rounds with certs */
192 return NEED_MORE;
193 }
194 return SUCCESS;
195 }
196
197 METHOD(task_t, process_i, status_t,
198 private_ike_cert_post_t *this, message_t *message)
199 {
200 if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
201 { /* stay alive, we might have additional rounds with CERTS */
202 return NEED_MORE;
203 }
204 return SUCCESS;
205 }
206
207 METHOD(task_t, get_type, task_type_t,
208 private_ike_cert_post_t *this)
209 {
210 return IKE_CERT_POST;
211 }
212
213 METHOD(task_t, migrate, void,
214 private_ike_cert_post_t *this, ike_sa_t *ike_sa)
215 {
216 this->ike_sa = ike_sa;
217 }
218
219 METHOD(task_t, destroy, void,
220 private_ike_cert_post_t *this)
221 {
222 free(this);
223 }
224
225 /*
226 * Described in header.
227 */
228 ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator)
229 {
230 private_ike_cert_post_t *this;
231
232 INIT(this,
233 .public = {
234 .task = {
235 .get_type = _get_type,
236 .migrate = _migrate,
237 .destroy = _destroy,
238 },
239 },
240 .ike_sa = ike_sa,
241 .initiator = initiator,
242 );
243
244 if (initiator)
245 {
246 this->public.task.build = _build_i;
247 this->public.task.process = _process_i;
248 }
249 else
250 {
251 this->public.task.build = _build_r;
252 this->public.task.process = _process_r;
253 }
254
255 return &this->public;
256 }
257