dnscert: Properly free enumerated certificates
[strongswan.git] / src / libcharon / plugins / dnscert / dnscert_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 * Copyright (C) 2013 Ruslan Marchenko
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * THE SOFTWARE.
36 */
37
38 #define _GNU_SOURCE
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "dnscert_cred.h"
43 #include "dnscert.h"
44
45 typedef struct private_dnscert_cred_t private_dnscert_cred_t;
46
47 /**
48 * Private data of an dnscert_cred_t object
49 */
50 struct private_dnscert_cred_t {
51
52 /**
53 * Public part
54 */
55 dnscert_cred_t public;
56
57 /**
58 * DNS resolver
59 */
60 resolver_t *res;
61 };
62
63 /**
64 * enumerator over certificates
65 */
66 typedef struct {
67 /** implements enumerator interface */
68 enumerator_t public;
69 /** inner enumerator (enumerates CERT resource records) */
70 enumerator_t *inner;
71 /** response of the DNS resolver which contains the CERTs */
72 resolver_response_t *response;
73 /** most recently enumerated certificate */
74 certificate_t *cert;
75 } cert_enumerator_t;
76
77 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
78 cert_enumerator_t *this, certificate_t **cert)
79 {
80 dnscert_t *cur_crt;
81 rr_t *cur_rr;
82 chunk_t certificate;
83
84 /* Get the next supported CERT using the inner enumerator. */
85 while (this->inner->enumerate(this->inner, &cur_rr))
86 {
87 cur_crt = dnscert_create_frm_rr(cur_rr);
88
89 if (!cur_crt)
90 {
91 DBG1(DBG_CFG, " failed to parse CERT RR, skipping");
92 continue;
93 }
94
95 if (cur_crt->get_cert_type(cur_crt) != DNSCERT_TYPE_PKIX &&
96 cur_crt->get_cert_type(cur_crt) != DNSCERT_TYPE_PGP)
97 {
98 DBG1(DBG_CFG, " unsupported CERT type [%d], skipping",
99 cur_crt->get_cert_type(cur_crt));
100 cur_crt->destroy(cur_crt);
101 continue;
102 }
103 /* Try to parse PEM certificate container. Both x509 and PGP should
104 * presumably come as PEM encoded certs. */
105 certificate = cur_crt->get_certificate(cur_crt);
106 DESTROY_IF(this->cert);
107 this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_ANY,
108 BUILD_BLOB_PEM, certificate,
109 BUILD_END);
110 cur_crt->destroy(cur_crt);
111 if (!this->cert)
112 {
113 DBG1(DBG_CFG, " unable to parse certificate, skipping");
114 continue;
115 }
116 *cert = this->cert;
117 return TRUE;
118 }
119 return FALSE;
120 }
121
122 METHOD(enumerator_t, cert_enumerator_destroy, void,
123 cert_enumerator_t *this)
124 {
125 DESTROY_IF(this->cert);
126 this->inner->destroy(this->inner);
127 this->response->destroy(this->response);
128 free(this);
129 }
130
131 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
132 private_dnscert_cred_t *this, certificate_type_t cert, key_type_t key,
133 identification_t *id, bool trusted)
134 {
135 resolver_response_t *response;
136 cert_enumerator_t *e;
137 char *fqdn;
138
139 if (!id || id->get_type(id) != ID_FQDN)
140 {
141 return enumerator_create_empty();
142 }
143
144 /* query the DNS for the required CERT RRs */
145 if (asprintf(&fqdn, "%Y", id) <= 0)
146 {
147 DBG1(DBG_CFG, "failed to determine FQDN to retrieve CERT RRs");
148 return enumerator_create_empty();
149 }
150
151 DBG1(DBG_CFG, "performing a DNS query for CERT RRs of '%s'", fqdn);
152 response = this->res->query(this->res, fqdn, RR_CLASS_IN, RR_TYPE_CERT);
153 if (!response)
154 {
155 DBG1(DBG_CFG, " query for CERT RRs failed");
156 free(fqdn);
157 return enumerator_create_empty();
158 }
159 free(fqdn);
160
161 if (!response->has_data(response) ||
162 !response->query_name_exist(response))
163 {
164 DBG1(DBG_CFG, " unable to retrieve CERT RRs from the DNS");
165 response->destroy(response);
166 return enumerator_create_empty();
167 }
168
169 if (response->get_security_state(response) != SECURE)
170 {
171 DBG1(DBG_CFG, " DNSSEC state of CERT RRs is not secure");
172 response->destroy(response);
173 return enumerator_create_empty();
174 }
175
176 INIT(e,
177 .public = {
178 .enumerate = (void*)_cert_enumerator_enumerate,
179 .destroy = _cert_enumerator_destroy,
180 },
181 .inner = response->get_rr_set(response)->create_rr_enumerator(
182 response->get_rr_set(response)),
183 .response = response
184 );
185 return &e->public;
186 }
187
188 METHOD(dnscert_cred_t, destroy, void,
189 private_dnscert_cred_t *this)
190 {
191 this->res->destroy(this->res);
192 free(this);
193 }
194
195 /**
196 * Described in header.
197 */
198 dnscert_cred_t *dnscert_cred_create(resolver_t *res)
199 {
200 private_dnscert_cred_t *this;
201
202 INIT(this,
203 .public = {
204 .set = {
205 .create_private_enumerator = (void*)return_null,
206 .create_cert_enumerator = _create_cert_enumerator,
207 .create_shared_enumerator = (void*)return_null,
208 .create_cdp_enumerator = (void*)return_null,
209 .cache_cert = (void*)nop,
210 },
211 .destroy = _destroy,
212 },
213 .res = res,
214 );
215
216 return &this->public;
217 }