6c041ce268f19a291126d852c70c2a434398dc99
[strongswan.git] / src / libcharon / plugins / ipseckey / ipseckey_cred.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2012 Reto Guadagnini
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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "ipseckey_cred.h"
22 #include "ipseckey.h"
23
24 #include <bio/bio_reader.h>
25
26 typedef struct private_ipseckey_cred_t private_ipseckey_cred_t;
27
28 /**
29 * Private data of an ipseckey_cred_t object
30 */
31 struct private_ipseckey_cred_t {
32
33 /**
34 * Public part
35 */
36 ipseckey_cred_t public;
37
38 /**
39 * DNS resolver
40 */
41 resolver_t *res;
42 };
43
44 /**
45 * enumerator over certificates
46 */
47 typedef struct {
48 /** implements enumerator interface */
49 enumerator_t public;
50 /** inner enumerator (enumerates IPSECKEY resource records) */
51 enumerator_t *inner;
52 /** response of the DNS resolver which contains the IPSECKEYs */
53 resolver_response_t *response;
54 /* IPSECKEYs are not valid before this point in time */
55 time_t notBefore;
56 /* IPSECKEYs are not valid after this point in time */
57 time_t notAfter;
58 /* identity to which the IPSECKEY belongs */
59 identification_t *identity;
60 } cert_enumerator_t;
61
62 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
63 cert_enumerator_t *this, certificate_t **cert)
64 {
65 ipseckey_t *cur_ipseckey;
66 public_key_t *public;
67 rr_t *cur_rr;
68 chunk_t key;
69
70 /* Get the next supported IPSECKEY using the inner enumerator. */
71 while (this->inner->enumerate(this->inner, &cur_rr))
72 {
73 cur_ipseckey = ipseckey_create_frm_rr(cur_rr);
74
75 if (!cur_ipseckey)
76 {
77 DBG1(DBG_CFG, " failed to parse IPSECKEY, skipping");
78 continue;
79 }
80
81 if (cur_ipseckey->get_algorithm(cur_ipseckey) != IPSECKEY_ALGORITHM_RSA)
82 {
83 DBG1(DBG_CFG, " unsupported IPSECKEY algorithm, skipping");
84 cur_ipseckey->destroy(cur_ipseckey);
85 continue;
86 }
87
88 /* wrap the key of the IPSECKEY in a certificate and return this
89 * certificate */
90 key = cur_ipseckey->get_public_key(cur_ipseckey);
91 public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
92 BUILD_BLOB_DNSKEY, key,
93 BUILD_END);
94 if (!public)
95 {
96 DBG1(DBG_CFG, " failed to create public key from IPSECKEY");
97 cur_ipseckey->destroy(cur_ipseckey);
98 continue;
99 }
100
101 *cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
102 CERT_TRUSTED_PUBKEY,
103 BUILD_PUBLIC_KEY, public,
104 BUILD_SUBJECT, this->identity,
105 BUILD_NOT_BEFORE_TIME, this->notBefore,
106 BUILD_NOT_AFTER_TIME, this->notAfter,
107 BUILD_END);
108 if (*cert == NULL)
109 {
110 DBG1(DBG_CFG, " failed to create certificate from IPSECKEY");
111 cur_ipseckey->destroy(cur_ipseckey);
112 public->destroy(public);
113 continue;
114 }
115 cur_ipseckey->destroy(cur_ipseckey);
116 return TRUE;
117 }
118 return FALSE;
119 }
120
121 METHOD(enumerator_t, cert_enumerator_destroy, void,
122 cert_enumerator_t *this)
123 {
124 this->inner->destroy(this->inner);
125 this->response->destroy(this->response);
126 free(this);
127 }
128
129 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
130 private_ipseckey_cred_t *this, certificate_type_t cert, key_type_t key,
131 identification_t *id, bool trusted)
132 {
133 resolver_response_t *response;
134 enumerator_t *rrsig_enum;
135 cert_enumerator_t *e;
136 rr_set_t *rrset;
137 rr_t *rrsig;
138 bio_reader_t *reader;
139 uint32_t nBefore, nAfter;
140 chunk_t ignore;
141 char *fqdn;
142
143 if (!id || id->get_type(id) != ID_FQDN)
144 {
145 return enumerator_create_empty();
146 }
147
148 /* query the DNS for the required IPSECKEY RRs */
149 if (asprintf(&fqdn, "%Y", id) <= 0)
150 {
151 DBG1(DBG_CFG, "failed to determine FQDN to retrieve IPSECKEY RRs");
152 return enumerator_create_empty();
153 }
154 DBG1(DBG_CFG, "performing a DNS query for IPSECKEY RRs of '%s'", fqdn);
155 response = this->res->query(this->res, fqdn, RR_CLASS_IN, RR_TYPE_IPSECKEY);
156 if (!response)
157 {
158 DBG1(DBG_CFG, " query for IPSECKEY RRs failed");
159 free(fqdn);
160 return enumerator_create_empty();
161 }
162 free(fqdn);
163
164 if (!response->has_data(response) ||
165 !response->query_name_exist(response))
166 {
167 DBG1(DBG_CFG, " unable to retrieve IPSECKEY RRs from the DNS");
168 response->destroy(response);
169 return enumerator_create_empty();
170 }
171
172 if (response->get_security_state(response) != SECURE)
173 {
174 DBG1(DBG_CFG, " DNSSEC state of IPSECKEY RRs is not secure");
175 response->destroy(response);
176 return enumerator_create_empty();
177 }
178
179 /* determine the validity period of the retrieved IPSECKEYs
180 *
181 * we use the "Signature Inception" and "Signature Expiration" field
182 * of the first RRSIG RR to determine the validity period of the
183 * IPSECKEY RRs.
184 * TODO: Take multiple RRSIGs into account. */
185 rrset = response->get_rr_set(response);
186 rrsig_enum = rrset->create_rrsig_enumerator(rrset);
187 if (!rrsig_enum || !rrsig_enum->enumerate(rrsig_enum, &rrsig))
188 {
189 DBG1(DBG_CFG, " unable to determine the validity period of "
190 "IPSECKEY RRs because no RRSIGs are present");
191 DESTROY_IF(rrsig_enum);
192 response->destroy(response);
193 return enumerator_create_empty();
194 }
195 rrsig_enum->destroy(rrsig_enum);
196
197 /* parse the RRSIG for its validity period (RFC 4034) */
198 reader = bio_reader_create(rrsig->get_rdata(rrsig));
199 if (!reader->read_data(reader, 8, &ignore) ||
200 !reader->read_uint32(reader, &nAfter) ||
201 !reader->read_uint32(reader, &nBefore))
202 {
203 DBG1(DBG_CFG, " unable to determine the validity period of RRSIG RRs");
204 reader->destroy(reader);
205 response->destroy(response);
206 return enumerator_create_empty();
207 }
208 reader->destroy(reader);
209
210 INIT(e,
211 .public = {
212 .enumerate = (void*)_cert_enumerator_enumerate,
213 .destroy = _cert_enumerator_destroy,
214 },
215 .inner = rrset->create_rr_enumerator(rrset),
216 .response = response,
217 .notBefore = nBefore,
218 .notAfter = nAfter,
219 .identity = id,
220 );
221 return &e->public;
222 }
223
224 METHOD(ipseckey_cred_t, destroy, void,
225 private_ipseckey_cred_t *this)
226 {
227 this->res->destroy(this->res);
228 free(this);
229 }
230
231 /**
232 * Described in header.
233 */
234 ipseckey_cred_t *ipseckey_cred_create(resolver_t *res)
235 {
236 private_ipseckey_cred_t *this;
237
238 INIT(this,
239 .public = {
240 .set = {
241 .create_private_enumerator = (void*)return_null,
242 .create_cert_enumerator = _create_cert_enumerator,
243 .create_shared_enumerator = (void*)return_null,
244 .create_cdp_enumerator = (void*)return_null,
245 .cache_cert = (void*)nop,
246 },
247 .destroy = _destroy,
248 },
249 .res = res,
250 );
251
252 return &this->public;
253 }