payload: Use common prefixes for all payload type identifiers
[strongswan.git] / src / libcharon / sa / ikev2 / 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 #include <credentials/certificates/ac.h>
26
27
28 typedef struct private_ike_cert_post_t private_ike_cert_post_t;
29
30 /**
31 * Private members of a ike_cert_post_t task.
32 */
33 struct private_ike_cert_post_t {
34
35 /**
36 * Public methods and task_t interface.
37 */
38 ike_cert_post_t public;
39
40 /**
41 * Assigned IKE_SA.
42 */
43 ike_sa_t *ike_sa;
44
45 /**
46 * Are we the initiator?
47 */
48 bool initiator;
49 };
50
51 /**
52 * Generates the cert payload, if possible with "Hash and URL"
53 */
54 static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
55 certificate_t *cert)
56 {
57 hasher_t *hasher;
58 identification_t *id;
59 chunk_t hash, encoded ;
60 enumerator_t *enumerator;
61 char *url;
62 cert_payload_t *payload = NULL;
63
64 if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
65 {
66 return cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
67 }
68
69 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
70 if (!hasher)
71 {
72 DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
73 return cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
74 }
75
76 if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
77 {
78 DBG1(DBG_IKE, "encoding certificate for cert payload failed");
79 hasher->destroy(hasher);
80 return NULL;
81 }
82 if (!hasher->allocate_hash(hasher, encoded, &hash))
83 {
84 hasher->destroy(hasher);
85 chunk_free(&encoded);
86 return cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
87 }
88 chunk_free(&encoded);
89 hasher->destroy(hasher);
90 id = identification_create_from_encoding(ID_KEY_ID, hash);
91
92 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id);
93 if (enumerator->enumerate(enumerator, &url))
94 {
95 payload = cert_payload_create_from_hash_and_url(hash, url);
96 DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url);
97 }
98 else
99 {
100 payload = cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
101 }
102 enumerator->destroy(enumerator);
103 chunk_free(&hash);
104 id->destroy(id);
105 return payload;
106 }
107
108 /**
109 * Add subject certificate to message
110 */
111 static bool add_subject_cert(private_ike_cert_post_t *this, auth_cfg_t *auth,
112 message_t *message)
113 {
114 cert_payload_t *payload;
115 certificate_t *cert;
116
117 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
118 if (!cert)
119 {
120 return FALSE;
121 }
122 payload = build_cert_payload(this, cert);
123 if (!payload)
124 {
125 return FALSE;
126 }
127 DBG1(DBG_IKE, "sending end entity cert \"%Y\"", cert->get_subject(cert));
128 message->add_payload(message, (payload_t*)payload);
129 return TRUE;
130 }
131
132 /**
133 * Add intermediate CA certificates to message
134 */
135 static void add_im_certs(private_ike_cert_post_t *this, auth_cfg_t *auth,
136 message_t *message)
137 {
138 cert_payload_t *payload;
139 enumerator_t *enumerator;
140 certificate_t *cert;
141 auth_rule_t type;
142
143 enumerator = auth->create_enumerator(auth);
144 while (enumerator->enumerate(enumerator, &type, &cert))
145 {
146 if (type == AUTH_RULE_IM_CERT)
147 {
148 payload = cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
149 if (payload)
150 {
151 DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
152 cert->get_subject(cert));
153 message->add_payload(message, (payload_t*)payload);
154 }
155 }
156 }
157 enumerator->destroy(enumerator);
158 }
159
160 /**
161 * Add any valid attribute certificates of subject to message
162 */
163 static void add_attribute_certs(private_ike_cert_post_t *this,
164 auth_cfg_t *auth, message_t *message)
165 {
166 certificate_t *subject, *cert;
167
168 subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
169 if (subject && subject->get_type(subject) == CERT_X509)
170 {
171 x509_t *x509 = (x509_t*)subject;
172 identification_t *id, *serial;
173 enumerator_t *enumerator;
174 cert_payload_t *payload;
175 ac_t *ac;
176
177 /* we look for attribute certs having our serial and holder issuer,
178 * which is recommended by RFC 5755 */
179 serial = identification_create_from_encoding(ID_KEY_ID,
180 x509->get_serial(x509));
181 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
182 CERT_X509_AC, KEY_ANY, serial, FALSE);
183 while (enumerator->enumerate(enumerator, &ac))
184 {
185 cert = &ac->certificate;
186 id = ac->get_holderIssuer(ac);
187 if (id && id->equals(id, subject->get_issuer(subject)) &&
188 cert->get_validity(cert, NULL, NULL, NULL))
189 {
190 payload = cert_payload_create_from_cert(PLV2_CERTIFICATE, cert);
191 if (payload)
192 {
193 DBG1(DBG_IKE, "sending attribute certificate "
194 "issued by \"%Y\"", cert->get_issuer(cert));
195 message->add_payload(message, (payload_t*)payload);
196 }
197 }
198 }
199 enumerator->destroy(enumerator);
200 serial->destroy(serial);
201 }
202 }
203
204 /**
205 * add certificates to message
206 */
207 static void build_certs(private_ike_cert_post_t *this, message_t *message)
208 {
209 peer_cfg_t *peer_cfg;
210 auth_payload_t *payload;
211 auth_cfg_t *auth;
212
213 payload = (auth_payload_t*)message->get_payload(message, PLV2_AUTH);
214 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
215 if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK)
216 { /* no CERT payload for EAP/PSK */
217 return;
218 }
219
220 switch (peer_cfg->get_cert_policy(peer_cfg))
221 {
222 case CERT_NEVER_SEND:
223 break;
224 case CERT_SEND_IF_ASKED:
225 if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN))
226 {
227 break;
228 }
229 /* FALL */
230 case CERT_ALWAYS_SEND:
231 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
232 if (add_subject_cert(this, auth, message))
233 {
234 add_im_certs(this, auth, message);
235 add_attribute_certs(this, auth, message);
236 }
237 break;
238 }
239 }
240
241 METHOD(task_t, build_i, status_t,
242 private_ike_cert_post_t *this, message_t *message)
243 {
244 build_certs(this, message);
245
246 return NEED_MORE;
247 }
248
249 METHOD(task_t, process_r, status_t,
250 private_ike_cert_post_t *this, message_t *message)
251 {
252 return NEED_MORE;
253 }
254
255 METHOD(task_t, build_r, status_t,
256 private_ike_cert_post_t *this, message_t *message)
257 {
258 build_certs(this, message);
259
260 if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
261 { /* stay alive, we might have additional rounds with certs */
262 return NEED_MORE;
263 }
264 return SUCCESS;
265 }
266
267 METHOD(task_t, process_i, status_t,
268 private_ike_cert_post_t *this, message_t *message)
269 {
270 if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
271 { /* stay alive, we might have additional rounds with CERTS */
272 return NEED_MORE;
273 }
274 return SUCCESS;
275 }
276
277 METHOD(task_t, get_type, task_type_t,
278 private_ike_cert_post_t *this)
279 {
280 return TASK_IKE_CERT_POST;
281 }
282
283 METHOD(task_t, migrate, void,
284 private_ike_cert_post_t *this, ike_sa_t *ike_sa)
285 {
286 this->ike_sa = ike_sa;
287 }
288
289 METHOD(task_t, destroy, void,
290 private_ike_cert_post_t *this)
291 {
292 free(this);
293 }
294
295 /*
296 * Described in header.
297 */
298 ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator)
299 {
300 private_ike_cert_post_t *this;
301
302 INIT(this,
303 .public = {
304 .task = {
305 .get_type = _get_type,
306 .migrate = _migrate,
307 .destroy = _destroy,
308 },
309 },
310 .ike_sa = ike_sa,
311 .initiator = initiator,
312 );
313
314 if (initiator)
315 {
316 this->public.task.build = _build_i;
317 this->public.task.process = _process_i;
318 }
319 else
320 {
321 this->public.task.build = _build_r;
322 this->public.task.process = _process_r;
323 }
324
325 return &this->public;
326 }