2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2006-2009 Martin Willi
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
17 #include "ike_cert_pre.h"
20 #include <sa/ike_sa.h>
21 #include <encoding/payloads/cert_payload.h>
22 #include <encoding/payloads/certreq_payload.h>
23 #include <credentials/certificates/x509.h>
26 typedef struct private_ike_cert_pre_t private_ike_cert_pre_t
;
29 * Private members of a ike_cert_pre_t task.
31 struct private_ike_cert_pre_t
{
34 * Public methods and task_t interface.
36 ike_cert_pre_t
public;
44 * Are we the initiator?
49 * Do we accept HTTP certificate lookup requests
54 * whether this is the final authentication round
60 * read certificate requests
62 static void process_certreqs(private_ike_cert_pre_t
*this, message_t
*message
)
64 enumerator_t
*enumerator
;
68 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
70 enumerator
= message
->create_payload_enumerator(message
);
71 while (enumerator
->enumerate(enumerator
, &payload
))
73 switch (payload
->get_type(payload
))
75 case CERTIFICATE_REQUEST
:
77 certreq_payload_t
*certreq
= (certreq_payload_t
*)payload
;
78 enumerator_t
*enumerator
;
82 this->ike_sa
->set_condition(this->ike_sa
, COND_CERTREQ_SEEN
, TRUE
);
84 if (certreq
->get_cert_type(certreq
) != CERT_X509
)
86 DBG1(DBG_IKE
, "cert payload %N not supported - ignored",
87 certificate_type_names
, certreq
->get_cert_type(certreq
));
90 enumerator
= certreq
->create_keyid_enumerator(certreq
);
91 while (enumerator
->enumerate(enumerator
, &keyid
))
96 id
= identification_create_from_encoding(ID_KEY_ID
, keyid
);
97 cert
= lib
->credmgr
->get_cert(lib
->credmgr
,
98 CERT_X509
, KEY_ANY
, id
, TRUE
);
101 DBG1(DBG_IKE
, "received cert request for \"%Y\"",
102 cert
->get_subject(cert
));
103 auth
->add(auth
, AUTH_RULE_CA_CERT
, cert
);
107 DBG2(DBG_IKE
, "received cert request for unknown ca "
108 "with keyid %Y", id
);
113 enumerator
->destroy(enumerator
);
116 DBG1(DBG_IKE
, "received %u cert requests for an unknown ca",
123 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
125 /* we only handle one type of notify here */
126 if (notify
->get_notify_type(notify
) == HTTP_CERT_LOOKUP_SUPPORTED
)
128 this->ike_sa
->enable_extension(this->ike_sa
, EXT_HASH_AND_URL
);
133 /* ignore other payloads here, these are handled elsewhere */
137 enumerator
->destroy(enumerator
);
141 * tries to extract a certificate from the cert payload or the credential
142 * manager (based on the hash of a "Hash and URL" encoded cert).
143 * Note: the returned certificate (if any) has to be destroyed
145 static certificate_t
*try_get_cert(cert_payload_t
*cert_payload
)
147 certificate_t
*cert
= NULL
;
149 switch (cert_payload
->get_cert_encoding(cert_payload
))
151 case ENC_X509_SIGNATURE
:
153 cert
= cert_payload
->get_cert(cert_payload
);
156 case ENC_X509_HASH_AND_URL
:
158 identification_t
*id
;
159 chunk_t hash
= cert_payload
->get_hash(cert_payload
);
162 /* invalid "Hash and URL" data (logged elsewhere) */
165 id
= identification_create_from_encoding(ID_KEY_ID
, hash
);
166 cert
= lib
->credmgr
->get_cert(lib
->credmgr
,
167 CERT_X509
, KEY_ANY
, id
, FALSE
);
180 * import certificates
182 static void process_certs(private_ike_cert_pre_t
*this, message_t
*message
)
184 enumerator_t
*enumerator
;
189 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
191 enumerator
= message
->create_payload_enumerator(message
);
192 while (enumerator
->enumerate(enumerator
, &payload
))
194 if (payload
->get_type(payload
) == CERTIFICATE
)
196 cert_payload_t
*cert_payload
;
197 cert_encoding_t encoding
;
201 cert_payload
= (cert_payload_t
*)payload
;
202 encoding
= cert_payload
->get_cert_encoding(cert_payload
);
206 case ENC_X509_HASH_AND_URL
:
208 if (!this->do_http_lookup
)
210 DBG1(DBG_IKE
, "received hash-and-url encoded cert, but"
211 " we don't accept them, ignore");
216 case ENC_X509_SIGNATURE
:
218 cert
= try_get_cert(cert_payload
);
222 { /* the first is an end entity certificate */
223 DBG1(DBG_IKE
, "received end entity cert \"%Y\"",
224 cert
->get_subject(cert
));
225 auth
->add(auth
, AUTH_HELPER_SUBJECT_CERT
, cert
);
230 DBG1(DBG_IKE
, "received issuer cert \"%Y\"",
231 cert
->get_subject(cert
));
232 auth
->add(auth
, AUTH_HELPER_IM_CERT
, cert
);
235 else if (encoding
== ENC_X509_HASH_AND_URL
)
237 /* we fetch the certificate not yet, but only if
238 * it is really needed during authentication */
239 url
= cert_payload
->get_url(cert_payload
);
242 DBG1(DBG_IKE
, "received invalid hash-and-url "
243 "encoded cert, ignore");
248 { /* first URL is for an end entity certificate */
249 DBG1(DBG_IKE
, "received hash-and-url for end"
250 " entity cert \"%s\"", url
);
251 auth
->add(auth
, AUTH_HELPER_SUBJECT_HASH_URL
, url
);
256 DBG1(DBG_IKE
, "received hash-and-url for issuer"
257 " cert \"%s\"", url
);
258 auth
->add(auth
, AUTH_HELPER_IM_HASH_URL
, url
);
264 cert
= cert_payload
->get_cert(cert_payload
);
267 DBG1(DBG_IKE
, "received CRL \"%Y\"",
268 cert
->get_subject(cert
));
269 auth
->add(auth
, AUTH_HELPER_REVOCATION_CERT
, cert
);
272 case ENC_PKCS7_WRAPPED_X509
:
274 case ENC_DNS_SIGNED_KEY
:
275 case ENC_KERBEROS_TOKEN
:
278 case ENC_X509_ATTRIBUTE
:
279 case ENC_RAW_RSA_KEY
:
280 case ENC_X509_HASH_AND_URL_BUNDLE
:
281 case ENC_OCSP_CONTENT
:
283 DBG1(DBG_ENC
, "certificate encoding %N not supported",
284 cert_encoding_names
, encoding
);
288 enumerator
->destroy(enumerator
);
292 * add the keyid of a certificate to the certificate request payload
294 static void add_certreq(certreq_payload_t
**req
, certificate_t
*cert
)
296 switch (cert
->get_type(cert
))
300 public_key_t
*public;
302 x509_t
*x509
= (x509_t
*)cert
;
304 if (!(x509
->get_flags(x509
) & X509_CA
))
305 { /* no CA cert, skip */
308 public = cert
->get_public_key(cert
);
315 *req
= certreq_payload_create_type(CERT_X509
);
317 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1
, &keyid
))
319 (*req
)->add_keyid(*req
, keyid
);
320 DBG1(DBG_IKE
, "sending cert request for \"%Y\"",
321 cert
->get_subject(cert
));
323 public->destroy(public);
332 * add a auth_cfg's CA certificates to the certificate request
334 static void add_certreqs(certreq_payload_t
**req
, auth_cfg_t
*auth
)
336 enumerator_t
*enumerator
;
340 enumerator
= auth
->create_enumerator(auth
);
341 while (enumerator
->enumerate(enumerator
, &type
, &value
))
345 case AUTH_RULE_CA_CERT
:
346 add_certreq(req
, (certificate_t
*)value
);
352 enumerator
->destroy(enumerator
);
356 * build certificate requests
358 static void build_certreqs(private_ike_cert_pre_t
*this, message_t
*message
)
360 enumerator_t
*enumerator
;
362 peer_cfg_t
*peer_cfg
;
365 certreq_payload_t
*req
= NULL
;
367 ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
368 if (!ike_cfg
->send_certreq(ike_cfg
))
373 /* check if we require a specific CA for that peer */
374 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
377 enumerator
= peer_cfg
->create_auth_cfg_enumerator(peer_cfg
, FALSE
);
378 while (enumerator
->enumerate(enumerator
, &auth
))
380 add_certreqs(&req
, auth
);
382 enumerator
->destroy(enumerator
);
387 /* otherwise add all trusted CA certificates */
388 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
389 CERT_ANY
, KEY_ANY
, NULL
, TRUE
);
390 while (enumerator
->enumerate(enumerator
, &cert
))
392 add_certreq(&req
, cert
);
394 enumerator
->destroy(enumerator
);
399 message
->add_payload(message
, (payload_t
*)req
);
401 if (lib
->settings
->get_bool(lib
->settings
, "charon.hash_and_url", FALSE
))
403 message
->add_notify(message
, FALSE
, HTTP_CERT_LOOKUP_SUPPORTED
,
405 this->do_http_lookup
= TRUE
;
411 * Check if this is the final authentication round
413 static bool final_auth(message_t
*message
)
415 /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */
416 if (message
->get_payload(message
, AUTHENTICATION
) == NULL
)
420 if (message
->get_notify(message
, ANOTHER_AUTH_FOLLOWS
))
427 METHOD(task_t
, build_i
, status_t
,
428 private_ike_cert_pre_t
*this, message_t
*message
)
430 if (message
->get_message_id(message
) == 1)
431 { /* initiator sends CERTREQs in first IKE_AUTH */
432 build_certreqs(this, message
);
437 METHOD(task_t
, process_r
, status_t
,
438 private_ike_cert_pre_t
*this, message_t
*message
)
440 if (message
->get_exchange_type(message
) != IKE_SA_INIT
)
441 { /* handle certreqs/certs in any IKE_AUTH, just in case */
442 process_certreqs(this, message
);
443 process_certs(this, message
);
445 this->final
= final_auth(message
);
449 METHOD(task_t
, build_r
, status_t
,
450 private_ike_cert_pre_t
*this, message_t
*message
)
452 if (message
->get_exchange_type(message
) == IKE_SA_INIT
)
454 build_certreqs(this, message
);
463 METHOD(task_t
, process_i
, status_t
,
464 private_ike_cert_pre_t
*this, message_t
*message
)
466 if (message
->get_exchange_type(message
) == IKE_SA_INIT
)
468 process_certreqs(this, message
);
470 process_certs(this, message
);
472 if (final_auth(message
))
479 METHOD(task_t
, get_type
, task_type_t
,
480 private_ike_cert_pre_t
*this)
482 return TASK_IKE_CERT_PRE
;
485 METHOD(task_t
, migrate
, void,
486 private_ike_cert_pre_t
*this, ike_sa_t
*ike_sa
)
488 this->ike_sa
= ike_sa
;
491 METHOD(task_t
, destroy
, void,
492 private_ike_cert_pre_t
*this)
498 * Described in header.
500 ike_cert_pre_t
*ike_cert_pre_create(ike_sa_t
*ike_sa
, bool initiator
)
502 private_ike_cert_pre_t
*this;
507 .get_type
= _get_type
,
513 .initiator
= initiator
,
518 this->public.task
.build
= _build_i
;
519 this->public.task
.process
= _process_i
;
523 this->public.task
.build
= _build_r
;
524 this->public.task
.process
= _process_r
;
527 return &this->public;