unbound-anchor.c revision 1.1.1.1.2.2 1 1.1.1.1.2.2 pgoyette /*
2 1.1.1.1.2.2 pgoyette * unbound-anchor.c - update the root anchor if necessary.
3 1.1.1.1.2.2 pgoyette *
4 1.1.1.1.2.2 pgoyette * Copyright (c) 2010, NLnet Labs. All rights reserved.
5 1.1.1.1.2.2 pgoyette *
6 1.1.1.1.2.2 pgoyette * This software is open source.
7 1.1.1.1.2.2 pgoyette *
8 1.1.1.1.2.2 pgoyette * Redistribution and use in source and binary forms, with or without
9 1.1.1.1.2.2 pgoyette * modification, are permitted provided that the following conditions
10 1.1.1.1.2.2 pgoyette * are met:
11 1.1.1.1.2.2 pgoyette *
12 1.1.1.1.2.2 pgoyette * Redistributions of source code must retain the above copyright notice,
13 1.1.1.1.2.2 pgoyette * this list of conditions and the following disclaimer.
14 1.1.1.1.2.2 pgoyette *
15 1.1.1.1.2.2 pgoyette * Redistributions in binary form must reproduce the above copyright notice,
16 1.1.1.1.2.2 pgoyette * this list of conditions and the following disclaimer in the documentation
17 1.1.1.1.2.2 pgoyette * and/or other materials provided with the distribution.
18 1.1.1.1.2.2 pgoyette *
19 1.1.1.1.2.2 pgoyette * Neither the name of the NLNET LABS nor the names of its contributors may
20 1.1.1.1.2.2 pgoyette * be used to endorse or promote products derived from this software without
21 1.1.1.1.2.2 pgoyette * specific prior written permission.
22 1.1.1.1.2.2 pgoyette *
23 1.1.1.1.2.2 pgoyette * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 1.1.1.1.2.2 pgoyette * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 1.1.1.1.2.2 pgoyette * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 1.1.1.1.2.2 pgoyette * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 1.1.1.1.2.2 pgoyette * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 1.1.1.1.2.2 pgoyette * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 1.1.1.1.2.2 pgoyette * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 1.1.1.1.2.2 pgoyette * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 1.1.1.1.2.2 pgoyette * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 1.1.1.1.2.2 pgoyette * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 1.1.1.1.2.2 pgoyette * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 1.1.1.1.2.2 pgoyette */
35 1.1.1.1.2.2 pgoyette
36 1.1.1.1.2.2 pgoyette /**
37 1.1.1.1.2.2 pgoyette * \file
38 1.1.1.1.2.2 pgoyette *
39 1.1.1.1.2.2 pgoyette * This file checks to see that the current 5011 keys work to prime the
40 1.1.1.1.2.2 pgoyette * current root anchor. If not a certificate is used to update the anchor.
41 1.1.1.1.2.2 pgoyette *
42 1.1.1.1.2.2 pgoyette * This is a concept solution for distribution of the DNSSEC root
43 1.1.1.1.2.2 pgoyette * trust anchor. It is a small tool, called "unbound-anchor", that
44 1.1.1.1.2.2 pgoyette * runs before the main validator starts. I.e. in the init script:
45 1.1.1.1.2.2 pgoyette * unbound-anchor; unbound. Thus it is meant to run at system boot time.
46 1.1.1.1.2.2 pgoyette *
47 1.1.1.1.2.2 pgoyette * Management-Abstract:
48 1.1.1.1.2.2 pgoyette * * first run: fill root.key file with hardcoded DS record.
49 1.1.1.1.2.2 pgoyette * * mostly: use RFC5011 tracking, quick . DNSKEY UDP query.
50 1.1.1.1.2.2 pgoyette * * failover: use builtin certificate, do https and update.
51 1.1.1.1.2.2 pgoyette * Special considerations:
52 1.1.1.1.2.2 pgoyette * * 30-days RFC5011 timer saves a lot of https traffic.
53 1.1.1.1.2.2 pgoyette * * DNSKEY probe must be NOERROR, saves a lot of https traffic.
54 1.1.1.1.2.2 pgoyette * * fail if clock before sign date of the root, if cert expired.
55 1.1.1.1.2.2 pgoyette * * if the root goes back to unsigned, deals with it.
56 1.1.1.1.2.2 pgoyette *
57 1.1.1.1.2.2 pgoyette * It has hardcoded the root DS anchors and the ICANN CA root certificate.
58 1.1.1.1.2.2 pgoyette * It allows with options to override those. It also takes root-hints (it
59 1.1.1.1.2.2 pgoyette * has to do a DNS resolve), and also has hardcoded defaults for those.
60 1.1.1.1.2.2 pgoyette *
61 1.1.1.1.2.2 pgoyette * Once it starts, just before the validator starts, it quickly checks if
62 1.1.1.1.2.2 pgoyette * the root anchor file needs to be updated. First it tries to use
63 1.1.1.1.2.2 pgoyette * RFC5011-tracking of the root key. If that fails (and for 30-days since
64 1.1.1.1.2.2 pgoyette * last successful probe), then it attempts to update using the
65 1.1.1.1.2.2 pgoyette * certificate. So most of the time, the RFC5011 tracking will work fine,
66 1.1.1.1.2.2 pgoyette * and within a couple milliseconds, the main daemon can start. It will
67 1.1.1.1.2.2 pgoyette * have only probed the . DNSKEY, not done expensive https transfers on the
68 1.1.1.1.2.2 pgoyette * root infrastructure.
69 1.1.1.1.2.2 pgoyette *
70 1.1.1.1.2.2 pgoyette * If there is no root key in the root.key file, it bootstraps the
71 1.1.1.1.2.2 pgoyette * RFC5011-tracking with its builtin DS anchors; if that fails it
72 1.1.1.1.2.2 pgoyette * bootstraps the RFC5011-tracking using the certificate. (again to avoid
73 1.1.1.1.2.2 pgoyette * https, and it is also faster).
74 1.1.1.1.2.2 pgoyette *
75 1.1.1.1.2.2 pgoyette * It uses the XML file by converting it to DS records and writing that to the
76 1.1.1.1.2.2 pgoyette * key file. Unbound can detect that the 'special comments' are gone, and
77 1.1.1.1.2.2 pgoyette * the file contains a list of normal DNSKEY/DS records, and uses that to
78 1.1.1.1.2.2 pgoyette * bootstrap 5011 (the KSK is made VALID).
79 1.1.1.1.2.2 pgoyette *
80 1.1.1.1.2.2 pgoyette * The certificate update is done by fetching root-anchors.xml and
81 1.1.1.1.2.2 pgoyette * root-anchors.p7s via SSL. The HTTPS certificate can be logged but is
82 1.1.1.1.2.2 pgoyette * not validated (https for channel security; the security comes from the
83 1.1.1.1.2.2 pgoyette * certificate). The 'data.iana.org' domain name A and AAAA are resolved
84 1.1.1.1.2.2 pgoyette * without DNSSEC. It tries a random IP until the transfer succeeds. It
85 1.1.1.1.2.2 pgoyette * then checks the p7s signature.
86 1.1.1.1.2.2 pgoyette *
87 1.1.1.1.2.2 pgoyette * On any failure, it leaves the root key file untouched. The main
88 1.1.1.1.2.2 pgoyette * validator has to cope with it, it cannot fix things (So a failure does
89 1.1.1.1.2.2 pgoyette * not go 'without DNSSEC', no downgrade). If it used its builtin stuff or
90 1.1.1.1.2.2 pgoyette * did the https, it exits with an exit code, so that this can trigger the
91 1.1.1.1.2.2 pgoyette * init script to log the event and potentially alert the operator that can
92 1.1.1.1.2.2 pgoyette * do a manual check.
93 1.1.1.1.2.2 pgoyette *
94 1.1.1.1.2.2 pgoyette * The date is also checked. Before 2010-07-15 is a failure (root not
95 1.1.1.1.2.2 pgoyette * signed yet; avoids attacks on system clock). The
96 1.1.1.1.2.2 pgoyette * last-successful-RFC5011-probe (if available) has to be more than 30 days
97 1.1.1.1.2.2 pgoyette * in the past (otherwise, RFC5011 should have worked). This keeps
98 1.1.1.1.2.2 pgoyette * unnecessary https traffic down. If the main certificate is expired, it
99 1.1.1.1.2.2 pgoyette * fails.
100 1.1.1.1.2.2 pgoyette *
101 1.1.1.1.2.2 pgoyette * The dates on the keys in the xml are checked (uses the libexpat xml
102 1.1.1.1.2.2 pgoyette * parser), only the valid ones are used to re-enstate RFC5011 tracking.
103 1.1.1.1.2.2 pgoyette * If 0 keys are valid, the zone has gone to insecure (a special marker is
104 1.1.1.1.2.2 pgoyette * written in the keyfile that tells the main validator daemon the zone is
105 1.1.1.1.2.2 pgoyette * insecure).
106 1.1.1.1.2.2 pgoyette *
107 1.1.1.1.2.2 pgoyette * Only the root ICANN CA is shipped, not the intermediate ones. The
108 1.1.1.1.2.2 pgoyette * intermediate CAs are included in the p7s file that was downloaded. (the
109 1.1.1.1.2.2 pgoyette * root cert is valid to 2028 and the intermediate to 2014, today).
110 1.1.1.1.2.2 pgoyette *
111 1.1.1.1.2.2 pgoyette * Obviously, the tool also has options so the operator can provide a new
112 1.1.1.1.2.2 pgoyette * keyfile, a new certificate and new URLs, and fresh root hints. By
113 1.1.1.1.2.2 pgoyette * default it logs nothing on failure and success; it 'just works'.
114 1.1.1.1.2.2 pgoyette *
115 1.1.1.1.2.2 pgoyette */
116 1.1.1.1.2.2 pgoyette
117 1.1.1.1.2.2 pgoyette #include "config.h"
118 1.1.1.1.2.2 pgoyette #include "libunbound/unbound.h"
119 1.1.1.1.2.2 pgoyette #include "sldns/rrdef.h"
120 1.1.1.1.2.2 pgoyette #include "sldns/parseutil.h"
121 1.1.1.1.2.2 pgoyette #include <expat.h>
122 1.1.1.1.2.2 pgoyette #ifndef HAVE_EXPAT_H
123 1.1.1.1.2.2 pgoyette #error "need libexpat to parse root-anchors.xml file."
124 1.1.1.1.2.2 pgoyette #endif
125 1.1.1.1.2.2 pgoyette #ifdef HAVE_GETOPT_H
126 1.1.1.1.2.2 pgoyette #include <getopt.h>
127 1.1.1.1.2.2 pgoyette #endif
128 1.1.1.1.2.2 pgoyette #ifdef HAVE_OPENSSL_SSL_H
129 1.1.1.1.2.2 pgoyette #include <openssl/ssl.h>
130 1.1.1.1.2.2 pgoyette #endif
131 1.1.1.1.2.2 pgoyette #ifdef HAVE_OPENSSL_ERR_H
132 1.1.1.1.2.2 pgoyette #include <openssl/err.h>
133 1.1.1.1.2.2 pgoyette #endif
134 1.1.1.1.2.2 pgoyette #ifdef HAVE_OPENSSL_RAND_H
135 1.1.1.1.2.2 pgoyette #include <openssl/rand.h>
136 1.1.1.1.2.2 pgoyette #endif
137 1.1.1.1.2.2 pgoyette #include <openssl/x509.h>
138 1.1.1.1.2.2 pgoyette #include <openssl/x509v3.h>
139 1.1.1.1.2.2 pgoyette #include <openssl/pem.h>
140 1.1.1.1.2.2 pgoyette
141 1.1.1.1.2.2 pgoyette /** name of server in URL to fetch HTTPS from */
142 1.1.1.1.2.2 pgoyette #define URLNAME "data.iana.org"
143 1.1.1.1.2.2 pgoyette /** path on HTTPS server to xml file */
144 1.1.1.1.2.2 pgoyette #define XMLNAME "root-anchors/root-anchors.xml"
145 1.1.1.1.2.2 pgoyette /** path on HTTPS server to p7s file */
146 1.1.1.1.2.2 pgoyette #define P7SNAME "root-anchors/root-anchors.p7s"
147 1.1.1.1.2.2 pgoyette /** name of the signer of the certificate */
148 1.1.1.1.2.2 pgoyette #define P7SIGNER "dnssec (at) iana.org"
149 1.1.1.1.2.2 pgoyette /** port number for https access */
150 1.1.1.1.2.2 pgoyette #define HTTPS_PORT 443
151 1.1.1.1.2.2 pgoyette
152 1.1.1.1.2.2 pgoyette #ifdef USE_WINSOCK
153 1.1.1.1.2.2 pgoyette /* sneakily reuse the the wsa_strerror function, on windows */
154 1.1.1.1.2.2 pgoyette char* wsa_strerror(int err);
155 1.1.1.1.2.2 pgoyette #endif
156 1.1.1.1.2.2 pgoyette
157 1.1.1.1.2.2 pgoyette /** verbosity for this application */
158 1.1.1.1.2.2 pgoyette static int verb = 0;
159 1.1.1.1.2.2 pgoyette
160 1.1.1.1.2.2 pgoyette /** list of IP addresses */
161 1.1.1.1.2.2 pgoyette struct ip_list {
162 1.1.1.1.2.2 pgoyette /** next in list */
163 1.1.1.1.2.2 pgoyette struct ip_list* next;
164 1.1.1.1.2.2 pgoyette /** length of addr */
165 1.1.1.1.2.2 pgoyette socklen_t len;
166 1.1.1.1.2.2 pgoyette /** address ready to connect to */
167 1.1.1.1.2.2 pgoyette struct sockaddr_storage addr;
168 1.1.1.1.2.2 pgoyette /** has the address been used */
169 1.1.1.1.2.2 pgoyette int used;
170 1.1.1.1.2.2 pgoyette };
171 1.1.1.1.2.2 pgoyette
172 1.1.1.1.2.2 pgoyette /** Give unbound-anchor usage, and exit (1). */
173 1.1.1.1.2.2 pgoyette static void
174 1.1.1.1.2.2 pgoyette usage()
175 1.1.1.1.2.2 pgoyette {
176 1.1.1.1.2.2 pgoyette printf("Usage: unbound-anchor [opts]\n");
177 1.1.1.1.2.2 pgoyette printf(" Setup or update root anchor. "
178 1.1.1.1.2.2 pgoyette "Most options have defaults.\n");
179 1.1.1.1.2.2 pgoyette printf(" Run this program before you start the validator.\n");
180 1.1.1.1.2.2 pgoyette printf("\n");
181 1.1.1.1.2.2 pgoyette printf(" The anchor and cert have default builtin content\n");
182 1.1.1.1.2.2 pgoyette printf(" if the file does not exist or is empty.\n");
183 1.1.1.1.2.2 pgoyette printf("\n");
184 1.1.1.1.2.2 pgoyette printf("-a file root key file, default %s\n", ROOT_ANCHOR_FILE);
185 1.1.1.1.2.2 pgoyette printf(" The key is input and output for this tool.\n");
186 1.1.1.1.2.2 pgoyette printf("-c file cert file, default %s\n", ROOT_CERT_FILE);
187 1.1.1.1.2.2 pgoyette printf("-l list builtin key and cert on stdout\n");
188 1.1.1.1.2.2 pgoyette printf("-u name server in https url, default %s\n", URLNAME);
189 1.1.1.1.2.2 pgoyette printf("-x path pathname to xml in url, default %s\n", XMLNAME);
190 1.1.1.1.2.2 pgoyette printf("-s path pathname to p7s in url, default %s\n", P7SNAME);
191 1.1.1.1.2.2 pgoyette printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER);
192 1.1.1.1.2.2 pgoyette printf("-4 work using IPv4 only\n");
193 1.1.1.1.2.2 pgoyette printf("-6 work using IPv6 only\n");
194 1.1.1.1.2.2 pgoyette printf("-f resolv.conf use given resolv.conf to resolve -u name\n");
195 1.1.1.1.2.2 pgoyette printf("-r root.hints use given root.hints to resolve -u name\n"
196 1.1.1.1.2.2 pgoyette " builtin root hints are used by default\n");
197 1.1.1.1.2.2 pgoyette printf("-v more verbose\n");
198 1.1.1.1.2.2 pgoyette printf("-C conf debug, read config\n");
199 1.1.1.1.2.2 pgoyette printf("-P port use port for https connect, default 443\n");
200 1.1.1.1.2.2 pgoyette printf("-F debug, force update with cert\n");
201 1.1.1.1.2.2 pgoyette printf("-h show this usage help\n");
202 1.1.1.1.2.2 pgoyette printf("Version %s\n", PACKAGE_VERSION);
203 1.1.1.1.2.2 pgoyette printf("BSD licensed, see LICENSE in source package for details.\n");
204 1.1.1.1.2.2 pgoyette printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
205 1.1.1.1.2.2 pgoyette exit(1);
206 1.1.1.1.2.2 pgoyette }
207 1.1.1.1.2.2 pgoyette
208 1.1.1.1.2.2 pgoyette /** return the built in root update certificate */
209 1.1.1.1.2.2 pgoyette static const char*
210 1.1.1.1.2.2 pgoyette get_builtin_cert(void)
211 1.1.1.1.2.2 pgoyette {
212 1.1.1.1.2.2 pgoyette return
213 1.1.1.1.2.2 pgoyette /* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */
214 1.1.1.1.2.2 pgoyette "-----BEGIN CERTIFICATE-----\n"
215 1.1.1.1.2.2 pgoyette "MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
216 1.1.1.1.2.2 pgoyette "TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
217 1.1.1.1.2.2 pgoyette "BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n"
218 1.1.1.1.2.2 pgoyette "DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n"
219 1.1.1.1.2.2 pgoyette "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n"
220 1.1.1.1.2.2 pgoyette "MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n"
221 1.1.1.1.2.2 pgoyette "cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n"
222 1.1.1.1.2.2 pgoyette "G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n"
223 1.1.1.1.2.2 pgoyette "ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n"
224 1.1.1.1.2.2 pgoyette "paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n"
225 1.1.1.1.2.2 pgoyette "MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n"
226 1.1.1.1.2.2 pgoyette "iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
227 1.1.1.1.2.2 pgoyette "Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n"
228 1.1.1.1.2.2 pgoyette "DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n"
229 1.1.1.1.2.2 pgoyette "6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n"
230 1.1.1.1.2.2 pgoyette "2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n"
231 1.1.1.1.2.2 pgoyette "15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
232 1.1.1.1.2.2 pgoyette "0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
233 1.1.1.1.2.2 pgoyette "j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
234 1.1.1.1.2.2 pgoyette "-----END CERTIFICATE-----\n"
235 1.1.1.1.2.2 pgoyette ;
236 1.1.1.1.2.2 pgoyette }
237 1.1.1.1.2.2 pgoyette
238 1.1.1.1.2.2 pgoyette /** return the built in root DS trust anchor */
239 1.1.1.1.2.2 pgoyette static const char*
240 1.1.1.1.2.2 pgoyette get_builtin_ds(void)
241 1.1.1.1.2.2 pgoyette {
242 1.1.1.1.2.2 pgoyette return
243 1.1.1.1.2.2 pgoyette ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n";
244 1.1.1.1.2.2 pgoyette }
245 1.1.1.1.2.2 pgoyette
246 1.1.1.1.2.2 pgoyette /** print hex data */
247 1.1.1.1.2.2 pgoyette static void
248 1.1.1.1.2.2 pgoyette print_data(const char* msg, const char* data, int len)
249 1.1.1.1.2.2 pgoyette {
250 1.1.1.1.2.2 pgoyette int i;
251 1.1.1.1.2.2 pgoyette printf("%s: ", msg);
252 1.1.1.1.2.2 pgoyette for(i=0; i<len; i++) {
253 1.1.1.1.2.2 pgoyette printf(" %2.2x", (unsigned char)data[i]);
254 1.1.1.1.2.2 pgoyette }
255 1.1.1.1.2.2 pgoyette printf("\n");
256 1.1.1.1.2.2 pgoyette }
257 1.1.1.1.2.2 pgoyette
258 1.1.1.1.2.2 pgoyette /** print ub context creation error and exit */
259 1.1.1.1.2.2 pgoyette static void
260 1.1.1.1.2.2 pgoyette ub_ctx_error_exit(struct ub_ctx* ctx, const char* str, const char* str2)
261 1.1.1.1.2.2 pgoyette {
262 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
263 1.1.1.1.2.2 pgoyette if(str && str2 && verb) printf("%s: %s\n", str, str2);
264 1.1.1.1.2.2 pgoyette if(verb) printf("error: could not create unbound resolver context\n");
265 1.1.1.1.2.2 pgoyette exit(0);
266 1.1.1.1.2.2 pgoyette }
267 1.1.1.1.2.2 pgoyette
268 1.1.1.1.2.2 pgoyette /**
269 1.1.1.1.2.2 pgoyette * Create a new unbound context with the commandline settings applied
270 1.1.1.1.2.2 pgoyette */
271 1.1.1.1.2.2 pgoyette static struct ub_ctx*
272 1.1.1.1.2.2 pgoyette create_unbound_context(const char* res_conf, const char* root_hints,
273 1.1.1.1.2.2 pgoyette const char* debugconf, int ip4only, int ip6only)
274 1.1.1.1.2.2 pgoyette {
275 1.1.1.1.2.2 pgoyette int r;
276 1.1.1.1.2.2 pgoyette struct ub_ctx* ctx = ub_ctx_create();
277 1.1.1.1.2.2 pgoyette if(!ctx) {
278 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
279 1.1.1.1.2.2 pgoyette exit(0);
280 1.1.1.1.2.2 pgoyette }
281 1.1.1.1.2.2 pgoyette /* do not waste time and network traffic to fetch extra nameservers */
282 1.1.1.1.2.2 pgoyette r = ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0");
283 1.1.1.1.2.2 pgoyette if(r && verb) printf("ctx targetfetchpolicy: %s\n", ub_strerror(r));
284 1.1.1.1.2.2 pgoyette /* read config file first, so its settings can be overridden */
285 1.1.1.1.2.2 pgoyette if(debugconf) {
286 1.1.1.1.2.2 pgoyette r = ub_ctx_config(ctx, debugconf);
287 1.1.1.1.2.2 pgoyette if(r) ub_ctx_error_exit(ctx, debugconf, ub_strerror(r));
288 1.1.1.1.2.2 pgoyette }
289 1.1.1.1.2.2 pgoyette if(res_conf) {
290 1.1.1.1.2.2 pgoyette r = ub_ctx_resolvconf(ctx, res_conf);
291 1.1.1.1.2.2 pgoyette if(r) ub_ctx_error_exit(ctx, res_conf, ub_strerror(r));
292 1.1.1.1.2.2 pgoyette }
293 1.1.1.1.2.2 pgoyette if(root_hints) {
294 1.1.1.1.2.2 pgoyette r = ub_ctx_set_option(ctx, "root-hints:", root_hints);
295 1.1.1.1.2.2 pgoyette if(r) ub_ctx_error_exit(ctx, root_hints, ub_strerror(r));
296 1.1.1.1.2.2 pgoyette }
297 1.1.1.1.2.2 pgoyette if(ip4only) {
298 1.1.1.1.2.2 pgoyette r = ub_ctx_set_option(ctx, "do-ip6:", "no");
299 1.1.1.1.2.2 pgoyette if(r) ub_ctx_error_exit(ctx, "ip4only", ub_strerror(r));
300 1.1.1.1.2.2 pgoyette }
301 1.1.1.1.2.2 pgoyette if(ip6only) {
302 1.1.1.1.2.2 pgoyette r = ub_ctx_set_option(ctx, "do-ip4:", "no");
303 1.1.1.1.2.2 pgoyette if(r) ub_ctx_error_exit(ctx, "ip6only", ub_strerror(r));
304 1.1.1.1.2.2 pgoyette }
305 1.1.1.1.2.2 pgoyette return ctx;
306 1.1.1.1.2.2 pgoyette }
307 1.1.1.1.2.2 pgoyette
308 1.1.1.1.2.2 pgoyette /** printout certificate in detail */
309 1.1.1.1.2.2 pgoyette static void
310 1.1.1.1.2.2 pgoyette verb_cert(const char* msg, X509* x)
311 1.1.1.1.2.2 pgoyette {
312 1.1.1.1.2.2 pgoyette if(verb == 0 || verb == 1) return;
313 1.1.1.1.2.2 pgoyette if(verb == 2) {
314 1.1.1.1.2.2 pgoyette if(msg) printf("%s\n", msg);
315 1.1.1.1.2.2 pgoyette X509_print_ex_fp(stdout, x, 0, (unsigned long)-1
316 1.1.1.1.2.2 pgoyette ^(X509_FLAG_NO_SUBJECT
317 1.1.1.1.2.2 pgoyette |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY));
318 1.1.1.1.2.2 pgoyette return;
319 1.1.1.1.2.2 pgoyette }
320 1.1.1.1.2.2 pgoyette if(msg) printf("%s\n", msg);
321 1.1.1.1.2.2 pgoyette X509_print_fp(stdout, x);
322 1.1.1.1.2.2 pgoyette }
323 1.1.1.1.2.2 pgoyette
324 1.1.1.1.2.2 pgoyette /** printout certificates in detail */
325 1.1.1.1.2.2 pgoyette static void
326 1.1.1.1.2.2 pgoyette verb_certs(const char* msg, STACK_OF(X509)* sk)
327 1.1.1.1.2.2 pgoyette {
328 1.1.1.1.2.2 pgoyette int i, num = sk_X509_num(sk);
329 1.1.1.1.2.2 pgoyette if(verb == 0 || verb == 1) return;
330 1.1.1.1.2.2 pgoyette for(i=0; i<num; i++) {
331 1.1.1.1.2.2 pgoyette printf("%s (%d/%d)\n", msg, i, num);
332 1.1.1.1.2.2 pgoyette verb_cert(NULL, sk_X509_value(sk, i));
333 1.1.1.1.2.2 pgoyette }
334 1.1.1.1.2.2 pgoyette }
335 1.1.1.1.2.2 pgoyette
336 1.1.1.1.2.2 pgoyette /** read certificates from a PEM bio */
337 1.1.1.1.2.2 pgoyette static STACK_OF(X509)*
338 1.1.1.1.2.2 pgoyette read_cert_bio(BIO* bio)
339 1.1.1.1.2.2 pgoyette {
340 1.1.1.1.2.2 pgoyette STACK_OF(X509) *sk = sk_X509_new_null();
341 1.1.1.1.2.2 pgoyette if(!sk) {
342 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
343 1.1.1.1.2.2 pgoyette exit(0);
344 1.1.1.1.2.2 pgoyette }
345 1.1.1.1.2.2 pgoyette while(!BIO_eof(bio)) {
346 1.1.1.1.2.2 pgoyette X509* x = PEM_read_bio_X509(bio, NULL, 0, NULL);
347 1.1.1.1.2.2 pgoyette if(x == NULL) {
348 1.1.1.1.2.2 pgoyette if(verb) {
349 1.1.1.1.2.2 pgoyette printf("failed to read X509\n");
350 1.1.1.1.2.2 pgoyette ERR_print_errors_fp(stdout);
351 1.1.1.1.2.2 pgoyette }
352 1.1.1.1.2.2 pgoyette continue;
353 1.1.1.1.2.2 pgoyette }
354 1.1.1.1.2.2 pgoyette if(!sk_X509_push(sk, x)) {
355 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
356 1.1.1.1.2.2 pgoyette exit(0);
357 1.1.1.1.2.2 pgoyette }
358 1.1.1.1.2.2 pgoyette }
359 1.1.1.1.2.2 pgoyette return sk;
360 1.1.1.1.2.2 pgoyette }
361 1.1.1.1.2.2 pgoyette
362 1.1.1.1.2.2 pgoyette /* read the certificate file */
363 1.1.1.1.2.2 pgoyette static STACK_OF(X509)*
364 1.1.1.1.2.2 pgoyette read_cert_file(const char* file)
365 1.1.1.1.2.2 pgoyette {
366 1.1.1.1.2.2 pgoyette STACK_OF(X509)* sk;
367 1.1.1.1.2.2 pgoyette FILE* in;
368 1.1.1.1.2.2 pgoyette int content = 0;
369 1.1.1.1.2.2 pgoyette char buf[128];
370 1.1.1.1.2.2 pgoyette if(file == NULL || strcmp(file, "") == 0) {
371 1.1.1.1.2.2 pgoyette return NULL;
372 1.1.1.1.2.2 pgoyette }
373 1.1.1.1.2.2 pgoyette sk = sk_X509_new_null();
374 1.1.1.1.2.2 pgoyette if(!sk) {
375 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
376 1.1.1.1.2.2 pgoyette exit(0);
377 1.1.1.1.2.2 pgoyette }
378 1.1.1.1.2.2 pgoyette in = fopen(file, "r");
379 1.1.1.1.2.2 pgoyette if(!in) {
380 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", file, strerror(errno));
381 1.1.1.1.2.2 pgoyette #ifndef S_SPLINT_S
382 1.1.1.1.2.2 pgoyette sk_X509_pop_free(sk, X509_free);
383 1.1.1.1.2.2 pgoyette #endif
384 1.1.1.1.2.2 pgoyette return NULL;
385 1.1.1.1.2.2 pgoyette }
386 1.1.1.1.2.2 pgoyette while(!feof(in)) {
387 1.1.1.1.2.2 pgoyette X509* x = PEM_read_X509(in, NULL, 0, NULL);
388 1.1.1.1.2.2 pgoyette if(x == NULL) {
389 1.1.1.1.2.2 pgoyette if(verb) {
390 1.1.1.1.2.2 pgoyette printf("failed to read X509 file\n");
391 1.1.1.1.2.2 pgoyette ERR_print_errors_fp(stdout);
392 1.1.1.1.2.2 pgoyette }
393 1.1.1.1.2.2 pgoyette continue;
394 1.1.1.1.2.2 pgoyette }
395 1.1.1.1.2.2 pgoyette if(!sk_X509_push(sk, x)) {
396 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
397 1.1.1.1.2.2 pgoyette fclose(in);
398 1.1.1.1.2.2 pgoyette exit(0);
399 1.1.1.1.2.2 pgoyette }
400 1.1.1.1.2.2 pgoyette content = 1;
401 1.1.1.1.2.2 pgoyette /* read away newline after --END CERT-- */
402 1.1.1.1.2.2 pgoyette if(!fgets(buf, (int)sizeof(buf), in))
403 1.1.1.1.2.2 pgoyette break;
404 1.1.1.1.2.2 pgoyette }
405 1.1.1.1.2.2 pgoyette fclose(in);
406 1.1.1.1.2.2 pgoyette if(!content) {
407 1.1.1.1.2.2 pgoyette if(verb) printf("%s is empty\n", file);
408 1.1.1.1.2.2 pgoyette #ifndef S_SPLINT_S
409 1.1.1.1.2.2 pgoyette sk_X509_pop_free(sk, X509_free);
410 1.1.1.1.2.2 pgoyette #endif
411 1.1.1.1.2.2 pgoyette return NULL;
412 1.1.1.1.2.2 pgoyette }
413 1.1.1.1.2.2 pgoyette return sk;
414 1.1.1.1.2.2 pgoyette }
415 1.1.1.1.2.2 pgoyette
416 1.1.1.1.2.2 pgoyette /** read certificates from the builtin certificate */
417 1.1.1.1.2.2 pgoyette static STACK_OF(X509)*
418 1.1.1.1.2.2 pgoyette read_builtin_cert(void)
419 1.1.1.1.2.2 pgoyette {
420 1.1.1.1.2.2 pgoyette const char* builtin_cert = get_builtin_cert();
421 1.1.1.1.2.2 pgoyette STACK_OF(X509)* sk;
422 1.1.1.1.2.2 pgoyette BIO *bio = BIO_new_mem_buf((void*)builtin_cert,
423 1.1.1.1.2.2 pgoyette (int)strlen(builtin_cert));
424 1.1.1.1.2.2 pgoyette if(!bio) {
425 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
426 1.1.1.1.2.2 pgoyette exit(0);
427 1.1.1.1.2.2 pgoyette }
428 1.1.1.1.2.2 pgoyette sk = read_cert_bio(bio);
429 1.1.1.1.2.2 pgoyette if(!sk) {
430 1.1.1.1.2.2 pgoyette if(verb) printf("internal error, out of memory\n");
431 1.1.1.1.2.2 pgoyette exit(0);
432 1.1.1.1.2.2 pgoyette }
433 1.1.1.1.2.2 pgoyette BIO_free(bio);
434 1.1.1.1.2.2 pgoyette return sk;
435 1.1.1.1.2.2 pgoyette }
436 1.1.1.1.2.2 pgoyette
437 1.1.1.1.2.2 pgoyette /** read update cert file or use builtin */
438 1.1.1.1.2.2 pgoyette static STACK_OF(X509)*
439 1.1.1.1.2.2 pgoyette read_cert_or_builtin(const char* file)
440 1.1.1.1.2.2 pgoyette {
441 1.1.1.1.2.2 pgoyette STACK_OF(X509) *sk = read_cert_file(file);
442 1.1.1.1.2.2 pgoyette if(!sk) {
443 1.1.1.1.2.2 pgoyette if(verb) printf("using builtin certificate\n");
444 1.1.1.1.2.2 pgoyette sk = read_builtin_cert();
445 1.1.1.1.2.2 pgoyette }
446 1.1.1.1.2.2 pgoyette if(verb) printf("have %d trusted certificates\n", sk_X509_num(sk));
447 1.1.1.1.2.2 pgoyette verb_certs("trusted certificates", sk);
448 1.1.1.1.2.2 pgoyette return sk;
449 1.1.1.1.2.2 pgoyette }
450 1.1.1.1.2.2 pgoyette
451 1.1.1.1.2.2 pgoyette static void
452 1.1.1.1.2.2 pgoyette do_list_builtin(void)
453 1.1.1.1.2.2 pgoyette {
454 1.1.1.1.2.2 pgoyette const char* builtin_cert = get_builtin_cert();
455 1.1.1.1.2.2 pgoyette const char* builtin_ds = get_builtin_ds();
456 1.1.1.1.2.2 pgoyette printf("%s\n", builtin_ds);
457 1.1.1.1.2.2 pgoyette printf("%s\n", builtin_cert);
458 1.1.1.1.2.2 pgoyette exit(0);
459 1.1.1.1.2.2 pgoyette }
460 1.1.1.1.2.2 pgoyette
461 1.1.1.1.2.2 pgoyette /** printout IP address with message */
462 1.1.1.1.2.2 pgoyette static void
463 1.1.1.1.2.2 pgoyette verb_addr(const char* msg, struct ip_list* ip)
464 1.1.1.1.2.2 pgoyette {
465 1.1.1.1.2.2 pgoyette if(verb) {
466 1.1.1.1.2.2 pgoyette char out[100];
467 1.1.1.1.2.2 pgoyette void* a = &((struct sockaddr_in*)&ip->addr)->sin_addr;
468 1.1.1.1.2.2 pgoyette if(ip->len != (socklen_t)sizeof(struct sockaddr_in))
469 1.1.1.1.2.2 pgoyette a = &((struct sockaddr_in6*)&ip->addr)->sin6_addr;
470 1.1.1.1.2.2 pgoyette
471 1.1.1.1.2.2 pgoyette if(inet_ntop((int)((struct sockaddr_in*)&ip->addr)->sin_family,
472 1.1.1.1.2.2 pgoyette a, out, (socklen_t)sizeof(out))==0)
473 1.1.1.1.2.2 pgoyette printf("%s (inet_ntop error)\n", msg);
474 1.1.1.1.2.2 pgoyette else printf("%s %s\n", msg, out);
475 1.1.1.1.2.2 pgoyette }
476 1.1.1.1.2.2 pgoyette }
477 1.1.1.1.2.2 pgoyette
478 1.1.1.1.2.2 pgoyette /** free ip_list */
479 1.1.1.1.2.2 pgoyette static void
480 1.1.1.1.2.2 pgoyette ip_list_free(struct ip_list* p)
481 1.1.1.1.2.2 pgoyette {
482 1.1.1.1.2.2 pgoyette struct ip_list* np;
483 1.1.1.1.2.2 pgoyette while(p) {
484 1.1.1.1.2.2 pgoyette np = p->next;
485 1.1.1.1.2.2 pgoyette free(p);
486 1.1.1.1.2.2 pgoyette p = np;
487 1.1.1.1.2.2 pgoyette }
488 1.1.1.1.2.2 pgoyette }
489 1.1.1.1.2.2 pgoyette
490 1.1.1.1.2.2 pgoyette /** create ip_list entry for a RR record */
491 1.1.1.1.2.2 pgoyette static struct ip_list*
492 1.1.1.1.2.2 pgoyette RR_to_ip(int tp, char* data, int len, int port)
493 1.1.1.1.2.2 pgoyette {
494 1.1.1.1.2.2 pgoyette struct ip_list* ip = (struct ip_list*)calloc(1, sizeof(*ip));
495 1.1.1.1.2.2 pgoyette uint16_t p = (uint16_t)port;
496 1.1.1.1.2.2 pgoyette if(tp == LDNS_RR_TYPE_A) {
497 1.1.1.1.2.2 pgoyette struct sockaddr_in* sa = (struct sockaddr_in*)&ip->addr;
498 1.1.1.1.2.2 pgoyette ip->len = (socklen_t)sizeof(*sa);
499 1.1.1.1.2.2 pgoyette sa->sin_family = AF_INET;
500 1.1.1.1.2.2 pgoyette sa->sin_port = (in_port_t)htons(p);
501 1.1.1.1.2.2 pgoyette if(len != (int)sizeof(sa->sin_addr)) {
502 1.1.1.1.2.2 pgoyette if(verb) printf("skipped badly formatted A\n");
503 1.1.1.1.2.2 pgoyette free(ip);
504 1.1.1.1.2.2 pgoyette return NULL;
505 1.1.1.1.2.2 pgoyette }
506 1.1.1.1.2.2 pgoyette memmove(&sa->sin_addr, data, sizeof(sa->sin_addr));
507 1.1.1.1.2.2 pgoyette
508 1.1.1.1.2.2 pgoyette } else if(tp == LDNS_RR_TYPE_AAAA) {
509 1.1.1.1.2.2 pgoyette struct sockaddr_in6* sa = (struct sockaddr_in6*)&ip->addr;
510 1.1.1.1.2.2 pgoyette ip->len = (socklen_t)sizeof(*sa);
511 1.1.1.1.2.2 pgoyette sa->sin6_family = AF_INET6;
512 1.1.1.1.2.2 pgoyette sa->sin6_port = (in_port_t)htons(p);
513 1.1.1.1.2.2 pgoyette if(len != (int)sizeof(sa->sin6_addr)) {
514 1.1.1.1.2.2 pgoyette if(verb) printf("skipped badly formatted AAAA\n");
515 1.1.1.1.2.2 pgoyette free(ip);
516 1.1.1.1.2.2 pgoyette return NULL;
517 1.1.1.1.2.2 pgoyette }
518 1.1.1.1.2.2 pgoyette memmove(&sa->sin6_addr, data, sizeof(sa->sin6_addr));
519 1.1.1.1.2.2 pgoyette } else {
520 1.1.1.1.2.2 pgoyette if(verb) printf("internal error: bad type in RRtoip\n");
521 1.1.1.1.2.2 pgoyette free(ip);
522 1.1.1.1.2.2 pgoyette return NULL;
523 1.1.1.1.2.2 pgoyette }
524 1.1.1.1.2.2 pgoyette verb_addr("resolved server address", ip);
525 1.1.1.1.2.2 pgoyette return ip;
526 1.1.1.1.2.2 pgoyette }
527 1.1.1.1.2.2 pgoyette
528 1.1.1.1.2.2 pgoyette /** Resolve name, type, class and add addresses to iplist */
529 1.1.1.1.2.2 pgoyette static void
530 1.1.1.1.2.2 pgoyette resolve_host_ip(struct ub_ctx* ctx, const char* host, int port, int tp, int cl,
531 1.1.1.1.2.2 pgoyette struct ip_list** head)
532 1.1.1.1.2.2 pgoyette {
533 1.1.1.1.2.2 pgoyette struct ub_result* res = NULL;
534 1.1.1.1.2.2 pgoyette int r;
535 1.1.1.1.2.2 pgoyette int i;
536 1.1.1.1.2.2 pgoyette
537 1.1.1.1.2.2 pgoyette r = ub_resolve(ctx, host, tp, cl, &res);
538 1.1.1.1.2.2 pgoyette if(r) {
539 1.1.1.1.2.2 pgoyette if(verb) printf("error: resolve %s %s: %s\n", host,
540 1.1.1.1.2.2 pgoyette (tp==LDNS_RR_TYPE_A)?"A":"AAAA", ub_strerror(r));
541 1.1.1.1.2.2 pgoyette return;
542 1.1.1.1.2.2 pgoyette }
543 1.1.1.1.2.2 pgoyette if(!res) {
544 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
545 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
546 1.1.1.1.2.2 pgoyette exit(0);
547 1.1.1.1.2.2 pgoyette }
548 1.1.1.1.2.2 pgoyette if(!res->havedata || res->rcode || !res->data) {
549 1.1.1.1.2.2 pgoyette if(verb) printf("resolve %s %s: no result\n", host,
550 1.1.1.1.2.2 pgoyette (tp==LDNS_RR_TYPE_A)?"A":"AAAA");
551 1.1.1.1.2.2 pgoyette return;
552 1.1.1.1.2.2 pgoyette }
553 1.1.1.1.2.2 pgoyette for(i = 0; res->data[i]; i++) {
554 1.1.1.1.2.2 pgoyette struct ip_list* ip = RR_to_ip(tp, res->data[i], res->len[i],
555 1.1.1.1.2.2 pgoyette port);
556 1.1.1.1.2.2 pgoyette if(!ip) continue;
557 1.1.1.1.2.2 pgoyette ip->next = *head;
558 1.1.1.1.2.2 pgoyette *head = ip;
559 1.1.1.1.2.2 pgoyette }
560 1.1.1.1.2.2 pgoyette ub_resolve_free(res);
561 1.1.1.1.2.2 pgoyette }
562 1.1.1.1.2.2 pgoyette
563 1.1.1.1.2.2 pgoyette /** parse a text IP address into a sockaddr */
564 1.1.1.1.2.2 pgoyette static struct ip_list*
565 1.1.1.1.2.2 pgoyette parse_ip_addr(const char* str, int port)
566 1.1.1.1.2.2 pgoyette {
567 1.1.1.1.2.2 pgoyette socklen_t len = 0;
568 1.1.1.1.2.2 pgoyette union {
569 1.1.1.1.2.2 pgoyette struct sockaddr_in6 a6;
570 1.1.1.1.2.2 pgoyette struct sockaddr_in a;
571 1.1.1.1.2.2 pgoyette } addr;
572 1.1.1.1.2.2 pgoyette struct ip_list* ip;
573 1.1.1.1.2.2 pgoyette uint16_t p = (uint16_t)port;
574 1.1.1.1.2.2 pgoyette memset(&addr, 0, sizeof(addr));
575 1.1.1.1.2.2 pgoyette
576 1.1.1.1.2.2 pgoyette if(inet_pton(AF_INET6, str, &addr.a6.sin6_addr) > 0) {
577 1.1.1.1.2.2 pgoyette /* it is an IPv6 */
578 1.1.1.1.2.2 pgoyette addr.a6.sin6_family = AF_INET6;
579 1.1.1.1.2.2 pgoyette addr.a6.sin6_port = (in_port_t)htons(p);
580 1.1.1.1.2.2 pgoyette len = (socklen_t)sizeof(addr.a6);
581 1.1.1.1.2.2 pgoyette }
582 1.1.1.1.2.2 pgoyette if(inet_pton(AF_INET, str, &addr.a.sin_addr) > 0) {
583 1.1.1.1.2.2 pgoyette /* it is an IPv4 */
584 1.1.1.1.2.2 pgoyette addr.a.sin_family = AF_INET;
585 1.1.1.1.2.2 pgoyette addr.a.sin_port = (in_port_t)htons(p);
586 1.1.1.1.2.2 pgoyette len = (socklen_t)sizeof(struct sockaddr_in);
587 1.1.1.1.2.2 pgoyette }
588 1.1.1.1.2.2 pgoyette if(!len) return NULL;
589 1.1.1.1.2.2 pgoyette ip = (struct ip_list*)calloc(1, sizeof(*ip));
590 1.1.1.1.2.2 pgoyette if(!ip) {
591 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
592 1.1.1.1.2.2 pgoyette exit(0);
593 1.1.1.1.2.2 pgoyette }
594 1.1.1.1.2.2 pgoyette ip->len = len;
595 1.1.1.1.2.2 pgoyette memmove(&ip->addr, &addr, len);
596 1.1.1.1.2.2 pgoyette if(verb) printf("server address is %s\n", str);
597 1.1.1.1.2.2 pgoyette return ip;
598 1.1.1.1.2.2 pgoyette }
599 1.1.1.1.2.2 pgoyette
600 1.1.1.1.2.2 pgoyette /**
601 1.1.1.1.2.2 pgoyette * Resolve a domain name (even though the resolver is down and there is
602 1.1.1.1.2.2 pgoyette * no trust anchor). Without DNSSEC validation.
603 1.1.1.1.2.2 pgoyette * @param host: the name to resolve.
604 1.1.1.1.2.2 pgoyette * If this name is an IP4 or IP6 address this address is returned.
605 1.1.1.1.2.2 pgoyette * @param port: the port number used for the returned IP structs.
606 1.1.1.1.2.2 pgoyette * @param res_conf: resolv.conf (if any).
607 1.1.1.1.2.2 pgoyette * @param root_hints: root hints (if any).
608 1.1.1.1.2.2 pgoyette * @param debugconf: unbound.conf for debugging options.
609 1.1.1.1.2.2 pgoyette * @param ip4only: use only ip4 for resolve and only lookup A
610 1.1.1.1.2.2 pgoyette * @param ip6only: use only ip6 for resolve and only lookup AAAA
611 1.1.1.1.2.2 pgoyette * default is to lookup A and AAAA using ip4 and ip6.
612 1.1.1.1.2.2 pgoyette * @return list of IP addresses.
613 1.1.1.1.2.2 pgoyette */
614 1.1.1.1.2.2 pgoyette static struct ip_list*
615 1.1.1.1.2.2 pgoyette resolve_name(const char* host, int port, const char* res_conf,
616 1.1.1.1.2.2 pgoyette const char* root_hints, const char* debugconf, int ip4only, int ip6only)
617 1.1.1.1.2.2 pgoyette {
618 1.1.1.1.2.2 pgoyette struct ub_ctx* ctx;
619 1.1.1.1.2.2 pgoyette struct ip_list* list = NULL;
620 1.1.1.1.2.2 pgoyette /* first see if name is an IP address itself */
621 1.1.1.1.2.2 pgoyette if( (list=parse_ip_addr(host, port)) ) {
622 1.1.1.1.2.2 pgoyette return list;
623 1.1.1.1.2.2 pgoyette }
624 1.1.1.1.2.2 pgoyette
625 1.1.1.1.2.2 pgoyette /* create resolver context */
626 1.1.1.1.2.2 pgoyette ctx = create_unbound_context(res_conf, root_hints, debugconf,
627 1.1.1.1.2.2 pgoyette ip4only, ip6only);
628 1.1.1.1.2.2 pgoyette
629 1.1.1.1.2.2 pgoyette /* try resolution of A */
630 1.1.1.1.2.2 pgoyette if(!ip6only) {
631 1.1.1.1.2.2 pgoyette resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_A,
632 1.1.1.1.2.2 pgoyette LDNS_RR_CLASS_IN, &list);
633 1.1.1.1.2.2 pgoyette }
634 1.1.1.1.2.2 pgoyette
635 1.1.1.1.2.2 pgoyette /* try resolution of AAAA */
636 1.1.1.1.2.2 pgoyette if(!ip4only) {
637 1.1.1.1.2.2 pgoyette resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_AAAA,
638 1.1.1.1.2.2 pgoyette LDNS_RR_CLASS_IN, &list);
639 1.1.1.1.2.2 pgoyette }
640 1.1.1.1.2.2 pgoyette
641 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
642 1.1.1.1.2.2 pgoyette if(!list) {
643 1.1.1.1.2.2 pgoyette if(verb) printf("%s has no IP addresses I can use\n", host);
644 1.1.1.1.2.2 pgoyette exit(0);
645 1.1.1.1.2.2 pgoyette }
646 1.1.1.1.2.2 pgoyette return list;
647 1.1.1.1.2.2 pgoyette }
648 1.1.1.1.2.2 pgoyette
649 1.1.1.1.2.2 pgoyette /** clear used flags */
650 1.1.1.1.2.2 pgoyette static void
651 1.1.1.1.2.2 pgoyette wipe_ip_usage(struct ip_list* p)
652 1.1.1.1.2.2 pgoyette {
653 1.1.1.1.2.2 pgoyette while(p) {
654 1.1.1.1.2.2 pgoyette p->used = 0;
655 1.1.1.1.2.2 pgoyette p = p->next;
656 1.1.1.1.2.2 pgoyette }
657 1.1.1.1.2.2 pgoyette }
658 1.1.1.1.2.2 pgoyette
659 1.1.1.1.2.2 pgoyette /** cound unused IPs */
660 1.1.1.1.2.2 pgoyette static int
661 1.1.1.1.2.2 pgoyette count_unused(struct ip_list* p)
662 1.1.1.1.2.2 pgoyette {
663 1.1.1.1.2.2 pgoyette int num = 0;
664 1.1.1.1.2.2 pgoyette while(p) {
665 1.1.1.1.2.2 pgoyette if(!p->used) num++;
666 1.1.1.1.2.2 pgoyette p = p->next;
667 1.1.1.1.2.2 pgoyette }
668 1.1.1.1.2.2 pgoyette return num;
669 1.1.1.1.2.2 pgoyette }
670 1.1.1.1.2.2 pgoyette
671 1.1.1.1.2.2 pgoyette /** pick random unused element from IP list */
672 1.1.1.1.2.2 pgoyette static struct ip_list*
673 1.1.1.1.2.2 pgoyette pick_random_ip(struct ip_list* list)
674 1.1.1.1.2.2 pgoyette {
675 1.1.1.1.2.2 pgoyette struct ip_list* p = list;
676 1.1.1.1.2.2 pgoyette int num = count_unused(list);
677 1.1.1.1.2.2 pgoyette int sel;
678 1.1.1.1.2.2 pgoyette if(num == 0) return NULL;
679 1.1.1.1.2.2 pgoyette /* not perfect, but random enough */
680 1.1.1.1.2.2 pgoyette sel = (int)arc4random_uniform((uint32_t)num);
681 1.1.1.1.2.2 pgoyette /* skip over unused elements that we did not select */
682 1.1.1.1.2.2 pgoyette while(sel > 0 && p) {
683 1.1.1.1.2.2 pgoyette if(!p->used) sel--;
684 1.1.1.1.2.2 pgoyette p = p->next;
685 1.1.1.1.2.2 pgoyette }
686 1.1.1.1.2.2 pgoyette /* find the next unused element */
687 1.1.1.1.2.2 pgoyette while(p && p->used)
688 1.1.1.1.2.2 pgoyette p = p->next;
689 1.1.1.1.2.2 pgoyette if(!p) return NULL; /* robustness */
690 1.1.1.1.2.2 pgoyette return p;
691 1.1.1.1.2.2 pgoyette }
692 1.1.1.1.2.2 pgoyette
693 1.1.1.1.2.2 pgoyette /** close the fd */
694 1.1.1.1.2.2 pgoyette static void
695 1.1.1.1.2.2 pgoyette fd_close(int fd)
696 1.1.1.1.2.2 pgoyette {
697 1.1.1.1.2.2 pgoyette #ifndef USE_WINSOCK
698 1.1.1.1.2.2 pgoyette close(fd);
699 1.1.1.1.2.2 pgoyette #else
700 1.1.1.1.2.2 pgoyette closesocket(fd);
701 1.1.1.1.2.2 pgoyette #endif
702 1.1.1.1.2.2 pgoyette }
703 1.1.1.1.2.2 pgoyette
704 1.1.1.1.2.2 pgoyette /** printout socket errno */
705 1.1.1.1.2.2 pgoyette static void
706 1.1.1.1.2.2 pgoyette print_sock_err(const char* msg)
707 1.1.1.1.2.2 pgoyette {
708 1.1.1.1.2.2 pgoyette #ifndef USE_WINSOCK
709 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", msg, strerror(errno));
710 1.1.1.1.2.2 pgoyette #else
711 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", msg, wsa_strerror(WSAGetLastError()));
712 1.1.1.1.2.2 pgoyette #endif
713 1.1.1.1.2.2 pgoyette }
714 1.1.1.1.2.2 pgoyette
715 1.1.1.1.2.2 pgoyette /** connect to IP address */
716 1.1.1.1.2.2 pgoyette static int
717 1.1.1.1.2.2 pgoyette connect_to_ip(struct ip_list* ip)
718 1.1.1.1.2.2 pgoyette {
719 1.1.1.1.2.2 pgoyette int fd;
720 1.1.1.1.2.2 pgoyette verb_addr("connect to", ip);
721 1.1.1.1.2.2 pgoyette fd = socket(ip->len==(socklen_t)sizeof(struct sockaddr_in)?
722 1.1.1.1.2.2 pgoyette AF_INET:AF_INET6, SOCK_STREAM, 0);
723 1.1.1.1.2.2 pgoyette if(fd == -1) {
724 1.1.1.1.2.2 pgoyette print_sock_err("socket");
725 1.1.1.1.2.2 pgoyette return -1;
726 1.1.1.1.2.2 pgoyette }
727 1.1.1.1.2.2 pgoyette if(connect(fd, (struct sockaddr*)&ip->addr, ip->len) < 0) {
728 1.1.1.1.2.2 pgoyette print_sock_err("connect");
729 1.1.1.1.2.2 pgoyette fd_close(fd);
730 1.1.1.1.2.2 pgoyette return -1;
731 1.1.1.1.2.2 pgoyette }
732 1.1.1.1.2.2 pgoyette return fd;
733 1.1.1.1.2.2 pgoyette }
734 1.1.1.1.2.2 pgoyette
735 1.1.1.1.2.2 pgoyette /** create SSL context */
736 1.1.1.1.2.2 pgoyette static SSL_CTX*
737 1.1.1.1.2.2 pgoyette setup_sslctx(void)
738 1.1.1.1.2.2 pgoyette {
739 1.1.1.1.2.2 pgoyette SSL_CTX* sslctx = SSL_CTX_new(SSLv23_client_method());
740 1.1.1.1.2.2 pgoyette if(!sslctx) {
741 1.1.1.1.2.2 pgoyette if(verb) printf("SSL_CTX_new error\n");
742 1.1.1.1.2.2 pgoyette return NULL;
743 1.1.1.1.2.2 pgoyette }
744 1.1.1.1.2.2 pgoyette return sslctx;
745 1.1.1.1.2.2 pgoyette }
746 1.1.1.1.2.2 pgoyette
747 1.1.1.1.2.2 pgoyette /** initiate TLS on a connection */
748 1.1.1.1.2.2 pgoyette static SSL*
749 1.1.1.1.2.2 pgoyette TLS_initiate(SSL_CTX* sslctx, int fd)
750 1.1.1.1.2.2 pgoyette {
751 1.1.1.1.2.2 pgoyette X509* x;
752 1.1.1.1.2.2 pgoyette int r;
753 1.1.1.1.2.2 pgoyette SSL* ssl = SSL_new(sslctx);
754 1.1.1.1.2.2 pgoyette if(!ssl) {
755 1.1.1.1.2.2 pgoyette if(verb) printf("SSL_new error\n");
756 1.1.1.1.2.2 pgoyette return NULL;
757 1.1.1.1.2.2 pgoyette }
758 1.1.1.1.2.2 pgoyette SSL_set_connect_state(ssl);
759 1.1.1.1.2.2 pgoyette (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
760 1.1.1.1.2.2 pgoyette if(!SSL_set_fd(ssl, fd)) {
761 1.1.1.1.2.2 pgoyette if(verb) printf("SSL_set_fd error\n");
762 1.1.1.1.2.2 pgoyette SSL_free(ssl);
763 1.1.1.1.2.2 pgoyette return NULL;
764 1.1.1.1.2.2 pgoyette }
765 1.1.1.1.2.2 pgoyette while(1) {
766 1.1.1.1.2.2 pgoyette ERR_clear_error();
767 1.1.1.1.2.2 pgoyette if( (r=SSL_do_handshake(ssl)) == 1)
768 1.1.1.1.2.2 pgoyette break;
769 1.1.1.1.2.2 pgoyette r = SSL_get_error(ssl, r);
770 1.1.1.1.2.2 pgoyette if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) {
771 1.1.1.1.2.2 pgoyette if(verb) printf("SSL handshake failed\n");
772 1.1.1.1.2.2 pgoyette SSL_free(ssl);
773 1.1.1.1.2.2 pgoyette return NULL;
774 1.1.1.1.2.2 pgoyette }
775 1.1.1.1.2.2 pgoyette /* wants to be called again */
776 1.1.1.1.2.2 pgoyette }
777 1.1.1.1.2.2 pgoyette x = SSL_get_peer_certificate(ssl);
778 1.1.1.1.2.2 pgoyette if(!x) {
779 1.1.1.1.2.2 pgoyette if(verb) printf("Server presented no peer certificate\n");
780 1.1.1.1.2.2 pgoyette SSL_free(ssl);
781 1.1.1.1.2.2 pgoyette return NULL;
782 1.1.1.1.2.2 pgoyette }
783 1.1.1.1.2.2 pgoyette verb_cert("server SSL certificate", x);
784 1.1.1.1.2.2 pgoyette X509_free(x);
785 1.1.1.1.2.2 pgoyette return ssl;
786 1.1.1.1.2.2 pgoyette }
787 1.1.1.1.2.2 pgoyette
788 1.1.1.1.2.2 pgoyette /** perform neat TLS shutdown */
789 1.1.1.1.2.2 pgoyette static void
790 1.1.1.1.2.2 pgoyette TLS_shutdown(int fd, SSL* ssl, SSL_CTX* sslctx)
791 1.1.1.1.2.2 pgoyette {
792 1.1.1.1.2.2 pgoyette /* shutdown the SSL connection nicely */
793 1.1.1.1.2.2 pgoyette if(SSL_shutdown(ssl) == 0) {
794 1.1.1.1.2.2 pgoyette SSL_shutdown(ssl);
795 1.1.1.1.2.2 pgoyette }
796 1.1.1.1.2.2 pgoyette SSL_free(ssl);
797 1.1.1.1.2.2 pgoyette SSL_CTX_free(sslctx);
798 1.1.1.1.2.2 pgoyette fd_close(fd);
799 1.1.1.1.2.2 pgoyette }
800 1.1.1.1.2.2 pgoyette
801 1.1.1.1.2.2 pgoyette /** write a line over SSL */
802 1.1.1.1.2.2 pgoyette static int
803 1.1.1.1.2.2 pgoyette write_ssl_line(SSL* ssl, const char* str, const char* sec)
804 1.1.1.1.2.2 pgoyette {
805 1.1.1.1.2.2 pgoyette char buf[1024];
806 1.1.1.1.2.2 pgoyette size_t l;
807 1.1.1.1.2.2 pgoyette if(sec) {
808 1.1.1.1.2.2 pgoyette snprintf(buf, sizeof(buf), str, sec);
809 1.1.1.1.2.2 pgoyette } else {
810 1.1.1.1.2.2 pgoyette snprintf(buf, sizeof(buf), "%s", str);
811 1.1.1.1.2.2 pgoyette }
812 1.1.1.1.2.2 pgoyette l = strlen(buf);
813 1.1.1.1.2.2 pgoyette if(l+2 >= sizeof(buf)) {
814 1.1.1.1.2.2 pgoyette if(verb) printf("line too long\n");
815 1.1.1.1.2.2 pgoyette return 0;
816 1.1.1.1.2.2 pgoyette }
817 1.1.1.1.2.2 pgoyette if(verb >= 2) printf("SSL_write: %s\n", buf);
818 1.1.1.1.2.2 pgoyette buf[l] = '\r';
819 1.1.1.1.2.2 pgoyette buf[l+1] = '\n';
820 1.1.1.1.2.2 pgoyette buf[l+2] = 0;
821 1.1.1.1.2.2 pgoyette /* add \r\n */
822 1.1.1.1.2.2 pgoyette if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) {
823 1.1.1.1.2.2 pgoyette if(verb) printf("could not SSL_write %s", str);
824 1.1.1.1.2.2 pgoyette return 0;
825 1.1.1.1.2.2 pgoyette }
826 1.1.1.1.2.2 pgoyette return 1;
827 1.1.1.1.2.2 pgoyette }
828 1.1.1.1.2.2 pgoyette
829 1.1.1.1.2.2 pgoyette /** process header line, check rcode and keeping track of size */
830 1.1.1.1.2.2 pgoyette static int
831 1.1.1.1.2.2 pgoyette process_one_header(char* buf, size_t* clen, int* chunked)
832 1.1.1.1.2.2 pgoyette {
833 1.1.1.1.2.2 pgoyette if(verb>=2) printf("header: '%s'\n", buf);
834 1.1.1.1.2.2 pgoyette if(strncasecmp(buf, "HTTP/1.1 ", 9) == 0) {
835 1.1.1.1.2.2 pgoyette /* check returncode */
836 1.1.1.1.2.2 pgoyette if(buf[9] != '2') {
837 1.1.1.1.2.2 pgoyette if(verb) printf("bad status %s\n", buf+9);
838 1.1.1.1.2.2 pgoyette return 0;
839 1.1.1.1.2.2 pgoyette }
840 1.1.1.1.2.2 pgoyette } else if(strncasecmp(buf, "Content-Length: ", 16) == 0) {
841 1.1.1.1.2.2 pgoyette if(!*chunked)
842 1.1.1.1.2.2 pgoyette *clen = (size_t)atoi(buf+16);
843 1.1.1.1.2.2 pgoyette } else if(strncasecmp(buf, "Transfer-Encoding: chunked", 19+7) == 0) {
844 1.1.1.1.2.2 pgoyette *clen = 0;
845 1.1.1.1.2.2 pgoyette *chunked = 1;
846 1.1.1.1.2.2 pgoyette }
847 1.1.1.1.2.2 pgoyette return 1;
848 1.1.1.1.2.2 pgoyette }
849 1.1.1.1.2.2 pgoyette
850 1.1.1.1.2.2 pgoyette /**
851 1.1.1.1.2.2 pgoyette * Read one line from SSL
852 1.1.1.1.2.2 pgoyette * zero terminates.
853 1.1.1.1.2.2 pgoyette * skips "\r\n" (but not copied to buf).
854 1.1.1.1.2.2 pgoyette * @param ssl: the SSL connection to read from (blocking).
855 1.1.1.1.2.2 pgoyette * @param buf: buffer to return line in.
856 1.1.1.1.2.2 pgoyette * @param len: size of the buffer.
857 1.1.1.1.2.2 pgoyette * @return 0 on error, 1 on success.
858 1.1.1.1.2.2 pgoyette */
859 1.1.1.1.2.2 pgoyette static int
860 1.1.1.1.2.2 pgoyette read_ssl_line(SSL* ssl, char* buf, size_t len)
861 1.1.1.1.2.2 pgoyette {
862 1.1.1.1.2.2 pgoyette size_t n = 0;
863 1.1.1.1.2.2 pgoyette int r;
864 1.1.1.1.2.2 pgoyette int endnl = 0;
865 1.1.1.1.2.2 pgoyette while(1) {
866 1.1.1.1.2.2 pgoyette if(n >= len) {
867 1.1.1.1.2.2 pgoyette if(verb) printf("line too long\n");
868 1.1.1.1.2.2 pgoyette return 0;
869 1.1.1.1.2.2 pgoyette }
870 1.1.1.1.2.2 pgoyette if((r = SSL_read(ssl, buf+n, 1)) <= 0) {
871 1.1.1.1.2.2 pgoyette if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
872 1.1.1.1.2.2 pgoyette /* EOF */
873 1.1.1.1.2.2 pgoyette break;
874 1.1.1.1.2.2 pgoyette }
875 1.1.1.1.2.2 pgoyette if(verb) printf("could not SSL_read\n");
876 1.1.1.1.2.2 pgoyette return 0;
877 1.1.1.1.2.2 pgoyette }
878 1.1.1.1.2.2 pgoyette if(endnl && buf[n] == '\n') {
879 1.1.1.1.2.2 pgoyette break;
880 1.1.1.1.2.2 pgoyette } else if(endnl) {
881 1.1.1.1.2.2 pgoyette /* bad data */
882 1.1.1.1.2.2 pgoyette if(verb) printf("error: stray linefeeds\n");
883 1.1.1.1.2.2 pgoyette return 0;
884 1.1.1.1.2.2 pgoyette } else if(buf[n] == '\r') {
885 1.1.1.1.2.2 pgoyette /* skip \r, and also \n on the wire */
886 1.1.1.1.2.2 pgoyette endnl = 1;
887 1.1.1.1.2.2 pgoyette continue;
888 1.1.1.1.2.2 pgoyette } else if(buf[n] == '\n') {
889 1.1.1.1.2.2 pgoyette /* skip the \n, we are done */
890 1.1.1.1.2.2 pgoyette break;
891 1.1.1.1.2.2 pgoyette } else n++;
892 1.1.1.1.2.2 pgoyette }
893 1.1.1.1.2.2 pgoyette buf[n] = 0;
894 1.1.1.1.2.2 pgoyette return 1;
895 1.1.1.1.2.2 pgoyette }
896 1.1.1.1.2.2 pgoyette
897 1.1.1.1.2.2 pgoyette /** read http headers and process them */
898 1.1.1.1.2.2 pgoyette static size_t
899 1.1.1.1.2.2 pgoyette read_http_headers(SSL* ssl, size_t* clen)
900 1.1.1.1.2.2 pgoyette {
901 1.1.1.1.2.2 pgoyette char buf[1024];
902 1.1.1.1.2.2 pgoyette int chunked = 0;
903 1.1.1.1.2.2 pgoyette *clen = 0;
904 1.1.1.1.2.2 pgoyette while(read_ssl_line(ssl, buf, sizeof(buf))) {
905 1.1.1.1.2.2 pgoyette if(buf[0] == 0)
906 1.1.1.1.2.2 pgoyette return 1;
907 1.1.1.1.2.2 pgoyette if(!process_one_header(buf, clen, &chunked))
908 1.1.1.1.2.2 pgoyette return 0;
909 1.1.1.1.2.2 pgoyette }
910 1.1.1.1.2.2 pgoyette return 0;
911 1.1.1.1.2.2 pgoyette }
912 1.1.1.1.2.2 pgoyette
913 1.1.1.1.2.2 pgoyette /** read a data chunk */
914 1.1.1.1.2.2 pgoyette static char*
915 1.1.1.1.2.2 pgoyette read_data_chunk(SSL* ssl, size_t len)
916 1.1.1.1.2.2 pgoyette {
917 1.1.1.1.2.2 pgoyette size_t got = 0;
918 1.1.1.1.2.2 pgoyette int r;
919 1.1.1.1.2.2 pgoyette char* data;
920 1.1.1.1.2.2 pgoyette if(len >= 0xfffffff0)
921 1.1.1.1.2.2 pgoyette return NULL; /* to protect against integer overflow in malloc*/
922 1.1.1.1.2.2 pgoyette data = malloc(len+1);
923 1.1.1.1.2.2 pgoyette if(!data) {
924 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
925 1.1.1.1.2.2 pgoyette return NULL;
926 1.1.1.1.2.2 pgoyette }
927 1.1.1.1.2.2 pgoyette while(got < len) {
928 1.1.1.1.2.2 pgoyette if((r = SSL_read(ssl, data+got, (int)(len-got))) <= 0) {
929 1.1.1.1.2.2 pgoyette if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
930 1.1.1.1.2.2 pgoyette /* EOF */
931 1.1.1.1.2.2 pgoyette if(verb) printf("could not SSL_read: unexpected EOF\n");
932 1.1.1.1.2.2 pgoyette free(data);
933 1.1.1.1.2.2 pgoyette return NULL;
934 1.1.1.1.2.2 pgoyette }
935 1.1.1.1.2.2 pgoyette if(verb) printf("could not SSL_read\n");
936 1.1.1.1.2.2 pgoyette free(data);
937 1.1.1.1.2.2 pgoyette return NULL;
938 1.1.1.1.2.2 pgoyette }
939 1.1.1.1.2.2 pgoyette if(verb >= 2) printf("at %d/%d\n", (int)got, (int)len);
940 1.1.1.1.2.2 pgoyette got += r;
941 1.1.1.1.2.2 pgoyette }
942 1.1.1.1.2.2 pgoyette if(verb>=2) printf("read %d data\n", (int)len);
943 1.1.1.1.2.2 pgoyette data[len] = 0;
944 1.1.1.1.2.2 pgoyette return data;
945 1.1.1.1.2.2 pgoyette }
946 1.1.1.1.2.2 pgoyette
947 1.1.1.1.2.2 pgoyette /** parse chunk header */
948 1.1.1.1.2.2 pgoyette static int
949 1.1.1.1.2.2 pgoyette parse_chunk_header(char* buf, size_t* result)
950 1.1.1.1.2.2 pgoyette {
951 1.1.1.1.2.2 pgoyette char* e = NULL;
952 1.1.1.1.2.2 pgoyette size_t v = (size_t)strtol(buf, &e, 16);
953 1.1.1.1.2.2 pgoyette if(e == buf)
954 1.1.1.1.2.2 pgoyette return 0;
955 1.1.1.1.2.2 pgoyette *result = v;
956 1.1.1.1.2.2 pgoyette return 1;
957 1.1.1.1.2.2 pgoyette }
958 1.1.1.1.2.2 pgoyette
959 1.1.1.1.2.2 pgoyette /** read chunked data from connection */
960 1.1.1.1.2.2 pgoyette static BIO*
961 1.1.1.1.2.2 pgoyette do_chunked_read(SSL* ssl)
962 1.1.1.1.2.2 pgoyette {
963 1.1.1.1.2.2 pgoyette char buf[1024];
964 1.1.1.1.2.2 pgoyette size_t len;
965 1.1.1.1.2.2 pgoyette char* body;
966 1.1.1.1.2.2 pgoyette BIO* mem = BIO_new(BIO_s_mem());
967 1.1.1.1.2.2 pgoyette if(verb>=3) printf("do_chunked_read\n");
968 1.1.1.1.2.2 pgoyette if(!mem) {
969 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
970 1.1.1.1.2.2 pgoyette return NULL;
971 1.1.1.1.2.2 pgoyette }
972 1.1.1.1.2.2 pgoyette while(read_ssl_line(ssl, buf, sizeof(buf))) {
973 1.1.1.1.2.2 pgoyette /* read the chunked start line */
974 1.1.1.1.2.2 pgoyette if(verb>=2) printf("chunk header: %s\n", buf);
975 1.1.1.1.2.2 pgoyette if(!parse_chunk_header(buf, &len)) {
976 1.1.1.1.2.2 pgoyette BIO_free(mem);
977 1.1.1.1.2.2 pgoyette if(verb>=3) printf("could not parse chunk header\n");
978 1.1.1.1.2.2 pgoyette return NULL;
979 1.1.1.1.2.2 pgoyette }
980 1.1.1.1.2.2 pgoyette if(verb>=2) printf("chunk len: %d\n", (int)len);
981 1.1.1.1.2.2 pgoyette /* are we done? */
982 1.1.1.1.2.2 pgoyette if(len == 0) {
983 1.1.1.1.2.2 pgoyette char z = 0;
984 1.1.1.1.2.2 pgoyette /* skip end-of-chunk-trailer lines,
985 1.1.1.1.2.2 pgoyette * until the empty line after that */
986 1.1.1.1.2.2 pgoyette do {
987 1.1.1.1.2.2 pgoyette if(!read_ssl_line(ssl, buf, sizeof(buf))) {
988 1.1.1.1.2.2 pgoyette BIO_free(mem);
989 1.1.1.1.2.2 pgoyette return NULL;
990 1.1.1.1.2.2 pgoyette }
991 1.1.1.1.2.2 pgoyette } while (strlen(buf) > 0);
992 1.1.1.1.2.2 pgoyette /* end of chunks, zero terminate it */
993 1.1.1.1.2.2 pgoyette if(BIO_write(mem, &z, 1) <= 0) {
994 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
995 1.1.1.1.2.2 pgoyette BIO_free(mem);
996 1.1.1.1.2.2 pgoyette return NULL;
997 1.1.1.1.2.2 pgoyette }
998 1.1.1.1.2.2 pgoyette return mem;
999 1.1.1.1.2.2 pgoyette }
1000 1.1.1.1.2.2 pgoyette /* read the chunked body */
1001 1.1.1.1.2.2 pgoyette body = read_data_chunk(ssl, len);
1002 1.1.1.1.2.2 pgoyette if(!body) {
1003 1.1.1.1.2.2 pgoyette BIO_free(mem);
1004 1.1.1.1.2.2 pgoyette return NULL;
1005 1.1.1.1.2.2 pgoyette }
1006 1.1.1.1.2.2 pgoyette if(BIO_write(mem, body, (int)len) <= 0) {
1007 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1008 1.1.1.1.2.2 pgoyette free(body);
1009 1.1.1.1.2.2 pgoyette BIO_free(mem);
1010 1.1.1.1.2.2 pgoyette return NULL;
1011 1.1.1.1.2.2 pgoyette }
1012 1.1.1.1.2.2 pgoyette free(body);
1013 1.1.1.1.2.2 pgoyette /* skip empty line after data chunk */
1014 1.1.1.1.2.2 pgoyette if(!read_ssl_line(ssl, buf, sizeof(buf))) {
1015 1.1.1.1.2.2 pgoyette BIO_free(mem);
1016 1.1.1.1.2.2 pgoyette return NULL;
1017 1.1.1.1.2.2 pgoyette }
1018 1.1.1.1.2.2 pgoyette }
1019 1.1.1.1.2.2 pgoyette BIO_free(mem);
1020 1.1.1.1.2.2 pgoyette return NULL;
1021 1.1.1.1.2.2 pgoyette }
1022 1.1.1.1.2.2 pgoyette
1023 1.1.1.1.2.2 pgoyette /** start HTTP1.1 transaction on SSL */
1024 1.1.1.1.2.2 pgoyette static int
1025 1.1.1.1.2.2 pgoyette write_http_get(SSL* ssl, const char* pathname, const char* urlname)
1026 1.1.1.1.2.2 pgoyette {
1027 1.1.1.1.2.2 pgoyette if(write_ssl_line(ssl, "GET /%s HTTP/1.1", pathname) &&
1028 1.1.1.1.2.2 pgoyette write_ssl_line(ssl, "Host: %s", urlname) &&
1029 1.1.1.1.2.2 pgoyette write_ssl_line(ssl, "User-Agent: unbound-anchor/%s",
1030 1.1.1.1.2.2 pgoyette PACKAGE_VERSION) &&
1031 1.1.1.1.2.2 pgoyette /* We do not really do multiple queries per connection,
1032 1.1.1.1.2.2 pgoyette * but this header setting is also not needed.
1033 1.1.1.1.2.2 pgoyette * write_ssl_line(ssl, "Connection: close", NULL) &&*/
1034 1.1.1.1.2.2 pgoyette write_ssl_line(ssl, "", NULL)) {
1035 1.1.1.1.2.2 pgoyette return 1;
1036 1.1.1.1.2.2 pgoyette }
1037 1.1.1.1.2.2 pgoyette return 0;
1038 1.1.1.1.2.2 pgoyette }
1039 1.1.1.1.2.2 pgoyette
1040 1.1.1.1.2.2 pgoyette /** read chunked data and zero terminate; len is without zero */
1041 1.1.1.1.2.2 pgoyette static char*
1042 1.1.1.1.2.2 pgoyette read_chunked_zero_terminate(SSL* ssl, size_t* len)
1043 1.1.1.1.2.2 pgoyette {
1044 1.1.1.1.2.2 pgoyette /* do the chunked version */
1045 1.1.1.1.2.2 pgoyette BIO* tmp = do_chunked_read(ssl);
1046 1.1.1.1.2.2 pgoyette char* data, *d = NULL;
1047 1.1.1.1.2.2 pgoyette size_t l;
1048 1.1.1.1.2.2 pgoyette if(!tmp) {
1049 1.1.1.1.2.2 pgoyette if(verb) printf("could not read from https\n");
1050 1.1.1.1.2.2 pgoyette return NULL;
1051 1.1.1.1.2.2 pgoyette }
1052 1.1.1.1.2.2 pgoyette l = (size_t)BIO_get_mem_data(tmp, &d);
1053 1.1.1.1.2.2 pgoyette if(verb>=2) printf("chunked data is %d\n", (int)l);
1054 1.1.1.1.2.2 pgoyette if(l == 0 || d == NULL) {
1055 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1056 1.1.1.1.2.2 pgoyette return NULL;
1057 1.1.1.1.2.2 pgoyette }
1058 1.1.1.1.2.2 pgoyette *len = l-1;
1059 1.1.1.1.2.2 pgoyette data = (char*)malloc(l);
1060 1.1.1.1.2.2 pgoyette if(data == NULL) {
1061 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1062 1.1.1.1.2.2 pgoyette return NULL;
1063 1.1.1.1.2.2 pgoyette }
1064 1.1.1.1.2.2 pgoyette memcpy(data, d, l);
1065 1.1.1.1.2.2 pgoyette BIO_free(tmp);
1066 1.1.1.1.2.2 pgoyette return data;
1067 1.1.1.1.2.2 pgoyette }
1068 1.1.1.1.2.2 pgoyette
1069 1.1.1.1.2.2 pgoyette /** read HTTP result from SSL */
1070 1.1.1.1.2.2 pgoyette static BIO*
1071 1.1.1.1.2.2 pgoyette read_http_result(SSL* ssl)
1072 1.1.1.1.2.2 pgoyette {
1073 1.1.1.1.2.2 pgoyette size_t len = 0;
1074 1.1.1.1.2.2 pgoyette char* data;
1075 1.1.1.1.2.2 pgoyette BIO* m;
1076 1.1.1.1.2.2 pgoyette if(!read_http_headers(ssl, &len)) {
1077 1.1.1.1.2.2 pgoyette return NULL;
1078 1.1.1.1.2.2 pgoyette }
1079 1.1.1.1.2.2 pgoyette if(len == 0) {
1080 1.1.1.1.2.2 pgoyette data = read_chunked_zero_terminate(ssl, &len);
1081 1.1.1.1.2.2 pgoyette } else {
1082 1.1.1.1.2.2 pgoyette data = read_data_chunk(ssl, len);
1083 1.1.1.1.2.2 pgoyette }
1084 1.1.1.1.2.2 pgoyette if(!data) return NULL;
1085 1.1.1.1.2.2 pgoyette if(verb >= 4) print_data("read data", data, (int)len);
1086 1.1.1.1.2.2 pgoyette m = BIO_new_mem_buf(data, (int)len);
1087 1.1.1.1.2.2 pgoyette if(!m) {
1088 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1089 1.1.1.1.2.2 pgoyette exit(0);
1090 1.1.1.1.2.2 pgoyette }
1091 1.1.1.1.2.2 pgoyette return m;
1092 1.1.1.1.2.2 pgoyette }
1093 1.1.1.1.2.2 pgoyette
1094 1.1.1.1.2.2 pgoyette /** https to an IP addr, return BIO with pathname or NULL */
1095 1.1.1.1.2.2 pgoyette static BIO*
1096 1.1.1.1.2.2 pgoyette https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname)
1097 1.1.1.1.2.2 pgoyette {
1098 1.1.1.1.2.2 pgoyette int fd;
1099 1.1.1.1.2.2 pgoyette SSL* ssl;
1100 1.1.1.1.2.2 pgoyette BIO* bio;
1101 1.1.1.1.2.2 pgoyette SSL_CTX* sslctx = setup_sslctx();
1102 1.1.1.1.2.2 pgoyette if(!sslctx) {
1103 1.1.1.1.2.2 pgoyette return NULL;
1104 1.1.1.1.2.2 pgoyette }
1105 1.1.1.1.2.2 pgoyette fd = connect_to_ip(ip);
1106 1.1.1.1.2.2 pgoyette if(fd == -1) {
1107 1.1.1.1.2.2 pgoyette SSL_CTX_free(sslctx);
1108 1.1.1.1.2.2 pgoyette return NULL;
1109 1.1.1.1.2.2 pgoyette }
1110 1.1.1.1.2.2 pgoyette ssl = TLS_initiate(sslctx, fd);
1111 1.1.1.1.2.2 pgoyette if(!ssl) {
1112 1.1.1.1.2.2 pgoyette SSL_CTX_free(sslctx);
1113 1.1.1.1.2.2 pgoyette fd_close(fd);
1114 1.1.1.1.2.2 pgoyette return NULL;
1115 1.1.1.1.2.2 pgoyette }
1116 1.1.1.1.2.2 pgoyette if(!write_http_get(ssl, pathname, urlname)) {
1117 1.1.1.1.2.2 pgoyette if(verb) printf("could not write to server\n");
1118 1.1.1.1.2.2 pgoyette SSL_free(ssl);
1119 1.1.1.1.2.2 pgoyette SSL_CTX_free(sslctx);
1120 1.1.1.1.2.2 pgoyette fd_close(fd);
1121 1.1.1.1.2.2 pgoyette return NULL;
1122 1.1.1.1.2.2 pgoyette }
1123 1.1.1.1.2.2 pgoyette bio = read_http_result(ssl);
1124 1.1.1.1.2.2 pgoyette TLS_shutdown(fd, ssl, sslctx);
1125 1.1.1.1.2.2 pgoyette return bio;
1126 1.1.1.1.2.2 pgoyette }
1127 1.1.1.1.2.2 pgoyette
1128 1.1.1.1.2.2 pgoyette /**
1129 1.1.1.1.2.2 pgoyette * Do a HTTPS, HTTP1.1 over TLS, to fetch a file
1130 1.1.1.1.2.2 pgoyette * @param ip_list: list of IP addresses to use to fetch from.
1131 1.1.1.1.2.2 pgoyette * @param pathname: pathname of file on server to GET.
1132 1.1.1.1.2.2 pgoyette * @param urlname: name to pass as the virtual host for this request.
1133 1.1.1.1.2.2 pgoyette * @return a memory BIO with the file in it.
1134 1.1.1.1.2.2 pgoyette */
1135 1.1.1.1.2.2 pgoyette static BIO*
1136 1.1.1.1.2.2 pgoyette https(struct ip_list* ip_list, const char* pathname, const char* urlname)
1137 1.1.1.1.2.2 pgoyette {
1138 1.1.1.1.2.2 pgoyette struct ip_list* ip;
1139 1.1.1.1.2.2 pgoyette BIO* bio = NULL;
1140 1.1.1.1.2.2 pgoyette /* try random address first, and work through the list */
1141 1.1.1.1.2.2 pgoyette wipe_ip_usage(ip_list);
1142 1.1.1.1.2.2 pgoyette while( (ip = pick_random_ip(ip_list)) ) {
1143 1.1.1.1.2.2 pgoyette ip->used = 1;
1144 1.1.1.1.2.2 pgoyette bio = https_to_ip(ip, pathname, urlname);
1145 1.1.1.1.2.2 pgoyette if(bio) break;
1146 1.1.1.1.2.2 pgoyette }
1147 1.1.1.1.2.2 pgoyette if(!bio) {
1148 1.1.1.1.2.2 pgoyette if(verb) printf("could not fetch %s\n", pathname);
1149 1.1.1.1.2.2 pgoyette exit(0);
1150 1.1.1.1.2.2 pgoyette } else {
1151 1.1.1.1.2.2 pgoyette if(verb) printf("fetched %s (%d bytes)\n",
1152 1.1.1.1.2.2 pgoyette pathname, (int)BIO_ctrl_pending(bio));
1153 1.1.1.1.2.2 pgoyette }
1154 1.1.1.1.2.2 pgoyette return bio;
1155 1.1.1.1.2.2 pgoyette }
1156 1.1.1.1.2.2 pgoyette
1157 1.1.1.1.2.2 pgoyette /** free up a downloaded file BIO */
1158 1.1.1.1.2.2 pgoyette static void
1159 1.1.1.1.2.2 pgoyette free_file_bio(BIO* bio)
1160 1.1.1.1.2.2 pgoyette {
1161 1.1.1.1.2.2 pgoyette char* pp = NULL;
1162 1.1.1.1.2.2 pgoyette (void)BIO_reset(bio);
1163 1.1.1.1.2.2 pgoyette (void)BIO_get_mem_data(bio, &pp);
1164 1.1.1.1.2.2 pgoyette free(pp);
1165 1.1.1.1.2.2 pgoyette BIO_free(bio);
1166 1.1.1.1.2.2 pgoyette }
1167 1.1.1.1.2.2 pgoyette
1168 1.1.1.1.2.2 pgoyette /** XML parse private data during the parse */
1169 1.1.1.1.2.2 pgoyette struct xml_data {
1170 1.1.1.1.2.2 pgoyette /** the parser, reference */
1171 1.1.1.1.2.2 pgoyette XML_Parser parser;
1172 1.1.1.1.2.2 pgoyette /** the current tag; malloced; or NULL outside of tags */
1173 1.1.1.1.2.2 pgoyette char* tag;
1174 1.1.1.1.2.2 pgoyette /** current date to use during the parse */
1175 1.1.1.1.2.2 pgoyette time_t date;
1176 1.1.1.1.2.2 pgoyette /** number of keys usefully read in */
1177 1.1.1.1.2.2 pgoyette int num_keys;
1178 1.1.1.1.2.2 pgoyette /** the compiled anchors as DS records */
1179 1.1.1.1.2.2 pgoyette BIO* ds;
1180 1.1.1.1.2.2 pgoyette
1181 1.1.1.1.2.2 pgoyette /** do we want to use this anchor? */
1182 1.1.1.1.2.2 pgoyette int use_key;
1183 1.1.1.1.2.2 pgoyette /** the current anchor: Zone */
1184 1.1.1.1.2.2 pgoyette BIO* czone;
1185 1.1.1.1.2.2 pgoyette /** the current anchor: KeyTag */
1186 1.1.1.1.2.2 pgoyette BIO* ctag;
1187 1.1.1.1.2.2 pgoyette /** the current anchor: Algorithm */
1188 1.1.1.1.2.2 pgoyette BIO* calgo;
1189 1.1.1.1.2.2 pgoyette /** the current anchor: DigestType */
1190 1.1.1.1.2.2 pgoyette BIO* cdigtype;
1191 1.1.1.1.2.2 pgoyette /** the current anchor: Digest*/
1192 1.1.1.1.2.2 pgoyette BIO* cdigest;
1193 1.1.1.1.2.2 pgoyette };
1194 1.1.1.1.2.2 pgoyette
1195 1.1.1.1.2.2 pgoyette /** The BIO for the tag */
1196 1.1.1.1.2.2 pgoyette static BIO*
1197 1.1.1.1.2.2 pgoyette xml_selectbio(struct xml_data* data, const char* tag)
1198 1.1.1.1.2.2 pgoyette {
1199 1.1.1.1.2.2 pgoyette BIO* b = NULL;
1200 1.1.1.1.2.2 pgoyette if(strcasecmp(tag, "KeyTag") == 0)
1201 1.1.1.1.2.2 pgoyette b = data->ctag;
1202 1.1.1.1.2.2 pgoyette else if(strcasecmp(tag, "Algorithm") == 0)
1203 1.1.1.1.2.2 pgoyette b = data->calgo;
1204 1.1.1.1.2.2 pgoyette else if(strcasecmp(tag, "DigestType") == 0)
1205 1.1.1.1.2.2 pgoyette b = data->cdigtype;
1206 1.1.1.1.2.2 pgoyette else if(strcasecmp(tag, "Digest") == 0)
1207 1.1.1.1.2.2 pgoyette b = data->cdigest;
1208 1.1.1.1.2.2 pgoyette return b;
1209 1.1.1.1.2.2 pgoyette }
1210 1.1.1.1.2.2 pgoyette
1211 1.1.1.1.2.2 pgoyette /**
1212 1.1.1.1.2.2 pgoyette * XML handle character data, the data inside an element.
1213 1.1.1.1.2.2 pgoyette * @param userData: xml_data structure
1214 1.1.1.1.2.2 pgoyette * @param s: the character data. May not all be in one callback.
1215 1.1.1.1.2.2 pgoyette * NOT zero terminated.
1216 1.1.1.1.2.2 pgoyette * @param len: length of this part of the data.
1217 1.1.1.1.2.2 pgoyette */
1218 1.1.1.1.2.2 pgoyette static void
1219 1.1.1.1.2.2 pgoyette xml_charhandle(void *userData, const XML_Char *s, int len)
1220 1.1.1.1.2.2 pgoyette {
1221 1.1.1.1.2.2 pgoyette struct xml_data* data = (struct xml_data*)userData;
1222 1.1.1.1.2.2 pgoyette BIO* b = NULL;
1223 1.1.1.1.2.2 pgoyette /* skip characters outside of elements */
1224 1.1.1.1.2.2 pgoyette if(!data->tag)
1225 1.1.1.1.2.2 pgoyette return;
1226 1.1.1.1.2.2 pgoyette if(verb>=4) {
1227 1.1.1.1.2.2 pgoyette int i;
1228 1.1.1.1.2.2 pgoyette printf("%s%s charhandle: '",
1229 1.1.1.1.2.2 pgoyette data->use_key?"use ":"",
1230 1.1.1.1.2.2 pgoyette data->tag?data->tag:"none");
1231 1.1.1.1.2.2 pgoyette for(i=0; i<len; i++)
1232 1.1.1.1.2.2 pgoyette printf("%c", s[i]);
1233 1.1.1.1.2.2 pgoyette printf("'\n");
1234 1.1.1.1.2.2 pgoyette }
1235 1.1.1.1.2.2 pgoyette if(strcasecmp(data->tag, "Zone") == 0) {
1236 1.1.1.1.2.2 pgoyette if(BIO_write(data->czone, s, len) < 0) {
1237 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory in BIO_write\n");
1238 1.1.1.1.2.2 pgoyette exit(0);
1239 1.1.1.1.2.2 pgoyette }
1240 1.1.1.1.2.2 pgoyette return;
1241 1.1.1.1.2.2 pgoyette }
1242 1.1.1.1.2.2 pgoyette /* only store if key is used */
1243 1.1.1.1.2.2 pgoyette if(!data->use_key)
1244 1.1.1.1.2.2 pgoyette return;
1245 1.1.1.1.2.2 pgoyette b = xml_selectbio(data, data->tag);
1246 1.1.1.1.2.2 pgoyette if(b) {
1247 1.1.1.1.2.2 pgoyette if(BIO_write(b, s, len) < 0) {
1248 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory in BIO_write\n");
1249 1.1.1.1.2.2 pgoyette exit(0);
1250 1.1.1.1.2.2 pgoyette }
1251 1.1.1.1.2.2 pgoyette }
1252 1.1.1.1.2.2 pgoyette }
1253 1.1.1.1.2.2 pgoyette
1254 1.1.1.1.2.2 pgoyette /**
1255 1.1.1.1.2.2 pgoyette * XML fetch value of particular attribute(by name) or NULL if not present.
1256 1.1.1.1.2.2 pgoyette * @param atts: attribute array (from xml_startelem).
1257 1.1.1.1.2.2 pgoyette * @param name: name of attribute to look for.
1258 1.1.1.1.2.2 pgoyette * @return the value or NULL. (ptr into atts).
1259 1.1.1.1.2.2 pgoyette */
1260 1.1.1.1.2.2 pgoyette static const XML_Char*
1261 1.1.1.1.2.2 pgoyette find_att(const XML_Char **atts, const XML_Char* name)
1262 1.1.1.1.2.2 pgoyette {
1263 1.1.1.1.2.2 pgoyette int i;
1264 1.1.1.1.2.2 pgoyette for(i=0; atts[i]; i+=2) {
1265 1.1.1.1.2.2 pgoyette if(strcasecmp(atts[i], name) == 0)
1266 1.1.1.1.2.2 pgoyette return atts[i+1];
1267 1.1.1.1.2.2 pgoyette }
1268 1.1.1.1.2.2 pgoyette return NULL;
1269 1.1.1.1.2.2 pgoyette }
1270 1.1.1.1.2.2 pgoyette
1271 1.1.1.1.2.2 pgoyette /**
1272 1.1.1.1.2.2 pgoyette * XML convert DateTime element to time_t.
1273 1.1.1.1.2.2 pgoyette * [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
1274 1.1.1.1.2.2 pgoyette * (with optional .ssssss fractional seconds)
1275 1.1.1.1.2.2 pgoyette * @param str: the string
1276 1.1.1.1.2.2 pgoyette * @return a time_t representation or 0 on failure.
1277 1.1.1.1.2.2 pgoyette */
1278 1.1.1.1.2.2 pgoyette static time_t
1279 1.1.1.1.2.2 pgoyette xml_convertdate(const char* str)
1280 1.1.1.1.2.2 pgoyette {
1281 1.1.1.1.2.2 pgoyette time_t t = 0;
1282 1.1.1.1.2.2 pgoyette struct tm tm;
1283 1.1.1.1.2.2 pgoyette const char* s;
1284 1.1.1.1.2.2 pgoyette /* for this application, ignore minus in front;
1285 1.1.1.1.2.2 pgoyette * only positive dates are expected */
1286 1.1.1.1.2.2 pgoyette s = str;
1287 1.1.1.1.2.2 pgoyette if(s[0] == '-') s++;
1288 1.1.1.1.2.2 pgoyette memset(&tm, 0, sizeof(tm));
1289 1.1.1.1.2.2 pgoyette /* parse initial content of the string (lots of whitespace allowed) */
1290 1.1.1.1.2.2 pgoyette s = strptime(s, "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t:%t%S%t", &tm);
1291 1.1.1.1.2.2 pgoyette if(!s) {
1292 1.1.1.1.2.2 pgoyette if(verb) printf("xml_convertdate parse failure %s\n", str);
1293 1.1.1.1.2.2 pgoyette return 0;
1294 1.1.1.1.2.2 pgoyette }
1295 1.1.1.1.2.2 pgoyette /* parse remainder of date string */
1296 1.1.1.1.2.2 pgoyette if(*s == '.') {
1297 1.1.1.1.2.2 pgoyette /* optional '.' and fractional seconds */
1298 1.1.1.1.2.2 pgoyette int frac = 0, n = 0;
1299 1.1.1.1.2.2 pgoyette if(sscanf(s+1, "%d%n", &frac, &n) < 1) {
1300 1.1.1.1.2.2 pgoyette if(verb) printf("xml_convertdate f failure %s\n", str);
1301 1.1.1.1.2.2 pgoyette return 0;
1302 1.1.1.1.2.2 pgoyette }
1303 1.1.1.1.2.2 pgoyette /* fraction is not used, time_t has second accuracy */
1304 1.1.1.1.2.2 pgoyette s++;
1305 1.1.1.1.2.2 pgoyette s+=n;
1306 1.1.1.1.2.2 pgoyette }
1307 1.1.1.1.2.2 pgoyette if(*s == 'Z' || *s == 'z') {
1308 1.1.1.1.2.2 pgoyette /* nothing to do for this */
1309 1.1.1.1.2.2 pgoyette s++;
1310 1.1.1.1.2.2 pgoyette } else if(*s == '+' || *s == '-') {
1311 1.1.1.1.2.2 pgoyette /* optional timezone spec: Z or +hh:mm or -hh:mm */
1312 1.1.1.1.2.2 pgoyette int hr = 0, mn = 0, n = 0;
1313 1.1.1.1.2.2 pgoyette if(sscanf(s+1, "%d:%d%n", &hr, &mn, &n) < 2) {
1314 1.1.1.1.2.2 pgoyette if(verb) printf("xml_convertdate tz failure %s\n", str);
1315 1.1.1.1.2.2 pgoyette return 0;
1316 1.1.1.1.2.2 pgoyette }
1317 1.1.1.1.2.2 pgoyette if(*s == '+') {
1318 1.1.1.1.2.2 pgoyette tm.tm_hour += hr;
1319 1.1.1.1.2.2 pgoyette tm.tm_min += mn;
1320 1.1.1.1.2.2 pgoyette } else {
1321 1.1.1.1.2.2 pgoyette tm.tm_hour -= hr;
1322 1.1.1.1.2.2 pgoyette tm.tm_min -= mn;
1323 1.1.1.1.2.2 pgoyette }
1324 1.1.1.1.2.2 pgoyette s++;
1325 1.1.1.1.2.2 pgoyette s += n;
1326 1.1.1.1.2.2 pgoyette }
1327 1.1.1.1.2.2 pgoyette if(*s != 0) {
1328 1.1.1.1.2.2 pgoyette /* not ended properly */
1329 1.1.1.1.2.2 pgoyette /* but ignore, (lenient) */
1330 1.1.1.1.2.2 pgoyette }
1331 1.1.1.1.2.2 pgoyette
1332 1.1.1.1.2.2 pgoyette t = sldns_mktime_from_utc(&tm);
1333 1.1.1.1.2.2 pgoyette if(t == (time_t)-1) {
1334 1.1.1.1.2.2 pgoyette if(verb) printf("xml_convertdate mktime failure\n");
1335 1.1.1.1.2.2 pgoyette return 0;
1336 1.1.1.1.2.2 pgoyette }
1337 1.1.1.1.2.2 pgoyette return t;
1338 1.1.1.1.2.2 pgoyette }
1339 1.1.1.1.2.2 pgoyette
1340 1.1.1.1.2.2 pgoyette /**
1341 1.1.1.1.2.2 pgoyette * XML handle the KeyDigest start tag, check validity periods.
1342 1.1.1.1.2.2 pgoyette */
1343 1.1.1.1.2.2 pgoyette static void
1344 1.1.1.1.2.2 pgoyette handle_keydigest(struct xml_data* data, const XML_Char **atts)
1345 1.1.1.1.2.2 pgoyette {
1346 1.1.1.1.2.2 pgoyette data->use_key = 0;
1347 1.1.1.1.2.2 pgoyette if(find_att(atts, "validFrom")) {
1348 1.1.1.1.2.2 pgoyette time_t from = xml_convertdate(find_att(atts, "validFrom"));
1349 1.1.1.1.2.2 pgoyette if(from == 0) {
1350 1.1.1.1.2.2 pgoyette if(verb) printf("error: xml cannot be parsed\n");
1351 1.1.1.1.2.2 pgoyette exit(0);
1352 1.1.1.1.2.2 pgoyette }
1353 1.1.1.1.2.2 pgoyette if(data->date < from)
1354 1.1.1.1.2.2 pgoyette return;
1355 1.1.1.1.2.2 pgoyette }
1356 1.1.1.1.2.2 pgoyette if(find_att(atts, "validUntil")) {
1357 1.1.1.1.2.2 pgoyette time_t until = xml_convertdate(find_att(atts, "validUntil"));
1358 1.1.1.1.2.2 pgoyette if(until == 0) {
1359 1.1.1.1.2.2 pgoyette if(verb) printf("error: xml cannot be parsed\n");
1360 1.1.1.1.2.2 pgoyette exit(0);
1361 1.1.1.1.2.2 pgoyette }
1362 1.1.1.1.2.2 pgoyette if(data->date > until)
1363 1.1.1.1.2.2 pgoyette return;
1364 1.1.1.1.2.2 pgoyette }
1365 1.1.1.1.2.2 pgoyette /* yes we want to use this key */
1366 1.1.1.1.2.2 pgoyette data->use_key = 1;
1367 1.1.1.1.2.2 pgoyette (void)BIO_reset(data->ctag);
1368 1.1.1.1.2.2 pgoyette (void)BIO_reset(data->calgo);
1369 1.1.1.1.2.2 pgoyette (void)BIO_reset(data->cdigtype);
1370 1.1.1.1.2.2 pgoyette (void)BIO_reset(data->cdigest);
1371 1.1.1.1.2.2 pgoyette }
1372 1.1.1.1.2.2 pgoyette
1373 1.1.1.1.2.2 pgoyette /** See if XML element equals the zone name */
1374 1.1.1.1.2.2 pgoyette static int
1375 1.1.1.1.2.2 pgoyette xml_is_zone_name(BIO* zone, const char* name)
1376 1.1.1.1.2.2 pgoyette {
1377 1.1.1.1.2.2 pgoyette char buf[1024];
1378 1.1.1.1.2.2 pgoyette char* z = NULL;
1379 1.1.1.1.2.2 pgoyette long zlen;
1380 1.1.1.1.2.2 pgoyette (void)BIO_seek(zone, 0);
1381 1.1.1.1.2.2 pgoyette zlen = BIO_get_mem_data(zone, &z);
1382 1.1.1.1.2.2 pgoyette if(!zlen || !z) return 0;
1383 1.1.1.1.2.2 pgoyette /* zero terminate */
1384 1.1.1.1.2.2 pgoyette if(zlen >= (long)sizeof(buf)) return 0;
1385 1.1.1.1.2.2 pgoyette memmove(buf, z, (size_t)zlen);
1386 1.1.1.1.2.2 pgoyette buf[zlen] = 0;
1387 1.1.1.1.2.2 pgoyette /* compare */
1388 1.1.1.1.2.2 pgoyette return (strncasecmp(buf, name, strlen(name)) == 0);
1389 1.1.1.1.2.2 pgoyette }
1390 1.1.1.1.2.2 pgoyette
1391 1.1.1.1.2.2 pgoyette /**
1392 1.1.1.1.2.2 pgoyette * XML start of element. This callback is called whenever an XML tag starts.
1393 1.1.1.1.2.2 pgoyette * XML_Char is UTF8.
1394 1.1.1.1.2.2 pgoyette * @param userData: the xml_data structure.
1395 1.1.1.1.2.2 pgoyette * @param name: the tag that starts.
1396 1.1.1.1.2.2 pgoyette * @param atts: array of strings, pairs of attr = value, ends with NULL.
1397 1.1.1.1.2.2 pgoyette * i.e. att[0]="att[1]" att[2]="att[3]" att[4]isNull
1398 1.1.1.1.2.2 pgoyette */
1399 1.1.1.1.2.2 pgoyette static void
1400 1.1.1.1.2.2 pgoyette xml_startelem(void *userData, const XML_Char *name, const XML_Char **atts)
1401 1.1.1.1.2.2 pgoyette {
1402 1.1.1.1.2.2 pgoyette struct xml_data* data = (struct xml_data*)userData;
1403 1.1.1.1.2.2 pgoyette BIO* b;
1404 1.1.1.1.2.2 pgoyette if(verb>=4) printf("xml tag start '%s'\n", name);
1405 1.1.1.1.2.2 pgoyette free(data->tag);
1406 1.1.1.1.2.2 pgoyette data->tag = strdup(name);
1407 1.1.1.1.2.2 pgoyette if(!data->tag) {
1408 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1409 1.1.1.1.2.2 pgoyette exit(0);
1410 1.1.1.1.2.2 pgoyette }
1411 1.1.1.1.2.2 pgoyette if(verb>=4) {
1412 1.1.1.1.2.2 pgoyette int i;
1413 1.1.1.1.2.2 pgoyette for(i=0; atts[i]; i+=2) {
1414 1.1.1.1.2.2 pgoyette printf(" %s='%s'\n", atts[i], atts[i+1]);
1415 1.1.1.1.2.2 pgoyette }
1416 1.1.1.1.2.2 pgoyette }
1417 1.1.1.1.2.2 pgoyette /* handle attributes to particular types */
1418 1.1.1.1.2.2 pgoyette if(strcasecmp(name, "KeyDigest") == 0) {
1419 1.1.1.1.2.2 pgoyette handle_keydigest(data, atts);
1420 1.1.1.1.2.2 pgoyette return;
1421 1.1.1.1.2.2 pgoyette } else if(strcasecmp(name, "Zone") == 0) {
1422 1.1.1.1.2.2 pgoyette (void)BIO_reset(data->czone);
1423 1.1.1.1.2.2 pgoyette return;
1424 1.1.1.1.2.2 pgoyette }
1425 1.1.1.1.2.2 pgoyette
1426 1.1.1.1.2.2 pgoyette /* for other types we prepare to pick up the data */
1427 1.1.1.1.2.2 pgoyette if(!data->use_key)
1428 1.1.1.1.2.2 pgoyette return;
1429 1.1.1.1.2.2 pgoyette b = xml_selectbio(data, data->tag);
1430 1.1.1.1.2.2 pgoyette if(b) {
1431 1.1.1.1.2.2 pgoyette /* empty it */
1432 1.1.1.1.2.2 pgoyette (void)BIO_reset(b);
1433 1.1.1.1.2.2 pgoyette }
1434 1.1.1.1.2.2 pgoyette }
1435 1.1.1.1.2.2 pgoyette
1436 1.1.1.1.2.2 pgoyette /** Append str to bio */
1437 1.1.1.1.2.2 pgoyette static void
1438 1.1.1.1.2.2 pgoyette xml_append_str(BIO* b, const char* s)
1439 1.1.1.1.2.2 pgoyette {
1440 1.1.1.1.2.2 pgoyette if(BIO_write(b, s, (int)strlen(s)) < 0) {
1441 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory in BIO_write\n");
1442 1.1.1.1.2.2 pgoyette exit(0);
1443 1.1.1.1.2.2 pgoyette }
1444 1.1.1.1.2.2 pgoyette }
1445 1.1.1.1.2.2 pgoyette
1446 1.1.1.1.2.2 pgoyette /** Append bio to bio */
1447 1.1.1.1.2.2 pgoyette static void
1448 1.1.1.1.2.2 pgoyette xml_append_bio(BIO* b, BIO* a)
1449 1.1.1.1.2.2 pgoyette {
1450 1.1.1.1.2.2 pgoyette char* z = NULL;
1451 1.1.1.1.2.2 pgoyette long i, len;
1452 1.1.1.1.2.2 pgoyette (void)BIO_seek(a, 0);
1453 1.1.1.1.2.2 pgoyette len = BIO_get_mem_data(a, &z);
1454 1.1.1.1.2.2 pgoyette if(!len || !z) {
1455 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory in BIO_write\n");
1456 1.1.1.1.2.2 pgoyette exit(0);
1457 1.1.1.1.2.2 pgoyette }
1458 1.1.1.1.2.2 pgoyette /* remove newlines in the data here */
1459 1.1.1.1.2.2 pgoyette for(i=0; i<len; i++) {
1460 1.1.1.1.2.2 pgoyette if(z[i] == '\r' || z[i] == '\n')
1461 1.1.1.1.2.2 pgoyette z[i] = ' ';
1462 1.1.1.1.2.2 pgoyette }
1463 1.1.1.1.2.2 pgoyette /* write to BIO */
1464 1.1.1.1.2.2 pgoyette if(BIO_write(b, z, len) < 0) {
1465 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory in BIO_write\n");
1466 1.1.1.1.2.2 pgoyette exit(0);
1467 1.1.1.1.2.2 pgoyette }
1468 1.1.1.1.2.2 pgoyette }
1469 1.1.1.1.2.2 pgoyette
1470 1.1.1.1.2.2 pgoyette /** write the parsed xml-DS to the DS list */
1471 1.1.1.1.2.2 pgoyette static void
1472 1.1.1.1.2.2 pgoyette xml_append_ds(struct xml_data* data)
1473 1.1.1.1.2.2 pgoyette {
1474 1.1.1.1.2.2 pgoyette /* write DS to accumulated DS */
1475 1.1.1.1.2.2 pgoyette xml_append_str(data->ds, ". IN DS ");
1476 1.1.1.1.2.2 pgoyette xml_append_bio(data->ds, data->ctag);
1477 1.1.1.1.2.2 pgoyette xml_append_str(data->ds, " ");
1478 1.1.1.1.2.2 pgoyette xml_append_bio(data->ds, data->calgo);
1479 1.1.1.1.2.2 pgoyette xml_append_str(data->ds, " ");
1480 1.1.1.1.2.2 pgoyette xml_append_bio(data->ds, data->cdigtype);
1481 1.1.1.1.2.2 pgoyette xml_append_str(data->ds, " ");
1482 1.1.1.1.2.2 pgoyette xml_append_bio(data->ds, data->cdigest);
1483 1.1.1.1.2.2 pgoyette xml_append_str(data->ds, "\n");
1484 1.1.1.1.2.2 pgoyette data->num_keys++;
1485 1.1.1.1.2.2 pgoyette }
1486 1.1.1.1.2.2 pgoyette
1487 1.1.1.1.2.2 pgoyette /**
1488 1.1.1.1.2.2 pgoyette * XML end of element. This callback is called whenever an XML tag ends.
1489 1.1.1.1.2.2 pgoyette * XML_Char is UTF8.
1490 1.1.1.1.2.2 pgoyette * @param userData: the xml_data structure
1491 1.1.1.1.2.2 pgoyette * @param name: the tag that ends.
1492 1.1.1.1.2.2 pgoyette */
1493 1.1.1.1.2.2 pgoyette static void
1494 1.1.1.1.2.2 pgoyette xml_endelem(void *userData, const XML_Char *name)
1495 1.1.1.1.2.2 pgoyette {
1496 1.1.1.1.2.2 pgoyette struct xml_data* data = (struct xml_data*)userData;
1497 1.1.1.1.2.2 pgoyette if(verb>=4) printf("xml tag end '%s'\n", name);
1498 1.1.1.1.2.2 pgoyette free(data->tag);
1499 1.1.1.1.2.2 pgoyette data->tag = NULL;
1500 1.1.1.1.2.2 pgoyette if(strcasecmp(name, "KeyDigest") == 0) {
1501 1.1.1.1.2.2 pgoyette if(data->use_key)
1502 1.1.1.1.2.2 pgoyette xml_append_ds(data);
1503 1.1.1.1.2.2 pgoyette data->use_key = 0;
1504 1.1.1.1.2.2 pgoyette } else if(strcasecmp(name, "Zone") == 0) {
1505 1.1.1.1.2.2 pgoyette if(!xml_is_zone_name(data->czone, ".")) {
1506 1.1.1.1.2.2 pgoyette if(verb) printf("xml not for the right zone\n");
1507 1.1.1.1.2.2 pgoyette exit(0);
1508 1.1.1.1.2.2 pgoyette }
1509 1.1.1.1.2.2 pgoyette }
1510 1.1.1.1.2.2 pgoyette }
1511 1.1.1.1.2.2 pgoyette
1512 1.1.1.1.2.2 pgoyette /* Stop the parser when an entity declaration is encountered. For safety. */
1513 1.1.1.1.2.2 pgoyette static void
1514 1.1.1.1.2.2 pgoyette xml_entitydeclhandler(void *userData,
1515 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(entityName),
1516 1.1.1.1.2.2 pgoyette int ATTR_UNUSED(is_parameter_entity),
1517 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(value), int ATTR_UNUSED(value_length),
1518 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(base),
1519 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(systemId),
1520 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(publicId),
1521 1.1.1.1.2.2 pgoyette const XML_Char *ATTR_UNUSED(notationName))
1522 1.1.1.1.2.2 pgoyette {
1523 1.1.1.1.2.2 pgoyette #if HAVE_DECL_XML_STOPPARSER
1524 1.1.1.1.2.2 pgoyette (void)XML_StopParser((XML_Parser)userData, XML_FALSE);
1525 1.1.1.1.2.2 pgoyette #else
1526 1.1.1.1.2.2 pgoyette (void)userData;
1527 1.1.1.1.2.2 pgoyette #endif
1528 1.1.1.1.2.2 pgoyette }
1529 1.1.1.1.2.2 pgoyette
1530 1.1.1.1.2.2 pgoyette /**
1531 1.1.1.1.2.2 pgoyette * XML parser setup of the callbacks for the tags
1532 1.1.1.1.2.2 pgoyette */
1533 1.1.1.1.2.2 pgoyette static void
1534 1.1.1.1.2.2 pgoyette xml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now)
1535 1.1.1.1.2.2 pgoyette {
1536 1.1.1.1.2.2 pgoyette char buf[1024];
1537 1.1.1.1.2.2 pgoyette memset(data, 0, sizeof(*data));
1538 1.1.1.1.2.2 pgoyette XML_SetUserData(parser, data);
1539 1.1.1.1.2.2 pgoyette data->parser = parser;
1540 1.1.1.1.2.2 pgoyette data->date = now;
1541 1.1.1.1.2.2 pgoyette data->ds = BIO_new(BIO_s_mem());
1542 1.1.1.1.2.2 pgoyette data->ctag = BIO_new(BIO_s_mem());
1543 1.1.1.1.2.2 pgoyette data->czone = BIO_new(BIO_s_mem());
1544 1.1.1.1.2.2 pgoyette data->calgo = BIO_new(BIO_s_mem());
1545 1.1.1.1.2.2 pgoyette data->cdigtype = BIO_new(BIO_s_mem());
1546 1.1.1.1.2.2 pgoyette data->cdigest = BIO_new(BIO_s_mem());
1547 1.1.1.1.2.2 pgoyette if(!data->ds || !data->ctag || !data->calgo || !data->czone ||
1548 1.1.1.1.2.2 pgoyette !data->cdigtype || !data->cdigest) {
1549 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1550 1.1.1.1.2.2 pgoyette exit(0);
1551 1.1.1.1.2.2 pgoyette }
1552 1.1.1.1.2.2 pgoyette snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s",
1553 1.1.1.1.2.2 pgoyette ctime(&now));
1554 1.1.1.1.2.2 pgoyette if(BIO_write(data->ds, buf, (int)strlen(buf)) < 0) {
1555 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1556 1.1.1.1.2.2 pgoyette exit(0);
1557 1.1.1.1.2.2 pgoyette }
1558 1.1.1.1.2.2 pgoyette XML_SetEntityDeclHandler(parser, xml_entitydeclhandler);
1559 1.1.1.1.2.2 pgoyette XML_SetElementHandler(parser, xml_startelem, xml_endelem);
1560 1.1.1.1.2.2 pgoyette XML_SetCharacterDataHandler(parser, xml_charhandle);
1561 1.1.1.1.2.2 pgoyette }
1562 1.1.1.1.2.2 pgoyette
1563 1.1.1.1.2.2 pgoyette /**
1564 1.1.1.1.2.2 pgoyette * Perform XML parsing of the root-anchors file
1565 1.1.1.1.2.2 pgoyette * Its format description can be read here
1566 1.1.1.1.2.2 pgoyette * https://data.iana.org/root-anchors/draft-icann-dnssec-trust-anchor.txt
1567 1.1.1.1.2.2 pgoyette * It uses libexpat.
1568 1.1.1.1.2.2 pgoyette * @param xml: BIO with xml data.
1569 1.1.1.1.2.2 pgoyette * @param now: the current time for checking DS validity periods.
1570 1.1.1.1.2.2 pgoyette * @return memoryBIO with the DS data in zone format.
1571 1.1.1.1.2.2 pgoyette * or NULL if the zone is insecure.
1572 1.1.1.1.2.2 pgoyette * (It exit()s on error)
1573 1.1.1.1.2.2 pgoyette */
1574 1.1.1.1.2.2 pgoyette static BIO*
1575 1.1.1.1.2.2 pgoyette xml_parse(BIO* xml, time_t now)
1576 1.1.1.1.2.2 pgoyette {
1577 1.1.1.1.2.2 pgoyette char* pp;
1578 1.1.1.1.2.2 pgoyette int len;
1579 1.1.1.1.2.2 pgoyette XML_Parser parser;
1580 1.1.1.1.2.2 pgoyette struct xml_data data;
1581 1.1.1.1.2.2 pgoyette
1582 1.1.1.1.2.2 pgoyette parser = XML_ParserCreate(NULL);
1583 1.1.1.1.2.2 pgoyette if(!parser) {
1584 1.1.1.1.2.2 pgoyette if(verb) printf("could not XML_ParserCreate\n");
1585 1.1.1.1.2.2 pgoyette exit(0);
1586 1.1.1.1.2.2 pgoyette }
1587 1.1.1.1.2.2 pgoyette
1588 1.1.1.1.2.2 pgoyette /* setup callbacks */
1589 1.1.1.1.2.2 pgoyette xml_parse_setup(parser, &data, now);
1590 1.1.1.1.2.2 pgoyette
1591 1.1.1.1.2.2 pgoyette /* parse it */
1592 1.1.1.1.2.2 pgoyette (void)BIO_reset(xml);
1593 1.1.1.1.2.2 pgoyette len = (int)BIO_get_mem_data(xml, &pp);
1594 1.1.1.1.2.2 pgoyette if(!len || !pp) {
1595 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1596 1.1.1.1.2.2 pgoyette exit(0);
1597 1.1.1.1.2.2 pgoyette }
1598 1.1.1.1.2.2 pgoyette if(!XML_Parse(parser, pp, len, 1 /*isfinal*/ )) {
1599 1.1.1.1.2.2 pgoyette const char *e = XML_ErrorString(XML_GetErrorCode(parser));
1600 1.1.1.1.2.2 pgoyette if(verb) printf("XML_Parse failure %s\n", e?e:"");
1601 1.1.1.1.2.2 pgoyette exit(0);
1602 1.1.1.1.2.2 pgoyette }
1603 1.1.1.1.2.2 pgoyette
1604 1.1.1.1.2.2 pgoyette /* parsed */
1605 1.1.1.1.2.2 pgoyette if(verb) printf("XML was parsed successfully, %d keys\n",
1606 1.1.1.1.2.2 pgoyette data.num_keys);
1607 1.1.1.1.2.2 pgoyette free(data.tag);
1608 1.1.1.1.2.2 pgoyette XML_ParserFree(parser);
1609 1.1.1.1.2.2 pgoyette
1610 1.1.1.1.2.2 pgoyette if(verb >= 4) {
1611 1.1.1.1.2.2 pgoyette (void)BIO_seek(data.ds, 0);
1612 1.1.1.1.2.2 pgoyette len = BIO_get_mem_data(data.ds, &pp);
1613 1.1.1.1.2.2 pgoyette printf("got DS bio %d: '", len);
1614 1.1.1.1.2.2 pgoyette if(!fwrite(pp, (size_t)len, 1, stdout))
1615 1.1.1.1.2.2 pgoyette /* compilers do not allow us to ignore fwrite .. */
1616 1.1.1.1.2.2 pgoyette fprintf(stderr, "error writing to stdout\n");
1617 1.1.1.1.2.2 pgoyette printf("'\n");
1618 1.1.1.1.2.2 pgoyette }
1619 1.1.1.1.2.2 pgoyette BIO_free(data.czone);
1620 1.1.1.1.2.2 pgoyette BIO_free(data.ctag);
1621 1.1.1.1.2.2 pgoyette BIO_free(data.calgo);
1622 1.1.1.1.2.2 pgoyette BIO_free(data.cdigtype);
1623 1.1.1.1.2.2 pgoyette BIO_free(data.cdigest);
1624 1.1.1.1.2.2 pgoyette
1625 1.1.1.1.2.2 pgoyette if(data.num_keys == 0) {
1626 1.1.1.1.2.2 pgoyette /* the root zone seems to have gone insecure */
1627 1.1.1.1.2.2 pgoyette BIO_free(data.ds);
1628 1.1.1.1.2.2 pgoyette return NULL;
1629 1.1.1.1.2.2 pgoyette } else {
1630 1.1.1.1.2.2 pgoyette return data.ds;
1631 1.1.1.1.2.2 pgoyette }
1632 1.1.1.1.2.2 pgoyette }
1633 1.1.1.1.2.2 pgoyette
1634 1.1.1.1.2.2 pgoyette /* get key usage out of its extension, returns 0 if no key_usage extension */
1635 1.1.1.1.2.2 pgoyette static unsigned long
1636 1.1.1.1.2.2 pgoyette get_usage_of_ex(X509* cert)
1637 1.1.1.1.2.2 pgoyette {
1638 1.1.1.1.2.2 pgoyette unsigned long val = 0;
1639 1.1.1.1.2.2 pgoyette ASN1_BIT_STRING* s;
1640 1.1.1.1.2.2 pgoyette if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) {
1641 1.1.1.1.2.2 pgoyette if(s->length > 0) {
1642 1.1.1.1.2.2 pgoyette val = s->data[0];
1643 1.1.1.1.2.2 pgoyette if(s->length > 1)
1644 1.1.1.1.2.2 pgoyette val |= s->data[1] << 8;
1645 1.1.1.1.2.2 pgoyette }
1646 1.1.1.1.2.2 pgoyette ASN1_BIT_STRING_free(s);
1647 1.1.1.1.2.2 pgoyette }
1648 1.1.1.1.2.2 pgoyette return val;
1649 1.1.1.1.2.2 pgoyette }
1650 1.1.1.1.2.2 pgoyette
1651 1.1.1.1.2.2 pgoyette /** get valid signers from the list of signers in the signature */
1652 1.1.1.1.2.2 pgoyette static STACK_OF(X509)*
1653 1.1.1.1.2.2 pgoyette get_valid_signers(PKCS7* p7, const char* p7signer)
1654 1.1.1.1.2.2 pgoyette {
1655 1.1.1.1.2.2 pgoyette int i;
1656 1.1.1.1.2.2 pgoyette STACK_OF(X509)* validsigners = sk_X509_new_null();
1657 1.1.1.1.2.2 pgoyette STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0);
1658 1.1.1.1.2.2 pgoyette unsigned long usage = 0;
1659 1.1.1.1.2.2 pgoyette if(!validsigners) {
1660 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1661 1.1.1.1.2.2 pgoyette sk_X509_free(signers);
1662 1.1.1.1.2.2 pgoyette return NULL;
1663 1.1.1.1.2.2 pgoyette }
1664 1.1.1.1.2.2 pgoyette if(!signers) {
1665 1.1.1.1.2.2 pgoyette if(verb) printf("no signers in pkcs7 signature\n");
1666 1.1.1.1.2.2 pgoyette sk_X509_free(validsigners);
1667 1.1.1.1.2.2 pgoyette return NULL;
1668 1.1.1.1.2.2 pgoyette }
1669 1.1.1.1.2.2 pgoyette for(i=0; i<sk_X509_num(signers); i++) {
1670 1.1.1.1.2.2 pgoyette X509_NAME* nm = X509_get_subject_name(
1671 1.1.1.1.2.2 pgoyette sk_X509_value(signers, i));
1672 1.1.1.1.2.2 pgoyette char buf[1024];
1673 1.1.1.1.2.2 pgoyette if(!nm) {
1674 1.1.1.1.2.2 pgoyette if(verb) printf("signer %d: cert has no subject name\n", i);
1675 1.1.1.1.2.2 pgoyette continue;
1676 1.1.1.1.2.2 pgoyette }
1677 1.1.1.1.2.2 pgoyette if(verb && nm) {
1678 1.1.1.1.2.2 pgoyette char* nmline = X509_NAME_oneline(nm, buf,
1679 1.1.1.1.2.2 pgoyette (int)sizeof(buf));
1680 1.1.1.1.2.2 pgoyette printf("signer %d: Subject: %s\n", i,
1681 1.1.1.1.2.2 pgoyette nmline?nmline:"no subject");
1682 1.1.1.1.2.2 pgoyette if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
1683 1.1.1.1.2.2 pgoyette NID_commonName, buf, (int)sizeof(buf)))
1684 1.1.1.1.2.2 pgoyette printf("commonName: %s\n", buf);
1685 1.1.1.1.2.2 pgoyette if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
1686 1.1.1.1.2.2 pgoyette NID_pkcs9_emailAddress, buf, (int)sizeof(buf)))
1687 1.1.1.1.2.2 pgoyette printf("emailAddress: %s\n", buf);
1688 1.1.1.1.2.2 pgoyette }
1689 1.1.1.1.2.2 pgoyette if(verb) {
1690 1.1.1.1.2.2 pgoyette int ku_loc = X509_get_ext_by_NID(
1691 1.1.1.1.2.2 pgoyette sk_X509_value(signers, i), NID_key_usage, -1);
1692 1.1.1.1.2.2 pgoyette if(verb >= 3 && ku_loc >= 0) {
1693 1.1.1.1.2.2 pgoyette X509_EXTENSION *ex = X509_get_ext(
1694 1.1.1.1.2.2 pgoyette sk_X509_value(signers, i), ku_loc);
1695 1.1.1.1.2.2 pgoyette if(ex) {
1696 1.1.1.1.2.2 pgoyette printf("keyUsage: ");
1697 1.1.1.1.2.2 pgoyette X509V3_EXT_print_fp(stdout, ex, 0, 0);
1698 1.1.1.1.2.2 pgoyette printf("\n");
1699 1.1.1.1.2.2 pgoyette }
1700 1.1.1.1.2.2 pgoyette }
1701 1.1.1.1.2.2 pgoyette }
1702 1.1.1.1.2.2 pgoyette if(!p7signer || strcmp(p7signer, "")==0) {
1703 1.1.1.1.2.2 pgoyette /* there is no name to check, return all records */
1704 1.1.1.1.2.2 pgoyette if(verb) printf("did not check commonName of signer\n");
1705 1.1.1.1.2.2 pgoyette } else {
1706 1.1.1.1.2.2 pgoyette if(!X509_NAME_get_text_by_NID(nm,
1707 1.1.1.1.2.2 pgoyette NID_pkcs9_emailAddress,
1708 1.1.1.1.2.2 pgoyette buf, (int)sizeof(buf))) {
1709 1.1.1.1.2.2 pgoyette if(verb) printf("removed cert with no name\n");
1710 1.1.1.1.2.2 pgoyette continue; /* no name, no use */
1711 1.1.1.1.2.2 pgoyette }
1712 1.1.1.1.2.2 pgoyette if(strcmp(buf, p7signer) != 0) {
1713 1.1.1.1.2.2 pgoyette if(verb) printf("removed cert with wrong name\n");
1714 1.1.1.1.2.2 pgoyette continue; /* wrong name, skip it */
1715 1.1.1.1.2.2 pgoyette }
1716 1.1.1.1.2.2 pgoyette }
1717 1.1.1.1.2.2 pgoyette
1718 1.1.1.1.2.2 pgoyette /* check that the key usage allows digital signatures
1719 1.1.1.1.2.2 pgoyette * (the p7s) */
1720 1.1.1.1.2.2 pgoyette usage = get_usage_of_ex(sk_X509_value(signers, i));
1721 1.1.1.1.2.2 pgoyette if(!(usage & KU_DIGITAL_SIGNATURE)) {
1722 1.1.1.1.2.2 pgoyette if(verb) printf("removed cert with no key usage Digital Signature allowed\n");
1723 1.1.1.1.2.2 pgoyette continue;
1724 1.1.1.1.2.2 pgoyette }
1725 1.1.1.1.2.2 pgoyette
1726 1.1.1.1.2.2 pgoyette /* we like this cert, add it to our list of valid
1727 1.1.1.1.2.2 pgoyette * signers certificates */
1728 1.1.1.1.2.2 pgoyette sk_X509_push(validsigners, sk_X509_value(signers, i));
1729 1.1.1.1.2.2 pgoyette }
1730 1.1.1.1.2.2 pgoyette sk_X509_free(signers);
1731 1.1.1.1.2.2 pgoyette return validsigners;
1732 1.1.1.1.2.2 pgoyette }
1733 1.1.1.1.2.2 pgoyette
1734 1.1.1.1.2.2 pgoyette /** verify a PKCS7 signature, false on failure */
1735 1.1.1.1.2.2 pgoyette static int
1736 1.1.1.1.2.2 pgoyette verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer)
1737 1.1.1.1.2.2 pgoyette {
1738 1.1.1.1.2.2 pgoyette PKCS7* p7;
1739 1.1.1.1.2.2 pgoyette X509_STORE *store = X509_STORE_new();
1740 1.1.1.1.2.2 pgoyette STACK_OF(X509)* validsigners;
1741 1.1.1.1.2.2 pgoyette int secure = 0;
1742 1.1.1.1.2.2 pgoyette int i;
1743 1.1.1.1.2.2 pgoyette #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1744 1.1.1.1.2.2 pgoyette X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
1745 1.1.1.1.2.2 pgoyette if(!param) {
1746 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1747 1.1.1.1.2.2 pgoyette X509_STORE_free(store);
1748 1.1.1.1.2.2 pgoyette return 0;
1749 1.1.1.1.2.2 pgoyette }
1750 1.1.1.1.2.2 pgoyette /* do the selfcheck on the root certificate; it checks that the
1751 1.1.1.1.2.2 pgoyette * input is valid */
1752 1.1.1.1.2.2 pgoyette X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CHECK_SS_SIGNATURE);
1753 1.1.1.1.2.2 pgoyette if(store) X509_STORE_set1_param(store, param);
1754 1.1.1.1.2.2 pgoyette #endif
1755 1.1.1.1.2.2 pgoyette if(!store) {
1756 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1757 1.1.1.1.2.2 pgoyette #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1758 1.1.1.1.2.2 pgoyette X509_VERIFY_PARAM_free(param);
1759 1.1.1.1.2.2 pgoyette #endif
1760 1.1.1.1.2.2 pgoyette return 0;
1761 1.1.1.1.2.2 pgoyette }
1762 1.1.1.1.2.2 pgoyette #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1763 1.1.1.1.2.2 pgoyette X509_VERIFY_PARAM_free(param);
1764 1.1.1.1.2.2 pgoyette #endif
1765 1.1.1.1.2.2 pgoyette
1766 1.1.1.1.2.2 pgoyette (void)BIO_reset(p7s);
1767 1.1.1.1.2.2 pgoyette (void)BIO_reset(data);
1768 1.1.1.1.2.2 pgoyette
1769 1.1.1.1.2.2 pgoyette /* convert p7s to p7 (the signature) */
1770 1.1.1.1.2.2 pgoyette p7 = d2i_PKCS7_bio(p7s, NULL);
1771 1.1.1.1.2.2 pgoyette if(!p7) {
1772 1.1.1.1.2.2 pgoyette if(verb) printf("could not parse p7s signature file\n");
1773 1.1.1.1.2.2 pgoyette X509_STORE_free(store);
1774 1.1.1.1.2.2 pgoyette return 0;
1775 1.1.1.1.2.2 pgoyette }
1776 1.1.1.1.2.2 pgoyette if(verb >= 2) printf("parsed the PKCS7 signature\n");
1777 1.1.1.1.2.2 pgoyette
1778 1.1.1.1.2.2 pgoyette /* convert trust to trusted certificate store */
1779 1.1.1.1.2.2 pgoyette for(i=0; i<sk_X509_num(trust); i++) {
1780 1.1.1.1.2.2 pgoyette if(!X509_STORE_add_cert(store, sk_X509_value(trust, i))) {
1781 1.1.1.1.2.2 pgoyette if(verb) printf("failed X509_STORE_add_cert\n");
1782 1.1.1.1.2.2 pgoyette X509_STORE_free(store);
1783 1.1.1.1.2.2 pgoyette PKCS7_free(p7);
1784 1.1.1.1.2.2 pgoyette return 0;
1785 1.1.1.1.2.2 pgoyette }
1786 1.1.1.1.2.2 pgoyette }
1787 1.1.1.1.2.2 pgoyette if(verb >= 2) printf("setup the X509_STORE\n");
1788 1.1.1.1.2.2 pgoyette
1789 1.1.1.1.2.2 pgoyette /* check what is in the Subject name of the certificates,
1790 1.1.1.1.2.2 pgoyette * and build a stack that contains only the right certificates */
1791 1.1.1.1.2.2 pgoyette validsigners = get_valid_signers(p7, p7signer);
1792 1.1.1.1.2.2 pgoyette if(!validsigners) {
1793 1.1.1.1.2.2 pgoyette X509_STORE_free(store);
1794 1.1.1.1.2.2 pgoyette PKCS7_free(p7);
1795 1.1.1.1.2.2 pgoyette return 0;
1796 1.1.1.1.2.2 pgoyette }
1797 1.1.1.1.2.2 pgoyette if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) {
1798 1.1.1.1.2.2 pgoyette secure = 1;
1799 1.1.1.1.2.2 pgoyette if(verb) printf("the PKCS7 signature verified\n");
1800 1.1.1.1.2.2 pgoyette } else {
1801 1.1.1.1.2.2 pgoyette if(verb) {
1802 1.1.1.1.2.2 pgoyette ERR_print_errors_fp(stdout);
1803 1.1.1.1.2.2 pgoyette }
1804 1.1.1.1.2.2 pgoyette }
1805 1.1.1.1.2.2 pgoyette
1806 1.1.1.1.2.2 pgoyette sk_X509_free(validsigners);
1807 1.1.1.1.2.2 pgoyette X509_STORE_free(store);
1808 1.1.1.1.2.2 pgoyette PKCS7_free(p7);
1809 1.1.1.1.2.2 pgoyette return secure;
1810 1.1.1.1.2.2 pgoyette }
1811 1.1.1.1.2.2 pgoyette
1812 1.1.1.1.2.2 pgoyette /** write unsigned root anchor file, a 5011 revoked tp */
1813 1.1.1.1.2.2 pgoyette static void
1814 1.1.1.1.2.2 pgoyette write_unsigned_root(const char* root_anchor_file)
1815 1.1.1.1.2.2 pgoyette {
1816 1.1.1.1.2.2 pgoyette FILE* out;
1817 1.1.1.1.2.2 pgoyette time_t now = time(NULL);
1818 1.1.1.1.2.2 pgoyette out = fopen(root_anchor_file, "w");
1819 1.1.1.1.2.2 pgoyette if(!out) {
1820 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
1821 1.1.1.1.2.2 pgoyette return;
1822 1.1.1.1.2.2 pgoyette }
1823 1.1.1.1.2.2 pgoyette if(fprintf(out, "; autotrust trust anchor file\n"
1824 1.1.1.1.2.2 pgoyette ";;REVOKED\n"
1825 1.1.1.1.2.2 pgoyette ";;id: . 1\n"
1826 1.1.1.1.2.2 pgoyette "; This file was written by unbound-anchor on %s"
1827 1.1.1.1.2.2 pgoyette "; It indicates that the root does not use DNSSEC\n"
1828 1.1.1.1.2.2 pgoyette "; to restart DNSSEC overwrite this file with a\n"
1829 1.1.1.1.2.2 pgoyette "; valid trustanchor or (empty-it and run unbound-anchor)\n"
1830 1.1.1.1.2.2 pgoyette , ctime(&now)) < 0) {
1831 1.1.1.1.2.2 pgoyette if(verb) printf("failed to write 'unsigned' to %s\n",
1832 1.1.1.1.2.2 pgoyette root_anchor_file);
1833 1.1.1.1.2.2 pgoyette if(verb && errno != 0) printf("%s\n", strerror(errno));
1834 1.1.1.1.2.2 pgoyette }
1835 1.1.1.1.2.2 pgoyette fflush(out);
1836 1.1.1.1.2.2 pgoyette #ifdef HAVE_FSYNC
1837 1.1.1.1.2.2 pgoyette fsync(fileno(out));
1838 1.1.1.1.2.2 pgoyette #else
1839 1.1.1.1.2.2 pgoyette FlushFileBuffers((HANDLE)_fileno(out));
1840 1.1.1.1.2.2 pgoyette #endif
1841 1.1.1.1.2.2 pgoyette fclose(out);
1842 1.1.1.1.2.2 pgoyette }
1843 1.1.1.1.2.2 pgoyette
1844 1.1.1.1.2.2 pgoyette /** write root anchor file */
1845 1.1.1.1.2.2 pgoyette static void
1846 1.1.1.1.2.2 pgoyette write_root_anchor(const char* root_anchor_file, BIO* ds)
1847 1.1.1.1.2.2 pgoyette {
1848 1.1.1.1.2.2 pgoyette char* pp = NULL;
1849 1.1.1.1.2.2 pgoyette int len;
1850 1.1.1.1.2.2 pgoyette FILE* out;
1851 1.1.1.1.2.2 pgoyette (void)BIO_seek(ds, 0);
1852 1.1.1.1.2.2 pgoyette len = BIO_get_mem_data(ds, &pp);
1853 1.1.1.1.2.2 pgoyette if(!len || !pp) {
1854 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
1855 1.1.1.1.2.2 pgoyette return;
1856 1.1.1.1.2.2 pgoyette }
1857 1.1.1.1.2.2 pgoyette out = fopen(root_anchor_file, "w");
1858 1.1.1.1.2.2 pgoyette if(!out) {
1859 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
1860 1.1.1.1.2.2 pgoyette return;
1861 1.1.1.1.2.2 pgoyette }
1862 1.1.1.1.2.2 pgoyette if(fwrite(pp, (size_t)len, 1, out) != 1) {
1863 1.1.1.1.2.2 pgoyette if(verb) printf("failed to write all data to %s\n",
1864 1.1.1.1.2.2 pgoyette root_anchor_file);
1865 1.1.1.1.2.2 pgoyette if(verb && errno != 0) printf("%s\n", strerror(errno));
1866 1.1.1.1.2.2 pgoyette }
1867 1.1.1.1.2.2 pgoyette fflush(out);
1868 1.1.1.1.2.2 pgoyette #ifdef HAVE_FSYNC
1869 1.1.1.1.2.2 pgoyette fsync(fileno(out));
1870 1.1.1.1.2.2 pgoyette #else
1871 1.1.1.1.2.2 pgoyette FlushFileBuffers((HANDLE)_fileno(out));
1872 1.1.1.1.2.2 pgoyette #endif
1873 1.1.1.1.2.2 pgoyette fclose(out);
1874 1.1.1.1.2.2 pgoyette }
1875 1.1.1.1.2.2 pgoyette
1876 1.1.1.1.2.2 pgoyette /** Perform the verification and update of the trustanchor file */
1877 1.1.1.1.2.2 pgoyette static void
1878 1.1.1.1.2.2 pgoyette verify_and_update_anchor(const char* root_anchor_file, BIO* xml, BIO* p7s,
1879 1.1.1.1.2.2 pgoyette STACK_OF(X509)* cert, const char* p7signer)
1880 1.1.1.1.2.2 pgoyette {
1881 1.1.1.1.2.2 pgoyette BIO* ds;
1882 1.1.1.1.2.2 pgoyette
1883 1.1.1.1.2.2 pgoyette /* verify xml file */
1884 1.1.1.1.2.2 pgoyette if(!verify_p7sig(xml, p7s, cert, p7signer)) {
1885 1.1.1.1.2.2 pgoyette printf("the PKCS7 signature failed\n");
1886 1.1.1.1.2.2 pgoyette exit(0);
1887 1.1.1.1.2.2 pgoyette }
1888 1.1.1.1.2.2 pgoyette
1889 1.1.1.1.2.2 pgoyette /* parse the xml file into DS records */
1890 1.1.1.1.2.2 pgoyette ds = xml_parse(xml, time(NULL));
1891 1.1.1.1.2.2 pgoyette if(!ds) {
1892 1.1.1.1.2.2 pgoyette /* the root zone is unsigned now */
1893 1.1.1.1.2.2 pgoyette write_unsigned_root(root_anchor_file);
1894 1.1.1.1.2.2 pgoyette } else {
1895 1.1.1.1.2.2 pgoyette /* reinstate 5011 tracking */
1896 1.1.1.1.2.2 pgoyette write_root_anchor(root_anchor_file, ds);
1897 1.1.1.1.2.2 pgoyette }
1898 1.1.1.1.2.2 pgoyette BIO_free(ds);
1899 1.1.1.1.2.2 pgoyette }
1900 1.1.1.1.2.2 pgoyette
1901 1.1.1.1.2.2 pgoyette #ifdef USE_WINSOCK
1902 1.1.1.1.2.2 pgoyette static void do_wsa_cleanup(void) { WSACleanup(); }
1903 1.1.1.1.2.2 pgoyette #endif
1904 1.1.1.1.2.2 pgoyette
1905 1.1.1.1.2.2 pgoyette /** perform actual certupdate work */
1906 1.1.1.1.2.2 pgoyette static int
1907 1.1.1.1.2.2 pgoyette do_certupdate(const char* root_anchor_file, const char* root_cert_file,
1908 1.1.1.1.2.2 pgoyette const char* urlname, const char* xmlname, const char* p7sname,
1909 1.1.1.1.2.2 pgoyette const char* p7signer, const char* res_conf, const char* root_hints,
1910 1.1.1.1.2.2 pgoyette const char* debugconf, int ip4only, int ip6only, int port,
1911 1.1.1.1.2.2 pgoyette struct ub_result* dnskey)
1912 1.1.1.1.2.2 pgoyette {
1913 1.1.1.1.2.2 pgoyette STACK_OF(X509)* cert;
1914 1.1.1.1.2.2 pgoyette BIO *xml, *p7s;
1915 1.1.1.1.2.2 pgoyette struct ip_list* ip_list = NULL;
1916 1.1.1.1.2.2 pgoyette
1917 1.1.1.1.2.2 pgoyette /* read pem file or provide builtin */
1918 1.1.1.1.2.2 pgoyette cert = read_cert_or_builtin(root_cert_file);
1919 1.1.1.1.2.2 pgoyette
1920 1.1.1.1.2.2 pgoyette /* lookup A, AAAA for the urlname (or parse urlname if IP address) */
1921 1.1.1.1.2.2 pgoyette ip_list = resolve_name(urlname, port, res_conf, root_hints, debugconf,
1922 1.1.1.1.2.2 pgoyette ip4only, ip6only);
1923 1.1.1.1.2.2 pgoyette
1924 1.1.1.1.2.2 pgoyette #ifdef USE_WINSOCK
1925 1.1.1.1.2.2 pgoyette if(1) { /* libunbound finished, startup WSA for the https connection */
1926 1.1.1.1.2.2 pgoyette WSADATA wsa_data;
1927 1.1.1.1.2.2 pgoyette int r;
1928 1.1.1.1.2.2 pgoyette if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
1929 1.1.1.1.2.2 pgoyette if(verb) printf("WSAStartup failed: %s\n",
1930 1.1.1.1.2.2 pgoyette wsa_strerror(r));
1931 1.1.1.1.2.2 pgoyette exit(0);
1932 1.1.1.1.2.2 pgoyette }
1933 1.1.1.1.2.2 pgoyette atexit(&do_wsa_cleanup);
1934 1.1.1.1.2.2 pgoyette }
1935 1.1.1.1.2.2 pgoyette #endif
1936 1.1.1.1.2.2 pgoyette
1937 1.1.1.1.2.2 pgoyette /* fetch the necessary files over HTTPS */
1938 1.1.1.1.2.2 pgoyette xml = https(ip_list, xmlname, urlname);
1939 1.1.1.1.2.2 pgoyette p7s = https(ip_list, p7sname, urlname);
1940 1.1.1.1.2.2 pgoyette
1941 1.1.1.1.2.2 pgoyette /* verify and update the root anchor */
1942 1.1.1.1.2.2 pgoyette verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer);
1943 1.1.1.1.2.2 pgoyette if(verb) printf("success: the anchor has been updated "
1944 1.1.1.1.2.2 pgoyette "using the cert\n");
1945 1.1.1.1.2.2 pgoyette
1946 1.1.1.1.2.2 pgoyette free_file_bio(xml);
1947 1.1.1.1.2.2 pgoyette free_file_bio(p7s);
1948 1.1.1.1.2.2 pgoyette #ifndef S_SPLINT_S
1949 1.1.1.1.2.2 pgoyette sk_X509_pop_free(cert, X509_free);
1950 1.1.1.1.2.2 pgoyette #endif
1951 1.1.1.1.2.2 pgoyette ub_resolve_free(dnskey);
1952 1.1.1.1.2.2 pgoyette ip_list_free(ip_list);
1953 1.1.1.1.2.2 pgoyette return 1;
1954 1.1.1.1.2.2 pgoyette }
1955 1.1.1.1.2.2 pgoyette
1956 1.1.1.1.2.2 pgoyette /**
1957 1.1.1.1.2.2 pgoyette * Try to read the root RFC5011 autotrust anchor file,
1958 1.1.1.1.2.2 pgoyette * @param file: filename.
1959 1.1.1.1.2.2 pgoyette * @return:
1960 1.1.1.1.2.2 pgoyette * 0 if does not exist or empty
1961 1.1.1.1.2.2 pgoyette * 1 if trust-point-revoked-5011
1962 1.1.1.1.2.2 pgoyette * 2 if it is OK.
1963 1.1.1.1.2.2 pgoyette */
1964 1.1.1.1.2.2 pgoyette static int
1965 1.1.1.1.2.2 pgoyette try_read_anchor(const char* file)
1966 1.1.1.1.2.2 pgoyette {
1967 1.1.1.1.2.2 pgoyette int empty = 1;
1968 1.1.1.1.2.2 pgoyette char line[10240];
1969 1.1.1.1.2.2 pgoyette char* p;
1970 1.1.1.1.2.2 pgoyette FILE* in = fopen(file, "r");
1971 1.1.1.1.2.2 pgoyette if(!in) {
1972 1.1.1.1.2.2 pgoyette /* only if the file does not exist, can we fix it */
1973 1.1.1.1.2.2 pgoyette if(errno != ENOENT) {
1974 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", file, strerror(errno));
1975 1.1.1.1.2.2 pgoyette if(verb) printf("error: cannot access the file\n");
1976 1.1.1.1.2.2 pgoyette exit(0);
1977 1.1.1.1.2.2 pgoyette }
1978 1.1.1.1.2.2 pgoyette if(verb) printf("%s does not exist\n", file);
1979 1.1.1.1.2.2 pgoyette return 0;
1980 1.1.1.1.2.2 pgoyette }
1981 1.1.1.1.2.2 pgoyette while(fgets(line, (int)sizeof(line), in)) {
1982 1.1.1.1.2.2 pgoyette line[sizeof(line)-1] = 0;
1983 1.1.1.1.2.2 pgoyette if(strncmp(line, ";;REVOKED", 9) == 0) {
1984 1.1.1.1.2.2 pgoyette fclose(in);
1985 1.1.1.1.2.2 pgoyette if(verb) printf("%s : the trust point is revoked\n"
1986 1.1.1.1.2.2 pgoyette "and the zone is considered unsigned.\n"
1987 1.1.1.1.2.2 pgoyette "if you wish to re-enable, delete the file\n",
1988 1.1.1.1.2.2 pgoyette file);
1989 1.1.1.1.2.2 pgoyette return 1;
1990 1.1.1.1.2.2 pgoyette }
1991 1.1.1.1.2.2 pgoyette p=line;
1992 1.1.1.1.2.2 pgoyette while(*p == ' ' || *p == '\t')
1993 1.1.1.1.2.2 pgoyette p++;
1994 1.1.1.1.2.2 pgoyette if(p[0]==0 || p[0]=='\n' || p[0]==';') continue;
1995 1.1.1.1.2.2 pgoyette /* this line is a line of content */
1996 1.1.1.1.2.2 pgoyette empty = 0;
1997 1.1.1.1.2.2 pgoyette }
1998 1.1.1.1.2.2 pgoyette fclose(in);
1999 1.1.1.1.2.2 pgoyette if(empty) {
2000 1.1.1.1.2.2 pgoyette if(verb) printf("%s is empty\n", file);
2001 1.1.1.1.2.2 pgoyette return 0;
2002 1.1.1.1.2.2 pgoyette }
2003 1.1.1.1.2.2 pgoyette if(verb) printf("%s has content\n", file);
2004 1.1.1.1.2.2 pgoyette return 2;
2005 1.1.1.1.2.2 pgoyette }
2006 1.1.1.1.2.2 pgoyette
2007 1.1.1.1.2.2 pgoyette /** Write the builtin root anchor to a file */
2008 1.1.1.1.2.2 pgoyette static void
2009 1.1.1.1.2.2 pgoyette write_builtin_anchor(const char* file)
2010 1.1.1.1.2.2 pgoyette {
2011 1.1.1.1.2.2 pgoyette const char* builtin_root_anchor = get_builtin_ds();
2012 1.1.1.1.2.2 pgoyette FILE* out = fopen(file, "w");
2013 1.1.1.1.2.2 pgoyette if(!out) {
2014 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", file, strerror(errno));
2015 1.1.1.1.2.2 pgoyette if(verb) printf(" could not write builtin anchor\n");
2016 1.1.1.1.2.2 pgoyette return;
2017 1.1.1.1.2.2 pgoyette }
2018 1.1.1.1.2.2 pgoyette if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
2019 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", file, strerror(errno));
2020 1.1.1.1.2.2 pgoyette if(verb) printf(" could not complete write builtin anchor\n");
2021 1.1.1.1.2.2 pgoyette }
2022 1.1.1.1.2.2 pgoyette fclose(out);
2023 1.1.1.1.2.2 pgoyette }
2024 1.1.1.1.2.2 pgoyette
2025 1.1.1.1.2.2 pgoyette /**
2026 1.1.1.1.2.2 pgoyette * Check the root anchor file.
2027 1.1.1.1.2.2 pgoyette * If does not exist, provide builtin and write file.
2028 1.1.1.1.2.2 pgoyette * If empty, provide builtin and write file.
2029 1.1.1.1.2.2 pgoyette * If trust-point-revoked-5011 file: make the program exit.
2030 1.1.1.1.2.2 pgoyette * @param root_anchor_file: filename of the root anchor.
2031 1.1.1.1.2.2 pgoyette * @param used_builtin: set to 1 if the builtin is written.
2032 1.1.1.1.2.2 pgoyette * @return 0 if trustpoint is insecure, 1 on success. Exit on failure.
2033 1.1.1.1.2.2 pgoyette */
2034 1.1.1.1.2.2 pgoyette static int
2035 1.1.1.1.2.2 pgoyette provide_builtin(const char* root_anchor_file, int* used_builtin)
2036 1.1.1.1.2.2 pgoyette {
2037 1.1.1.1.2.2 pgoyette /* try to read it */
2038 1.1.1.1.2.2 pgoyette switch(try_read_anchor(root_anchor_file))
2039 1.1.1.1.2.2 pgoyette {
2040 1.1.1.1.2.2 pgoyette case 0: /* no exist or empty */
2041 1.1.1.1.2.2 pgoyette write_builtin_anchor(root_anchor_file);
2042 1.1.1.1.2.2 pgoyette *used_builtin = 1;
2043 1.1.1.1.2.2 pgoyette break;
2044 1.1.1.1.2.2 pgoyette case 1: /* revoked tp */
2045 1.1.1.1.2.2 pgoyette return 0;
2046 1.1.1.1.2.2 pgoyette case 2: /* it is fine */
2047 1.1.1.1.2.2 pgoyette default:
2048 1.1.1.1.2.2 pgoyette break;
2049 1.1.1.1.2.2 pgoyette }
2050 1.1.1.1.2.2 pgoyette return 1;
2051 1.1.1.1.2.2 pgoyette }
2052 1.1.1.1.2.2 pgoyette
2053 1.1.1.1.2.2 pgoyette /**
2054 1.1.1.1.2.2 pgoyette * add an autotrust anchor for the root to the context
2055 1.1.1.1.2.2 pgoyette */
2056 1.1.1.1.2.2 pgoyette static void
2057 1.1.1.1.2.2 pgoyette add_5011_probe_root(struct ub_ctx* ctx, const char* root_anchor_file)
2058 1.1.1.1.2.2 pgoyette {
2059 1.1.1.1.2.2 pgoyette int r;
2060 1.1.1.1.2.2 pgoyette r = ub_ctx_set_option(ctx, "auto-trust-anchor-file:", root_anchor_file);
2061 1.1.1.1.2.2 pgoyette if(r) {
2062 1.1.1.1.2.2 pgoyette if(verb) printf("add 5011 probe to ctx: %s\n", ub_strerror(r));
2063 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
2064 1.1.1.1.2.2 pgoyette exit(0);
2065 1.1.1.1.2.2 pgoyette }
2066 1.1.1.1.2.2 pgoyette }
2067 1.1.1.1.2.2 pgoyette
2068 1.1.1.1.2.2 pgoyette /**
2069 1.1.1.1.2.2 pgoyette * Prime the root key and return the result. Exit on error.
2070 1.1.1.1.2.2 pgoyette * @param ctx: the unbound context to perform the priming with.
2071 1.1.1.1.2.2 pgoyette * @return: the result of the prime, on error it exit()s.
2072 1.1.1.1.2.2 pgoyette */
2073 1.1.1.1.2.2 pgoyette static struct ub_result*
2074 1.1.1.1.2.2 pgoyette prime_root_key(struct ub_ctx* ctx)
2075 1.1.1.1.2.2 pgoyette {
2076 1.1.1.1.2.2 pgoyette struct ub_result* res = NULL;
2077 1.1.1.1.2.2 pgoyette int r;
2078 1.1.1.1.2.2 pgoyette r = ub_resolve(ctx, ".", LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &res);
2079 1.1.1.1.2.2 pgoyette if(r) {
2080 1.1.1.1.2.2 pgoyette if(verb) printf("resolve DNSKEY: %s\n", ub_strerror(r));
2081 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
2082 1.1.1.1.2.2 pgoyette exit(0);
2083 1.1.1.1.2.2 pgoyette }
2084 1.1.1.1.2.2 pgoyette if(!res) {
2085 1.1.1.1.2.2 pgoyette if(verb) printf("out of memory\n");
2086 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
2087 1.1.1.1.2.2 pgoyette exit(0);
2088 1.1.1.1.2.2 pgoyette }
2089 1.1.1.1.2.2 pgoyette return res;
2090 1.1.1.1.2.2 pgoyette }
2091 1.1.1.1.2.2 pgoyette
2092 1.1.1.1.2.2 pgoyette /** see if ADDPEND keys exist in autotrust file (if possible) */
2093 1.1.1.1.2.2 pgoyette static int
2094 1.1.1.1.2.2 pgoyette read_if_pending_keys(const char* file)
2095 1.1.1.1.2.2 pgoyette {
2096 1.1.1.1.2.2 pgoyette FILE* in = fopen(file, "r");
2097 1.1.1.1.2.2 pgoyette char line[8192];
2098 1.1.1.1.2.2 pgoyette if(!in) {
2099 1.1.1.1.2.2 pgoyette if(verb>=2) printf("%s: %s\n", file, strerror(errno));
2100 1.1.1.1.2.2 pgoyette return 0;
2101 1.1.1.1.2.2 pgoyette }
2102 1.1.1.1.2.2 pgoyette while(fgets(line, (int)sizeof(line), in)) {
2103 1.1.1.1.2.2 pgoyette if(line[0]==';') continue;
2104 1.1.1.1.2.2 pgoyette if(strstr(line, "[ ADDPEND ]")) {
2105 1.1.1.1.2.2 pgoyette fclose(in);
2106 1.1.1.1.2.2 pgoyette if(verb) printf("RFC5011-state has ADDPEND keys\n");
2107 1.1.1.1.2.2 pgoyette return 1;
2108 1.1.1.1.2.2 pgoyette }
2109 1.1.1.1.2.2 pgoyette }
2110 1.1.1.1.2.2 pgoyette fclose(in);
2111 1.1.1.1.2.2 pgoyette return 0;
2112 1.1.1.1.2.2 pgoyette }
2113 1.1.1.1.2.2 pgoyette
2114 1.1.1.1.2.2 pgoyette /** read last successful probe time from autotrust file (if possible) */
2115 1.1.1.1.2.2 pgoyette static int32_t
2116 1.1.1.1.2.2 pgoyette read_last_success_time(const char* file)
2117 1.1.1.1.2.2 pgoyette {
2118 1.1.1.1.2.2 pgoyette FILE* in = fopen(file, "r");
2119 1.1.1.1.2.2 pgoyette char line[1024];
2120 1.1.1.1.2.2 pgoyette if(!in) {
2121 1.1.1.1.2.2 pgoyette if(verb) printf("%s: %s\n", file, strerror(errno));
2122 1.1.1.1.2.2 pgoyette return 0;
2123 1.1.1.1.2.2 pgoyette }
2124 1.1.1.1.2.2 pgoyette while(fgets(line, (int)sizeof(line), in)) {
2125 1.1.1.1.2.2 pgoyette if(strncmp(line, ";;last_success: ", 16) == 0) {
2126 1.1.1.1.2.2 pgoyette char* e;
2127 1.1.1.1.2.2 pgoyette time_t x = (unsigned int)strtol(line+16, &e, 10);
2128 1.1.1.1.2.2 pgoyette fclose(in);
2129 1.1.1.1.2.2 pgoyette if(line+16 == e) {
2130 1.1.1.1.2.2 pgoyette if(verb) printf("failed to parse "
2131 1.1.1.1.2.2 pgoyette "last_success probe time\n");
2132 1.1.1.1.2.2 pgoyette return 0;
2133 1.1.1.1.2.2 pgoyette }
2134 1.1.1.1.2.2 pgoyette if(verb) printf("last successful probe: %s", ctime(&x));
2135 1.1.1.1.2.2 pgoyette return (int32_t)x;
2136 1.1.1.1.2.2 pgoyette }
2137 1.1.1.1.2.2 pgoyette }
2138 1.1.1.1.2.2 pgoyette fclose(in);
2139 1.1.1.1.2.2 pgoyette if(verb) printf("no last_success probe time in anchor file\n");
2140 1.1.1.1.2.2 pgoyette return 0;
2141 1.1.1.1.2.2 pgoyette }
2142 1.1.1.1.2.2 pgoyette
2143 1.1.1.1.2.2 pgoyette /**
2144 1.1.1.1.2.2 pgoyette * Read autotrust 5011 probe file and see if the date
2145 1.1.1.1.2.2 pgoyette * compared to the current date allows a certupdate.
2146 1.1.1.1.2.2 pgoyette * If the last successful probe was recent then 5011 cannot be behind,
2147 1.1.1.1.2.2 pgoyette * and the failure cannot be solved with a certupdate.
2148 1.1.1.1.2.2 pgoyette * The debugconf is to validation-override the date for testing.
2149 1.1.1.1.2.2 pgoyette * @param root_anchor_file: filename of root key
2150 1.1.1.1.2.2 pgoyette * @return true if certupdate is ok.
2151 1.1.1.1.2.2 pgoyette */
2152 1.1.1.1.2.2 pgoyette static int
2153 1.1.1.1.2.2 pgoyette probe_date_allows_certupdate(const char* root_anchor_file)
2154 1.1.1.1.2.2 pgoyette {
2155 1.1.1.1.2.2 pgoyette int has_pending_keys = read_if_pending_keys(root_anchor_file);
2156 1.1.1.1.2.2 pgoyette int32_t last_success = read_last_success_time(root_anchor_file);
2157 1.1.1.1.2.2 pgoyette int32_t now = (int32_t)time(NULL);
2158 1.1.1.1.2.2 pgoyette int32_t leeway = 30 * 24 * 3600; /* 30 days leeway */
2159 1.1.1.1.2.2 pgoyette /* if the date is before 2010-07-15:00.00.00 then the root has not
2160 1.1.1.1.2.2 pgoyette * been signed yet, and thus we refuse to take action. */
2161 1.1.1.1.2.2 pgoyette if(time(NULL) < xml_convertdate("2010-07-15T00:00:00")) {
2162 1.1.1.1.2.2 pgoyette if(verb) printf("the date is before the root was first signed,"
2163 1.1.1.1.2.2 pgoyette " please correct the clock\n");
2164 1.1.1.1.2.2 pgoyette return 0;
2165 1.1.1.1.2.2 pgoyette }
2166 1.1.1.1.2.2 pgoyette if(last_success == 0)
2167 1.1.1.1.2.2 pgoyette return 1; /* no probe time */
2168 1.1.1.1.2.2 pgoyette if(has_pending_keys)
2169 1.1.1.1.2.2 pgoyette return 1; /* key in ADDPEND state, a previous probe has
2170 1.1.1.1.2.2 pgoyette inserted that, and it was present in all recent probes,
2171 1.1.1.1.2.2 pgoyette but it has not become active. The 30 day timer may not have
2172 1.1.1.1.2.2 pgoyette expired, but we know(for sure) there is a rollover going on.
2173 1.1.1.1.2.2 pgoyette If we only managed to pickup the new key on its last day
2174 1.1.1.1.2.2 pgoyette of announcement (for example) this can happen. */
2175 1.1.1.1.2.2 pgoyette if(now - last_success < 0) {
2176 1.1.1.1.2.2 pgoyette if(verb) printf("the last successful probe is in the future,"
2177 1.1.1.1.2.2 pgoyette " clock was modified\n");
2178 1.1.1.1.2.2 pgoyette return 0;
2179 1.1.1.1.2.2 pgoyette }
2180 1.1.1.1.2.2 pgoyette if(now - last_success >= leeway) {
2181 1.1.1.1.2.2 pgoyette if(verb) printf("the last successful probe was more than 30 "
2182 1.1.1.1.2.2 pgoyette "days ago\n");
2183 1.1.1.1.2.2 pgoyette return 1;
2184 1.1.1.1.2.2 pgoyette }
2185 1.1.1.1.2.2 pgoyette if(verb) printf("the last successful probe is recent\n");
2186 1.1.1.1.2.2 pgoyette return 0;
2187 1.1.1.1.2.2 pgoyette }
2188 1.1.1.1.2.2 pgoyette
2189 1.1.1.1.2.2 pgoyette /** perform the unbound-anchor work */
2190 1.1.1.1.2.2 pgoyette static int
2191 1.1.1.1.2.2 pgoyette do_root_update_work(const char* root_anchor_file, const char* root_cert_file,
2192 1.1.1.1.2.2 pgoyette const char* urlname, const char* xmlname, const char* p7sname,
2193 1.1.1.1.2.2 pgoyette const char* p7signer, const char* res_conf, const char* root_hints,
2194 1.1.1.1.2.2 pgoyette const char* debugconf, int ip4only, int ip6only, int force, int port)
2195 1.1.1.1.2.2 pgoyette {
2196 1.1.1.1.2.2 pgoyette struct ub_ctx* ctx;
2197 1.1.1.1.2.2 pgoyette struct ub_result* dnskey;
2198 1.1.1.1.2.2 pgoyette int used_builtin = 0;
2199 1.1.1.1.2.2 pgoyette
2200 1.1.1.1.2.2 pgoyette /* see if builtin rootanchor needs to be provided, or if
2201 1.1.1.1.2.2 pgoyette * rootanchor is 'revoked-trust-point' */
2202 1.1.1.1.2.2 pgoyette if(!provide_builtin(root_anchor_file, &used_builtin))
2203 1.1.1.1.2.2 pgoyette return 0;
2204 1.1.1.1.2.2 pgoyette
2205 1.1.1.1.2.2 pgoyette /* make unbound context with 5011-probe for root anchor,
2206 1.1.1.1.2.2 pgoyette * and probe . DNSKEY */
2207 1.1.1.1.2.2 pgoyette ctx = create_unbound_context(res_conf, root_hints, debugconf,
2208 1.1.1.1.2.2 pgoyette ip4only, ip6only);
2209 1.1.1.1.2.2 pgoyette add_5011_probe_root(ctx, root_anchor_file);
2210 1.1.1.1.2.2 pgoyette dnskey = prime_root_key(ctx);
2211 1.1.1.1.2.2 pgoyette ub_ctx_delete(ctx);
2212 1.1.1.1.2.2 pgoyette
2213 1.1.1.1.2.2 pgoyette /* if secure: exit */
2214 1.1.1.1.2.2 pgoyette if(dnskey->secure && !force) {
2215 1.1.1.1.2.2 pgoyette if(verb) printf("success: the anchor is ok\n");
2216 1.1.1.1.2.2 pgoyette ub_resolve_free(dnskey);
2217 1.1.1.1.2.2 pgoyette return used_builtin;
2218 1.1.1.1.2.2 pgoyette }
2219 1.1.1.1.2.2 pgoyette if(force && verb) printf("debug cert update forced\n");
2220 1.1.1.1.2.2 pgoyette
2221 1.1.1.1.2.2 pgoyette /* if not (and NOERROR): check date and do certupdate */
2222 1.1.1.1.2.2 pgoyette if((dnskey->rcode == 0 &&
2223 1.1.1.1.2.2 pgoyette probe_date_allows_certupdate(root_anchor_file)) || force) {
2224 1.1.1.1.2.2 pgoyette if(do_certupdate(root_anchor_file, root_cert_file, urlname,
2225 1.1.1.1.2.2 pgoyette xmlname, p7sname, p7signer, res_conf, root_hints,
2226 1.1.1.1.2.2 pgoyette debugconf, ip4only, ip6only, port, dnskey))
2227 1.1.1.1.2.2 pgoyette return 1;
2228 1.1.1.1.2.2 pgoyette return used_builtin;
2229 1.1.1.1.2.2 pgoyette }
2230 1.1.1.1.2.2 pgoyette if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n");
2231 1.1.1.1.2.2 pgoyette ub_resolve_free(dnskey);
2232 1.1.1.1.2.2 pgoyette return used_builtin;
2233 1.1.1.1.2.2 pgoyette }
2234 1.1.1.1.2.2 pgoyette
2235 1.1.1.1.2.2 pgoyette /** getopt global, in case header files fail to declare it. */
2236 1.1.1.1.2.2 pgoyette extern int optind;
2237 1.1.1.1.2.2 pgoyette /** getopt global, in case header files fail to declare it. */
2238 1.1.1.1.2.2 pgoyette extern char* optarg;
2239 1.1.1.1.2.2 pgoyette
2240 1.1.1.1.2.2 pgoyette /** Main routine for unbound-anchor */
2241 1.1.1.1.2.2 pgoyette int main(int argc, char* argv[])
2242 1.1.1.1.2.2 pgoyette {
2243 1.1.1.1.2.2 pgoyette int c;
2244 1.1.1.1.2.2 pgoyette const char* root_anchor_file = ROOT_ANCHOR_FILE;
2245 1.1.1.1.2.2 pgoyette const char* root_cert_file = ROOT_CERT_FILE;
2246 1.1.1.1.2.2 pgoyette const char* urlname = URLNAME;
2247 1.1.1.1.2.2 pgoyette const char* xmlname = XMLNAME;
2248 1.1.1.1.2.2 pgoyette const char* p7sname = P7SNAME;
2249 1.1.1.1.2.2 pgoyette const char* p7signer = P7SIGNER;
2250 1.1.1.1.2.2 pgoyette const char* res_conf = NULL;
2251 1.1.1.1.2.2 pgoyette const char* root_hints = NULL;
2252 1.1.1.1.2.2 pgoyette const char* debugconf = NULL;
2253 1.1.1.1.2.2 pgoyette int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT;
2254 1.1.1.1.2.2 pgoyette /* parse the options */
2255 1.1.1.1.2.2 pgoyette while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) {
2256 1.1.1.1.2.2 pgoyette switch(c) {
2257 1.1.1.1.2.2 pgoyette case 'l':
2258 1.1.1.1.2.2 pgoyette dolist = 1;
2259 1.1.1.1.2.2 pgoyette break;
2260 1.1.1.1.2.2 pgoyette case '4':
2261 1.1.1.1.2.2 pgoyette ip4only = 1;
2262 1.1.1.1.2.2 pgoyette break;
2263 1.1.1.1.2.2 pgoyette case '6':
2264 1.1.1.1.2.2 pgoyette ip6only = 1;
2265 1.1.1.1.2.2 pgoyette break;
2266 1.1.1.1.2.2 pgoyette case 'a':
2267 1.1.1.1.2.2 pgoyette root_anchor_file = optarg;
2268 1.1.1.1.2.2 pgoyette break;
2269 1.1.1.1.2.2 pgoyette case 'c':
2270 1.1.1.1.2.2 pgoyette root_cert_file = optarg;
2271 1.1.1.1.2.2 pgoyette break;
2272 1.1.1.1.2.2 pgoyette case 'u':
2273 1.1.1.1.2.2 pgoyette urlname = optarg;
2274 1.1.1.1.2.2 pgoyette break;
2275 1.1.1.1.2.2 pgoyette case 'x':
2276 1.1.1.1.2.2 pgoyette xmlname = optarg;
2277 1.1.1.1.2.2 pgoyette break;
2278 1.1.1.1.2.2 pgoyette case 's':
2279 1.1.1.1.2.2 pgoyette p7sname = optarg;
2280 1.1.1.1.2.2 pgoyette break;
2281 1.1.1.1.2.2 pgoyette case 'n':
2282 1.1.1.1.2.2 pgoyette p7signer = optarg;
2283 1.1.1.1.2.2 pgoyette break;
2284 1.1.1.1.2.2 pgoyette case 'f':
2285 1.1.1.1.2.2 pgoyette res_conf = optarg;
2286 1.1.1.1.2.2 pgoyette break;
2287 1.1.1.1.2.2 pgoyette case 'r':
2288 1.1.1.1.2.2 pgoyette root_hints = optarg;
2289 1.1.1.1.2.2 pgoyette break;
2290 1.1.1.1.2.2 pgoyette case 'C':
2291 1.1.1.1.2.2 pgoyette debugconf = optarg;
2292 1.1.1.1.2.2 pgoyette break;
2293 1.1.1.1.2.2 pgoyette case 'F':
2294 1.1.1.1.2.2 pgoyette force = 1;
2295 1.1.1.1.2.2 pgoyette break;
2296 1.1.1.1.2.2 pgoyette case 'P':
2297 1.1.1.1.2.2 pgoyette port = atoi(optarg);
2298 1.1.1.1.2.2 pgoyette break;
2299 1.1.1.1.2.2 pgoyette case 'v':
2300 1.1.1.1.2.2 pgoyette verb++;
2301 1.1.1.1.2.2 pgoyette break;
2302 1.1.1.1.2.2 pgoyette case '?':
2303 1.1.1.1.2.2 pgoyette case 'h':
2304 1.1.1.1.2.2 pgoyette default:
2305 1.1.1.1.2.2 pgoyette usage();
2306 1.1.1.1.2.2 pgoyette }
2307 1.1.1.1.2.2 pgoyette }
2308 1.1.1.1.2.2 pgoyette argc -= optind;
2309 1.1.1.1.2.2 pgoyette argv += optind;
2310 1.1.1.1.2.2 pgoyette if(argc != 0)
2311 1.1.1.1.2.2 pgoyette usage();
2312 1.1.1.1.2.2 pgoyette
2313 1.1.1.1.2.2 pgoyette ERR_load_crypto_strings();
2314 1.1.1.1.2.2 pgoyette ERR_load_SSL_strings();
2315 1.1.1.1.2.2 pgoyette OpenSSL_add_all_algorithms();
2316 1.1.1.1.2.2 pgoyette (void)SSL_library_init();
2317 1.1.1.1.2.2 pgoyette
2318 1.1.1.1.2.2 pgoyette if(dolist) do_list_builtin();
2319 1.1.1.1.2.2 pgoyette
2320 1.1.1.1.2.2 pgoyette return do_root_update_work(root_anchor_file, root_cert_file, urlname,
2321 1.1.1.1.2.2 pgoyette xmlname, p7sname, p7signer, res_conf, root_hints, debugconf,
2322 1.1.1.1.2.2 pgoyette ip4only, ip6only, force, port);
2323 1.1.1.1.2.2 pgoyette }
2324