1238106Sdes/*
2238106Sdes * unbound-anchor.c - update the root anchor if necessary.
3238106Sdes *
4238106Sdes * Copyright (c) 2010, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file checks to see that the current 5011 keys work to prime the
40307729Sdes * current root anchor.  If not a certificate is used to update the anchor,
41307729Sdes * with RFC7958 https xml fetch.
42238106Sdes *
43238106Sdes * This is a concept solution for distribution of the DNSSEC root
44238106Sdes * trust anchor.  It is a small tool, called "unbound-anchor", that
45238106Sdes * runs before the main validator starts.  I.e. in the init script:
46238106Sdes * unbound-anchor; unbound.  Thus it is meant to run at system boot time.
47238106Sdes *
48238106Sdes * Management-Abstract:
49238106Sdes *    * first run: fill root.key file with hardcoded DS record.
50238106Sdes *    * mostly: use RFC5011 tracking, quick . DNSKEY UDP query.
51307729Sdes *    * failover: use RFC7958 builtin certificate, do https and update.
52238106Sdes * Special considerations:
53238106Sdes *    * 30-days RFC5011 timer saves a lot of https traffic.
54238106Sdes *    * DNSKEY probe must be NOERROR, saves a lot of https traffic.
55238106Sdes *    * fail if clock before sign date of the root, if cert expired.
56238106Sdes *    * if the root goes back to unsigned, deals with it.
57238106Sdes *
58238106Sdes * It has hardcoded the root DS anchors and the ICANN CA root certificate.
59238106Sdes * It allows with options to override those.  It also takes root-hints (it
60238106Sdes * has to do a DNS resolve), and also has hardcoded defaults for those.
61238106Sdes *
62238106Sdes * Once it starts, just before the validator starts, it quickly checks if
63238106Sdes * the root anchor file needs to be updated.  First it tries to use
64238106Sdes * RFC5011-tracking of the root key.  If that fails (and for 30-days since
65238106Sdes * last successful probe), then it attempts to update using the
66238106Sdes * certificate.  So most of the time, the RFC5011 tracking will work fine,
67238106Sdes * and within a couple milliseconds, the main daemon can start.  It will
68238106Sdes * have only probed the . DNSKEY, not done expensive https transfers on the
69238106Sdes * root infrastructure.
70238106Sdes *
71238106Sdes * If there is no root key in the root.key file, it bootstraps the
72238106Sdes * RFC5011-tracking with its builtin DS anchors; if that fails it
73238106Sdes * bootstraps the RFC5011-tracking using the certificate.  (again to avoid
74238106Sdes * https, and it is also faster).
75238106Sdes *
76238106Sdes * It uses the XML file by converting it to DS records and writing that to the
77238106Sdes * key file.  Unbound can detect that the 'special comments' are gone, and
78238106Sdes * the file contains a list of normal DNSKEY/DS records, and uses that to
79238106Sdes * bootstrap 5011 (the KSK is made VALID).
80238106Sdes *
81307729Sdes * The certificate RFC7958 update is done by fetching root-anchors.xml and
82238106Sdes * root-anchors.p7s via SSL.  The HTTPS certificate can be logged but is
83238106Sdes * not validated (https for channel security; the security comes from the
84238106Sdes * certificate).  The 'data.iana.org' domain name A and AAAA are resolved
85238106Sdes * without DNSSEC.  It tries a random IP until the transfer succeeds.  It
86238106Sdes * then checks the p7s signature.
87238106Sdes *
88238106Sdes * On any failure, it leaves the root key file untouched.  The main
89238106Sdes * validator has to cope with it, it cannot fix things (So a failure does
90238106Sdes * not go 'without DNSSEC', no downgrade).  If it used its builtin stuff or
91238106Sdes * did the https, it exits with an exit code, so that this can trigger the
92238106Sdes * init script to log the event and potentially alert the operator that can
93238106Sdes * do a manual check.
94238106Sdes *
95238106Sdes * The date is also checked.  Before 2010-07-15 is a failure (root not
96238106Sdes * signed yet; avoids attacks on system clock).  The
97238106Sdes * last-successful-RFC5011-probe (if available) has to be more than 30 days
98238106Sdes * in the past (otherwise, RFC5011 should have worked).  This keeps
99292206Sdes * unnecessary https traffic down.  If the main certificate is expired, it
100238106Sdes * fails.
101238106Sdes *
102238106Sdes * The dates on the keys in the xml are checked (uses the libexpat xml
103238106Sdes * parser), only the valid ones are used to re-enstate RFC5011 tracking.
104238106Sdes * If 0 keys are valid, the zone has gone to insecure (a special marker is
105238106Sdes * written in the keyfile that tells the main validator daemon the zone is
106238106Sdes * insecure).
107238106Sdes *
108238106Sdes * Only the root ICANN CA is shipped, not the intermediate ones.  The
109238106Sdes * intermediate CAs are included in the p7s file that was downloaded.  (the
110238106Sdes * root cert is valid to 2028 and the intermediate to 2014, today).
111238106Sdes *
112238106Sdes * Obviously, the tool also has options so the operator can provide a new
113238106Sdes * keyfile, a new certificate and new URLs, and fresh root hints.  By
114238106Sdes * default it logs nothing on failure and success; it 'just works'.
115238106Sdes *
116238106Sdes */
117238106Sdes
118238106Sdes#include "config.h"
119238106Sdes#include "libunbound/unbound.h"
120287917Sdes#include "sldns/rrdef.h"
121289063Sdes#include "sldns/parseutil.h"
122238106Sdes#include <expat.h>
123238106Sdes#ifndef HAVE_EXPAT_H
124238106Sdes#error "need libexpat to parse root-anchors.xml file."
125238106Sdes#endif
126238106Sdes#ifdef HAVE_GETOPT_H
127238106Sdes#include <getopt.h>
128238106Sdes#endif
129238106Sdes#ifdef HAVE_OPENSSL_SSL_H
130238106Sdes#include <openssl/ssl.h>
131238106Sdes#endif
132238106Sdes#ifdef HAVE_OPENSSL_ERR_H
133238106Sdes#include <openssl/err.h>
134238106Sdes#endif
135238106Sdes#ifdef HAVE_OPENSSL_RAND_H
136238106Sdes#include <openssl/rand.h>
137238106Sdes#endif
138238106Sdes#include <openssl/x509.h>
139249141Sdes#include <openssl/x509v3.h>
140238106Sdes#include <openssl/pem.h>
141238106Sdes
142238106Sdes/** name of server in URL to fetch HTTPS from */
143238106Sdes#define URLNAME "data.iana.org"
144238106Sdes/** path on HTTPS server to xml file */
145238106Sdes#define XMLNAME "root-anchors/root-anchors.xml"
146238106Sdes/** path on HTTPS server to p7s file */
147238106Sdes#define P7SNAME "root-anchors/root-anchors.p7s"
148249141Sdes/** name of the signer of the certificate */
149249141Sdes#define P7SIGNER "dnssec@iana.org"
150238106Sdes/** port number for https access */
151238106Sdes#define HTTPS_PORT 443
152238106Sdes
153238106Sdes#ifdef USE_WINSOCK
154238106Sdes/* sneakily reuse the the wsa_strerror function, on windows */
155238106Sdeschar* wsa_strerror(int err);
156238106Sdes#endif
157238106Sdes
158369939Sgit2svnstatic const char ICANN_UPDATE_CA[] =
159369939Sgit2svn	/* The ICANN CA fetched at 24 Sep 2010.  Valid to 2028 */
160369939Sgit2svn	"-----BEGIN CERTIFICATE-----\n"
161369939Sgit2svn	"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
162369939Sgit2svn	"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
163369939Sgit2svn	"BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n"
164369939Sgit2svn	"DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n"
165369939Sgit2svn	"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n"
166369939Sgit2svn	"MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n"
167369939Sgit2svn	"cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n"
168369939Sgit2svn	"G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n"
169369939Sgit2svn	"ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n"
170369939Sgit2svn	"paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n"
171369939Sgit2svn	"MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n"
172369939Sgit2svn	"iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
173369939Sgit2svn	"Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n"
174369939Sgit2svn	"DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n"
175369939Sgit2svn	"6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n"
176369939Sgit2svn	"2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n"
177369939Sgit2svn	"15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
178369939Sgit2svn	"0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
179369939Sgit2svn	"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
180369939Sgit2svn	"-----END CERTIFICATE-----\n";
181369939Sgit2svn
182369939Sgit2svnstatic const char DS_TRUST_ANCHOR[] =
183369939Sgit2svn	/* The anchors must start on a new line with ". IN DS and end with \n"[;]
184369939Sgit2svn	 * because the makedist script greps on the source here */
185369939Sgit2svn	/* anchor 20326 is from 2017 */
186369939Sgit2svn". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n";
187369939Sgit2svn
188238106Sdes/** verbosity for this application */
189238106Sdesstatic int verb = 0;
190238106Sdes
191238106Sdes/** list of IP addresses */
192238106Sdesstruct ip_list {
193238106Sdes	/** next in list */
194238106Sdes	struct ip_list* next;
195238106Sdes	/** length of addr */
196238106Sdes	socklen_t len;
197238106Sdes	/** address ready to connect to */
198238106Sdes	struct sockaddr_storage addr;
199238106Sdes	/** has the address been used */
200238106Sdes	int used;
201238106Sdes};
202238106Sdes
203238106Sdes/** Give unbound-anchor usage, and exit (1). */
204238106Sdesstatic void
205307729Sdesusage(void)
206238106Sdes{
207356345Scy	printf("Usage:	local-unbound-anchor [opts]\n");
208238106Sdes	printf("	Setup or update root anchor. "
209238106Sdes		"Most options have defaults.\n");
210238106Sdes	printf("	Run this program before you start the validator.\n");
211238106Sdes	printf("\n");
212238106Sdes	printf("	The anchor and cert have default builtin content\n");
213238106Sdes	printf("	if the file does not exist or is empty.\n");
214238106Sdes	printf("\n");
215238106Sdes	printf("-a file		root key file, default %s\n", ROOT_ANCHOR_FILE);
216238106Sdes	printf("		The key is input and output for this tool.\n");
217238106Sdes	printf("-c file		cert file, default %s\n", ROOT_CERT_FILE);
218238106Sdes	printf("-l		list builtin key and cert on stdout\n");
219238106Sdes	printf("-u name		server in https url, default %s\n", URLNAME);
220366095Scy	printf("-S		do not use SNI for the https connection\n");
221238106Sdes	printf("-x path		pathname to xml in url, default %s\n", XMLNAME);
222238106Sdes	printf("-s path		pathname to p7s in url, default %s\n", P7SNAME);
223249141Sdes	printf("-n name		signer's subject emailAddress, default %s\n", P7SIGNER);
224356345Scy	printf("-b address	source address to bind to\n");
225238106Sdes	printf("-4		work using IPv4 only\n");
226238106Sdes	printf("-6		work using IPv6 only\n");
227356345Scy	printf("-f resolv.conf	use given resolv.conf\n");
228356345Scy	printf("-r root.hints	use given root.hints\n"
229238106Sdes		"		builtin root hints are used by default\n");
230356345Scy	printf("-R		fallback from -f to root query on error\n");
231238106Sdes	printf("-v		more verbose\n");
232238106Sdes	printf("-C conf		debug, read config\n");
233238106Sdes	printf("-P port		use port for https connect, default 443\n");
234238106Sdes	printf("-F 		debug, force update with cert\n");
235238106Sdes	printf("-h		show this usage help\n");
236238106Sdes	printf("Version %s\n", PACKAGE_VERSION);
237238106Sdes	printf("BSD licensed, see LICENSE in source package for details.\n");
238238106Sdes	printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
239238106Sdes	exit(1);
240238106Sdes}
241238106Sdes
242238106Sdes/** return the built in root update certificate */
243238106Sdesstatic const char*
244238106Sdesget_builtin_cert(void)
245238106Sdes{
246369939Sgit2svn	return ICANN_UPDATE_CA;
247238106Sdes}
248238106Sdes
249238106Sdes/** return the built in root DS trust anchor */
250238106Sdesstatic const char*
251238106Sdesget_builtin_ds(void)
252238106Sdes{
253369939Sgit2svn	return DS_TRUST_ANCHOR;
254238106Sdes}
255238106Sdes
256238106Sdes/** print hex data */
257238106Sdesstatic void
258369939Sgit2svnprint_data(const char* msg, const char* data, size_t len)
259238106Sdes{
260369939Sgit2svn	size_t i;
261238106Sdes	printf("%s: ", msg);
262238106Sdes	for(i=0; i<len; i++) {
263238106Sdes		printf(" %2.2x", (unsigned char)data[i]);
264238106Sdes	}
265238106Sdes	printf("\n");
266238106Sdes}
267238106Sdes
268238106Sdes/** print ub context creation error and exit */
269238106Sdesstatic void
270238106Sdesub_ctx_error_exit(struct ub_ctx* ctx, const char* str, const char* str2)
271238106Sdes{
272238106Sdes	ub_ctx_delete(ctx);
273238106Sdes	if(str && str2 && verb) printf("%s: %s\n", str, str2);
274238106Sdes	if(verb) printf("error: could not create unbound resolver context\n");
275238106Sdes	exit(0);
276238106Sdes}
277238106Sdes
278238106Sdes/**
279238106Sdes * Create a new unbound context with the commandline settings applied
280238106Sdes */
281238106Sdesstatic struct ub_ctx*
282255586Sdescreate_unbound_context(const char* res_conf, const char* root_hints,
283356345Scy	const char* debugconf, const char* srcaddr, int ip4only, int ip6only)
284238106Sdes{
285238106Sdes	int r;
286238106Sdes	struct ub_ctx* ctx = ub_ctx_create();
287238106Sdes	if(!ctx) {
288238106Sdes		if(verb) printf("out of memory\n");
289238106Sdes		exit(0);
290238106Sdes	}
291238106Sdes	/* do not waste time and network traffic to fetch extra nameservers */
292238106Sdes	r = ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0");
293238106Sdes	if(r && verb) printf("ctx targetfetchpolicy: %s\n", ub_strerror(r));
294238106Sdes	/* read config file first, so its settings can be overridden */
295238106Sdes	if(debugconf) {
296238106Sdes		r = ub_ctx_config(ctx, debugconf);
297238106Sdes		if(r) ub_ctx_error_exit(ctx, debugconf, ub_strerror(r));
298238106Sdes	}
299238106Sdes	if(res_conf) {
300238106Sdes		r = ub_ctx_resolvconf(ctx, res_conf);
301238106Sdes		if(r) ub_ctx_error_exit(ctx, res_conf, ub_strerror(r));
302238106Sdes	}
303238106Sdes	if(root_hints) {
304238106Sdes		r = ub_ctx_set_option(ctx, "root-hints:", root_hints);
305238106Sdes		if(r) ub_ctx_error_exit(ctx, root_hints, ub_strerror(r));
306238106Sdes	}
307356345Scy	if(srcaddr) {
308356345Scy		r = ub_ctx_set_option(ctx, "outgoing-interface:", srcaddr);
309356345Scy		if(r) ub_ctx_error_exit(ctx, srcaddr, ub_strerror(r));
310356345Scy	}
311238106Sdes	if(ip4only) {
312238106Sdes		r = ub_ctx_set_option(ctx, "do-ip6:", "no");
313238106Sdes		if(r) ub_ctx_error_exit(ctx, "ip4only", ub_strerror(r));
314238106Sdes	}
315238106Sdes	if(ip6only) {
316238106Sdes		r = ub_ctx_set_option(ctx, "do-ip4:", "no");
317238106Sdes		if(r) ub_ctx_error_exit(ctx, "ip6only", ub_strerror(r));
318238106Sdes	}
319238106Sdes	return ctx;
320238106Sdes}
321238106Sdes
322238106Sdes/** printout certificate in detail */
323238106Sdesstatic void
324255586Sdesverb_cert(const char* msg, X509* x)
325238106Sdes{
326238106Sdes	if(verb == 0 || verb == 1) return;
327238106Sdes	if(verb == 2) {
328238106Sdes		if(msg) printf("%s\n", msg);
329238106Sdes		X509_print_ex_fp(stdout, x, 0, (unsigned long)-1
330238106Sdes			^(X509_FLAG_NO_SUBJECT
331238106Sdes			|X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY));
332238106Sdes		return;
333238106Sdes	}
334238106Sdes	if(msg) printf("%s\n", msg);
335238106Sdes	X509_print_fp(stdout, x);
336238106Sdes}
337238106Sdes
338238106Sdes/** printout certificates in detail */
339238106Sdesstatic void
340255586Sdesverb_certs(const char* msg, STACK_OF(X509)* sk)
341238106Sdes{
342238106Sdes	int i, num = sk_X509_num(sk);
343238106Sdes	if(verb == 0 || verb == 1) return;
344238106Sdes	for(i=0; i<num; i++) {
345238106Sdes		printf("%s (%d/%d)\n", msg, i, num);
346238106Sdes		verb_cert(NULL, sk_X509_value(sk, i));
347238106Sdes	}
348238106Sdes}
349238106Sdes
350238106Sdes/** read certificates from a PEM bio */
351238106Sdesstatic STACK_OF(X509)*
352238106Sdesread_cert_bio(BIO* bio)
353238106Sdes{
354238106Sdes	STACK_OF(X509) *sk = sk_X509_new_null();
355238106Sdes	if(!sk) {
356238106Sdes		if(verb) printf("out of memory\n");
357238106Sdes		exit(0);
358238106Sdes	}
359238106Sdes	while(!BIO_eof(bio)) {
360356345Scy		X509* x = PEM_read_bio_X509(bio, NULL, NULL, NULL);
361238106Sdes		if(x == NULL) {
362238106Sdes			if(verb) {
363238106Sdes				printf("failed to read X509\n");
364238106Sdes			 	ERR_print_errors_fp(stdout);
365238106Sdes			}
366238106Sdes			continue;
367238106Sdes		}
368238106Sdes		if(!sk_X509_push(sk, x)) {
369238106Sdes			if(verb) printf("out of memory\n");
370238106Sdes			exit(0);
371238106Sdes		}
372238106Sdes	}
373238106Sdes	return sk;
374238106Sdes}
375238106Sdes
376238106Sdes/* read the certificate file */
377238106Sdesstatic STACK_OF(X509)*
378255586Sdesread_cert_file(const char* file)
379238106Sdes{
380238106Sdes	STACK_OF(X509)* sk;
381238106Sdes	FILE* in;
382238106Sdes	int content = 0;
383238106Sdes	char buf[128];
384238106Sdes	if(file == NULL || strcmp(file, "") == 0) {
385238106Sdes		return NULL;
386238106Sdes	}
387238106Sdes	sk = sk_X509_new_null();
388238106Sdes	if(!sk) {
389238106Sdes		if(verb) printf("out of memory\n");
390238106Sdes		exit(0);
391238106Sdes	}
392238106Sdes	in = fopen(file, "r");
393238106Sdes	if(!in) {
394238106Sdes		if(verb) printf("%s: %s\n", file, strerror(errno));
395238106Sdes#ifndef S_SPLINT_S
396238106Sdes		sk_X509_pop_free(sk, X509_free);
397238106Sdes#endif
398238106Sdes		return NULL;
399238106Sdes	}
400238106Sdes	while(!feof(in)) {
401356345Scy		X509* x = PEM_read_X509(in, NULL, NULL, NULL);
402238106Sdes		if(x == NULL) {
403238106Sdes			if(verb) {
404238106Sdes				printf("failed to read X509 file\n");
405238106Sdes			 	ERR_print_errors_fp(stdout);
406238106Sdes			}
407238106Sdes			continue;
408238106Sdes		}
409238106Sdes		if(!sk_X509_push(sk, x)) {
410238106Sdes			if(verb) printf("out of memory\n");
411238106Sdes			fclose(in);
412238106Sdes			exit(0);
413238106Sdes		}
414238106Sdes		content = 1;
415238106Sdes		/* read away newline after --END CERT-- */
416238106Sdes		if(!fgets(buf, (int)sizeof(buf), in))
417238106Sdes			break;
418238106Sdes	}
419238106Sdes	fclose(in);
420238106Sdes	if(!content) {
421238106Sdes		if(verb) printf("%s is empty\n", file);
422238106Sdes#ifndef S_SPLINT_S
423238106Sdes		sk_X509_pop_free(sk, X509_free);
424238106Sdes#endif
425238106Sdes		return NULL;
426238106Sdes	}
427238106Sdes	return sk;
428238106Sdes}
429238106Sdes
430238106Sdes/** read certificates from the builtin certificate */
431238106Sdesstatic STACK_OF(X509)*
432238106Sdesread_builtin_cert(void)
433238106Sdes{
434238106Sdes	const char* builtin_cert = get_builtin_cert();
435238106Sdes	STACK_OF(X509)* sk;
436307729Sdes	BIO *bio = BIO_new_mem_buf(builtin_cert,
437238106Sdes		(int)strlen(builtin_cert));
438238106Sdes	if(!bio) {
439238106Sdes		if(verb) printf("out of memory\n");
440238106Sdes		exit(0);
441238106Sdes	}
442238106Sdes	sk = read_cert_bio(bio);
443238106Sdes	if(!sk) {
444238106Sdes		if(verb) printf("internal error, out of memory\n");
445238106Sdes		exit(0);
446238106Sdes	}
447238106Sdes	BIO_free(bio);
448238106Sdes	return sk;
449238106Sdes}
450238106Sdes
451238106Sdes/** read update cert file or use builtin */
452238106Sdesstatic STACK_OF(X509)*
453255586Sdesread_cert_or_builtin(const char* file)
454238106Sdes{
455238106Sdes	STACK_OF(X509) *sk = read_cert_file(file);
456238106Sdes	if(!sk) {
457238106Sdes		if(verb) printf("using builtin certificate\n");
458238106Sdes		sk = read_builtin_cert();
459238106Sdes	}
460238106Sdes	if(verb) printf("have %d trusted certificates\n", sk_X509_num(sk));
461238106Sdes	verb_certs("trusted certificates", sk);
462238106Sdes	return sk;
463238106Sdes}
464238106Sdes
465238106Sdesstatic void
466238106Sdesdo_list_builtin(void)
467238106Sdes{
468238106Sdes	const char* builtin_cert = get_builtin_cert();
469238106Sdes	const char* builtin_ds = get_builtin_ds();
470238106Sdes	printf("%s\n", builtin_ds);
471238106Sdes	printf("%s\n", builtin_cert);
472238106Sdes	exit(0);
473238106Sdes}
474238106Sdes
475238106Sdes/** printout IP address with message */
476238106Sdesstatic void
477255586Sdesverb_addr(const char* msg, struct ip_list* ip)
478238106Sdes{
479238106Sdes	if(verb) {
480238106Sdes		char out[100];
481238106Sdes		void* a = &((struct sockaddr_in*)&ip->addr)->sin_addr;
482238106Sdes		if(ip->len != (socklen_t)sizeof(struct sockaddr_in))
483238106Sdes			a = &((struct sockaddr_in6*)&ip->addr)->sin6_addr;
484238106Sdes
485238106Sdes		if(inet_ntop((int)((struct sockaddr_in*)&ip->addr)->sin_family,
486238106Sdes			a, out, (socklen_t)sizeof(out))==0)
487238106Sdes			printf("%s (inet_ntop error)\n", msg);
488238106Sdes		else printf("%s %s\n", msg, out);
489238106Sdes	}
490238106Sdes}
491238106Sdes
492238106Sdes/** free ip_list */
493238106Sdesstatic void
494238106Sdesip_list_free(struct ip_list* p)
495238106Sdes{
496238106Sdes	struct ip_list* np;
497238106Sdes	while(p) {
498238106Sdes		np = p->next;
499238106Sdes		free(p);
500238106Sdes		p = np;
501238106Sdes	}
502238106Sdes}
503238106Sdes
504238106Sdes/** create ip_list entry for a RR record */
505238106Sdesstatic struct ip_list*
506238106SdesRR_to_ip(int tp, char* data, int len, int port)
507238106Sdes{
508238106Sdes	struct ip_list* ip = (struct ip_list*)calloc(1, sizeof(*ip));
509238106Sdes	uint16_t p = (uint16_t)port;
510238106Sdes	if(tp == LDNS_RR_TYPE_A) {
511238106Sdes		struct sockaddr_in* sa = (struct sockaddr_in*)&ip->addr;
512238106Sdes		ip->len = (socklen_t)sizeof(*sa);
513238106Sdes		sa->sin_family = AF_INET;
514238106Sdes		sa->sin_port = (in_port_t)htons(p);
515238106Sdes		if(len != (int)sizeof(sa->sin_addr)) {
516238106Sdes			if(verb) printf("skipped badly formatted A\n");
517238106Sdes			free(ip);
518238106Sdes			return NULL;
519238106Sdes		}
520238106Sdes		memmove(&sa->sin_addr, data, sizeof(sa->sin_addr));
521238106Sdes
522238106Sdes	} else if(tp == LDNS_RR_TYPE_AAAA) {
523238106Sdes		struct sockaddr_in6* sa = (struct sockaddr_in6*)&ip->addr;
524238106Sdes		ip->len = (socklen_t)sizeof(*sa);
525238106Sdes		sa->sin6_family = AF_INET6;
526238106Sdes		sa->sin6_port = (in_port_t)htons(p);
527238106Sdes		if(len != (int)sizeof(sa->sin6_addr)) {
528238106Sdes			if(verb) printf("skipped badly formatted AAAA\n");
529238106Sdes			free(ip);
530238106Sdes			return NULL;
531238106Sdes		}
532238106Sdes		memmove(&sa->sin6_addr, data, sizeof(sa->sin6_addr));
533238106Sdes	} else {
534238106Sdes		if(verb) printf("internal error: bad type in RRtoip\n");
535238106Sdes		free(ip);
536238106Sdes		return NULL;
537238106Sdes	}
538238106Sdes	verb_addr("resolved server address", ip);
539238106Sdes	return ip;
540238106Sdes}
541238106Sdes
542238106Sdes/** Resolve name, type, class and add addresses to iplist */
543238106Sdesstatic void
544255586Sdesresolve_host_ip(struct ub_ctx* ctx, const char* host, int port, int tp, int cl,
545238106Sdes	struct ip_list** head)
546238106Sdes{
547238106Sdes	struct ub_result* res = NULL;
548238106Sdes	int r;
549238106Sdes	int i;
550238106Sdes
551238106Sdes	r = ub_resolve(ctx, host, tp, cl, &res);
552238106Sdes	if(r) {
553238106Sdes		if(verb) printf("error: resolve %s %s: %s\n", host,
554238106Sdes			(tp==LDNS_RR_TYPE_A)?"A":"AAAA", ub_strerror(r));
555238106Sdes		return;
556238106Sdes	}
557238106Sdes	if(!res) {
558238106Sdes		if(verb) printf("out of memory\n");
559238106Sdes		ub_ctx_delete(ctx);
560238106Sdes		exit(0);
561238106Sdes	}
562249141Sdes	if(!res->havedata || res->rcode || !res->data) {
563249141Sdes		if(verb) printf("resolve %s %s: no result\n", host,
564249141Sdes			(tp==LDNS_RR_TYPE_A)?"A":"AAAA");
565249141Sdes		return;
566249141Sdes	}
567238106Sdes	for(i = 0; res->data[i]; i++) {
568238106Sdes		struct ip_list* ip = RR_to_ip(tp, res->data[i], res->len[i],
569238106Sdes			port);
570238106Sdes		if(!ip) continue;
571238106Sdes		ip->next = *head;
572238106Sdes		*head = ip;
573238106Sdes	}
574238106Sdes	ub_resolve_free(res);
575238106Sdes}
576238106Sdes
577238106Sdes/** parse a text IP address into a sockaddr */
578238106Sdesstatic struct ip_list*
579255586Sdesparse_ip_addr(const char* str, int port)
580238106Sdes{
581238106Sdes	socklen_t len = 0;
582255586Sdes	union {
583255586Sdes		struct sockaddr_in6 a6;
584255586Sdes		struct sockaddr_in a;
585255586Sdes	} addr;
586238106Sdes	struct ip_list* ip;
587238106Sdes	uint16_t p = (uint16_t)port;
588255586Sdes	memset(&addr, 0, sizeof(addr));
589238106Sdes
590255586Sdes	if(inet_pton(AF_INET6, str, &addr.a6.sin6_addr) > 0) {
591238106Sdes		/* it is an IPv6 */
592255586Sdes		addr.a6.sin6_family = AF_INET6;
593255586Sdes		addr.a6.sin6_port = (in_port_t)htons(p);
594255586Sdes		len = (socklen_t)sizeof(addr.a6);
595238106Sdes	}
596255586Sdes	if(inet_pton(AF_INET, str, &addr.a.sin_addr) > 0) {
597238106Sdes		/* it is an IPv4 */
598255586Sdes		addr.a.sin_family = AF_INET;
599255586Sdes		addr.a.sin_port = (in_port_t)htons(p);
600238106Sdes		len = (socklen_t)sizeof(struct sockaddr_in);
601238106Sdes	}
602238106Sdes	if(!len) return NULL;
603238106Sdes	ip = (struct ip_list*)calloc(1, sizeof(*ip));
604238106Sdes	if(!ip) {
605238106Sdes		if(verb) printf("out of memory\n");
606238106Sdes		exit(0);
607238106Sdes	}
608238106Sdes	ip->len = len;
609255586Sdes	memmove(&ip->addr, &addr, len);
610238106Sdes	if(verb) printf("server address is %s\n", str);
611238106Sdes	return ip;
612238106Sdes}
613238106Sdes
614238106Sdes/**
615238106Sdes * Resolve a domain name (even though the resolver is down and there is
616238106Sdes * no trust anchor).  Without DNSSEC validation.
617238106Sdes * @param host: the name to resolve.
618238106Sdes * 	If this name is an IP4 or IP6 address this address is returned.
619238106Sdes * @param port: the port number used for the returned IP structs.
620238106Sdes * @param res_conf: resolv.conf (if any).
621238106Sdes * @param root_hints: root hints (if any).
622238106Sdes * @param debugconf: unbound.conf for debugging options.
623356345Scy * @param srcaddr: source address option (if any).
624238106Sdes * @param ip4only: use only ip4 for resolve and only lookup A
625238106Sdes * @param ip6only: use only ip6 for resolve and only lookup AAAA
626238106Sdes * 	default is to lookup A and AAAA using ip4 and ip6.
627238106Sdes * @return list of IP addresses.
628238106Sdes */
629238106Sdesstatic struct ip_list*
630255586Sdesresolve_name(const char* host, int port, const char* res_conf,
631356345Scy	const char* root_hints, const char* debugconf,
632356345Scy	const char* srcaddr, int ip4only, int ip6only)
633238106Sdes{
634238106Sdes	struct ub_ctx* ctx;
635238106Sdes	struct ip_list* list = NULL;
636238106Sdes	/* first see if name is an IP address itself */
637238106Sdes	if( (list=parse_ip_addr(host, port)) ) {
638238106Sdes		return list;
639238106Sdes	}
640238106Sdes
641238106Sdes	/* create resolver context */
642238106Sdes	ctx = create_unbound_context(res_conf, root_hints, debugconf,
643356345Scy        	srcaddr, ip4only, ip6only);
644238106Sdes
645238106Sdes	/* try resolution of A */
646238106Sdes	if(!ip6only) {
647238106Sdes		resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_A,
648238106Sdes			LDNS_RR_CLASS_IN, &list);
649238106Sdes	}
650238106Sdes
651238106Sdes	/* try resolution of AAAA */
652238106Sdes	if(!ip4only) {
653238106Sdes		resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_AAAA,
654238106Sdes			LDNS_RR_CLASS_IN, &list);
655238106Sdes	}
656238106Sdes
657238106Sdes	ub_ctx_delete(ctx);
658238106Sdes	if(!list) {
659238106Sdes		if(verb) printf("%s has no IP addresses I can use\n", host);
660238106Sdes		exit(0);
661238106Sdes	}
662238106Sdes	return list;
663238106Sdes}
664238106Sdes
665238106Sdes/** clear used flags */
666238106Sdesstatic void
667238106Sdeswipe_ip_usage(struct ip_list* p)
668238106Sdes{
669238106Sdes	while(p) {
670238106Sdes		p->used = 0;
671238106Sdes		p = p->next;
672238106Sdes	}
673238106Sdes}
674238106Sdes
675356345Scy/** count unused IPs */
676238106Sdesstatic int
677238106Sdescount_unused(struct ip_list* p)
678238106Sdes{
679238106Sdes	int num = 0;
680238106Sdes	while(p) {
681238106Sdes		if(!p->used) num++;
682238106Sdes		p = p->next;
683238106Sdes	}
684238106Sdes	return num;
685238106Sdes}
686238106Sdes
687238106Sdes/** pick random unused element from IP list */
688238106Sdesstatic struct ip_list*
689238106Sdespick_random_ip(struct ip_list* list)
690238106Sdes{
691238106Sdes	struct ip_list* p = list;
692238106Sdes	int num = count_unused(list);
693238106Sdes	int sel;
694238106Sdes	if(num == 0) return NULL;
695238106Sdes	/* not perfect, but random enough */
696276605Sdes	sel = (int)arc4random_uniform((uint32_t)num);
697238106Sdes	/* skip over unused elements that we did not select */
698238106Sdes	while(sel > 0 && p) {
699238106Sdes		if(!p->used) sel--;
700238106Sdes		p = p->next;
701238106Sdes	}
702238106Sdes	/* find the next unused element */
703238106Sdes	while(p && p->used)
704238106Sdes		p = p->next;
705238106Sdes	if(!p) return NULL; /* robustness */
706238106Sdes	return p;
707238106Sdes}
708238106Sdes
709238106Sdes/** close the fd */
710238106Sdesstatic void
711238106Sdesfd_close(int fd)
712238106Sdes{
713238106Sdes#ifndef USE_WINSOCK
714238106Sdes	close(fd);
715238106Sdes#else
716238106Sdes	closesocket(fd);
717238106Sdes#endif
718238106Sdes}
719238106Sdes
720238106Sdes/** printout socket errno */
721238106Sdesstatic void
722238106Sdesprint_sock_err(const char* msg)
723238106Sdes{
724238106Sdes#ifndef USE_WINSOCK
725238106Sdes	if(verb) printf("%s: %s\n", msg, strerror(errno));
726238106Sdes#else
727238106Sdes	if(verb) printf("%s: %s\n", msg, wsa_strerror(WSAGetLastError()));
728238106Sdes#endif
729238106Sdes}
730238106Sdes
731238106Sdes/** connect to IP address */
732238106Sdesstatic int
733356345Scyconnect_to_ip(struct ip_list* ip, struct ip_list* src)
734238106Sdes{
735238106Sdes	int fd;
736238106Sdes	verb_addr("connect to", ip);
737238106Sdes	fd = socket(ip->len==(socklen_t)sizeof(struct sockaddr_in)?
738238106Sdes		AF_INET:AF_INET6, SOCK_STREAM, 0);
739238106Sdes	if(fd == -1) {
740238106Sdes		print_sock_err("socket");
741238106Sdes		return -1;
742238106Sdes	}
743356345Scy	if(src && bind(fd, (struct sockaddr*)&src->addr, src->len) < 0) {
744356345Scy		print_sock_err("bind");
745356345Scy		fd_close(fd);
746356345Scy		return -1;
747356345Scy	}
748238106Sdes	if(connect(fd, (struct sockaddr*)&ip->addr, ip->len) < 0) {
749238106Sdes		print_sock_err("connect");
750238106Sdes		fd_close(fd);
751238106Sdes		return -1;
752238106Sdes	}
753238106Sdes	return fd;
754238106Sdes}
755238106Sdes
756238106Sdes/** create SSL context */
757238106Sdesstatic SSL_CTX*
758238106Sdessetup_sslctx(void)
759238106Sdes{
760238106Sdes	SSL_CTX* sslctx = SSL_CTX_new(SSLv23_client_method());
761238106Sdes	if(!sslctx) {
762238106Sdes		if(verb) printf("SSL_CTX_new error\n");
763238106Sdes		return NULL;
764238106Sdes	}
765238106Sdes	return sslctx;
766238106Sdes}
767238106Sdes
768238106Sdes/** initiate TLS on a connection */
769238106Sdesstatic SSL*
770366095ScyTLS_initiate(SSL_CTX* sslctx, int fd, const char* urlname, int use_sni)
771238106Sdes{
772238106Sdes	X509* x;
773238106Sdes	int r;
774238106Sdes	SSL* ssl = SSL_new(sslctx);
775238106Sdes	if(!ssl) {
776238106Sdes		if(verb) printf("SSL_new error\n");
777238106Sdes		return NULL;
778238106Sdes	}
779238106Sdes	SSL_set_connect_state(ssl);
780356345Scy	(void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
781238106Sdes	if(!SSL_set_fd(ssl, fd)) {
782238106Sdes		if(verb) printf("SSL_set_fd error\n");
783238106Sdes		SSL_free(ssl);
784238106Sdes		return NULL;
785238106Sdes	}
786366095Scy	if(use_sni) {
787366095Scy		(void)SSL_set_tlsext_host_name(ssl, urlname);
788366095Scy	}
789238106Sdes	while(1) {
790238106Sdes		ERR_clear_error();
791238106Sdes		if( (r=SSL_do_handshake(ssl)) == 1)
792238106Sdes			break;
793238106Sdes		r = SSL_get_error(ssl, r);
794238106Sdes		if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) {
795238106Sdes			if(verb) printf("SSL handshake failed\n");
796238106Sdes			SSL_free(ssl);
797238106Sdes			return NULL;
798238106Sdes		}
799238106Sdes		/* wants to be called again */
800238106Sdes	}
801238106Sdes	x = SSL_get_peer_certificate(ssl);
802238106Sdes	if(!x) {
803238106Sdes		if(verb) printf("Server presented no peer certificate\n");
804238106Sdes		SSL_free(ssl);
805238106Sdes		return NULL;
806238106Sdes	}
807238106Sdes	verb_cert("server SSL certificate", x);
808238106Sdes	X509_free(x);
809238106Sdes	return ssl;
810238106Sdes}
811238106Sdes
812238106Sdes/** perform neat TLS shutdown */
813238106Sdesstatic void
814238106SdesTLS_shutdown(int fd, SSL* ssl, SSL_CTX* sslctx)
815238106Sdes{
816238106Sdes	/* shutdown the SSL connection nicely */
817238106Sdes	if(SSL_shutdown(ssl) == 0) {
818238106Sdes		SSL_shutdown(ssl);
819238106Sdes	}
820238106Sdes	SSL_free(ssl);
821238106Sdes	SSL_CTX_free(sslctx);
822238106Sdes	fd_close(fd);
823238106Sdes}
824238106Sdes
825238106Sdes/** write a line over SSL */
826238106Sdesstatic int
827255586Sdeswrite_ssl_line(SSL* ssl, const char* str, const char* sec)
828238106Sdes{
829238106Sdes	char buf[1024];
830238106Sdes	size_t l;
831238106Sdes	if(sec) {
832238106Sdes		snprintf(buf, sizeof(buf), str, sec);
833238106Sdes	} else {
834238106Sdes		snprintf(buf, sizeof(buf), "%s", str);
835238106Sdes	}
836238106Sdes	l = strlen(buf);
837238106Sdes	if(l+2 >= sizeof(buf)) {
838238106Sdes		if(verb) printf("line too long\n");
839238106Sdes		return 0;
840238106Sdes	}
841238106Sdes	if(verb >= 2) printf("SSL_write: %s\n", buf);
842238106Sdes	buf[l] = '\r';
843238106Sdes	buf[l+1] = '\n';
844238106Sdes	buf[l+2] = 0;
845238106Sdes	/* add \r\n */
846238106Sdes	if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) {
847238106Sdes		if(verb) printf("could not SSL_write %s", str);
848238106Sdes		return 0;
849238106Sdes	}
850238106Sdes	return 1;
851238106Sdes}
852238106Sdes
853238106Sdes/** process header line, check rcode and keeping track of size */
854238106Sdesstatic int
855238106Sdesprocess_one_header(char* buf, size_t* clen, int* chunked)
856238106Sdes{
857238106Sdes	if(verb>=2) printf("header: '%s'\n", buf);
858238106Sdes	if(strncasecmp(buf, "HTTP/1.1 ", 9) == 0) {
859238106Sdes		/* check returncode */
860238106Sdes		if(buf[9] != '2') {
861238106Sdes			if(verb) printf("bad status %s\n", buf+9);
862238106Sdes			return 0;
863238106Sdes		}
864238106Sdes	} else if(strncasecmp(buf, "Content-Length: ", 16) == 0) {
865238106Sdes		if(!*chunked)
866238106Sdes			*clen = (size_t)atoi(buf+16);
867238106Sdes	} else if(strncasecmp(buf, "Transfer-Encoding: chunked", 19+7) == 0) {
868238106Sdes		*clen = 0;
869238106Sdes		*chunked = 1;
870238106Sdes	}
871238106Sdes	return 1;
872238106Sdes}
873238106Sdes
874238106Sdes/**
875238106Sdes * Read one line from SSL
876238106Sdes * zero terminates.
877238106Sdes * skips "\r\n" (but not copied to buf).
878238106Sdes * @param ssl: the SSL connection to read from (blocking).
879238106Sdes * @param buf: buffer to return line in.
880238106Sdes * @param len: size of the buffer.
881238106Sdes * @return 0 on error, 1 on success.
882238106Sdes */
883238106Sdesstatic int
884238106Sdesread_ssl_line(SSL* ssl, char* buf, size_t len)
885238106Sdes{
886238106Sdes	size_t n = 0;
887238106Sdes	int r;
888238106Sdes	int endnl = 0;
889238106Sdes	while(1) {
890238106Sdes		if(n >= len) {
891238106Sdes			if(verb) printf("line too long\n");
892238106Sdes			return 0;
893238106Sdes		}
894238106Sdes		if((r = SSL_read(ssl, buf+n, 1)) <= 0) {
895238106Sdes			if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
896238106Sdes				/* EOF */
897238106Sdes				break;
898238106Sdes			}
899238106Sdes			if(verb) printf("could not SSL_read\n");
900238106Sdes			return 0;
901238106Sdes		}
902238106Sdes		if(endnl && buf[n] == '\n') {
903238106Sdes			break;
904238106Sdes		} else if(endnl) {
905238106Sdes			/* bad data */
906238106Sdes			if(verb) printf("error: stray linefeeds\n");
907238106Sdes			return 0;
908238106Sdes		} else if(buf[n] == '\r') {
909238106Sdes			/* skip \r, and also \n on the wire */
910238106Sdes			endnl = 1;
911238106Sdes			continue;
912238106Sdes		} else if(buf[n] == '\n') {
913238106Sdes			/* skip the \n, we are done */
914238106Sdes			break;
915238106Sdes		} else n++;
916238106Sdes	}
917238106Sdes	buf[n] = 0;
918238106Sdes	return 1;
919238106Sdes}
920238106Sdes
921238106Sdes/** read http headers and process them */
922238106Sdesstatic size_t
923238106Sdesread_http_headers(SSL* ssl, size_t* clen)
924238106Sdes{
925238106Sdes	char buf[1024];
926238106Sdes	int chunked = 0;
927238106Sdes	*clen = 0;
928238106Sdes	while(read_ssl_line(ssl, buf, sizeof(buf))) {
929238106Sdes		if(buf[0] == 0)
930238106Sdes			return 1;
931238106Sdes		if(!process_one_header(buf, clen, &chunked))
932238106Sdes			return 0;
933238106Sdes	}
934238106Sdes	return 0;
935238106Sdes}
936238106Sdes
937238106Sdes/** read a data chunk */
938238106Sdesstatic char*
939238106Sdesread_data_chunk(SSL* ssl, size_t len)
940238106Sdes{
941238106Sdes	size_t got = 0;
942238106Sdes	int r;
943287917Sdes	char* data;
944356345Scy	if((unsigned)len >= (unsigned)0xfffffff0)
945287917Sdes		return NULL; /* to protect against integer overflow in malloc*/
946287917Sdes	data = malloc(len+1);
947238106Sdes	if(!data) {
948238106Sdes		if(verb) printf("out of memory\n");
949238106Sdes		return NULL;
950238106Sdes	}
951238106Sdes	while(got < len) {
952238106Sdes		if((r = SSL_read(ssl, data+got, (int)(len-got))) <= 0) {
953238106Sdes			if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
954238106Sdes				/* EOF */
955238106Sdes				if(verb) printf("could not SSL_read: unexpected EOF\n");
956238106Sdes				free(data);
957238106Sdes				return NULL;
958238106Sdes			}
959238106Sdes			if(verb) printf("could not SSL_read\n");
960238106Sdes			free(data);
961238106Sdes			return NULL;
962238106Sdes		}
963238106Sdes		if(verb >= 2) printf("at %d/%d\n", (int)got, (int)len);
964238106Sdes		got += r;
965238106Sdes	}
966238106Sdes	if(verb>=2) printf("read %d data\n", (int)len);
967238106Sdes	data[len] = 0;
968238106Sdes	return data;
969238106Sdes}
970238106Sdes
971238106Sdes/** parse chunk header */
972238106Sdesstatic int
973238106Sdesparse_chunk_header(char* buf, size_t* result)
974238106Sdes{
975238106Sdes	char* e = NULL;
976238106Sdes	size_t v = (size_t)strtol(buf, &e, 16);
977238106Sdes	if(e == buf)
978238106Sdes		return 0;
979238106Sdes	*result = v;
980238106Sdes	return 1;
981238106Sdes}
982238106Sdes
983238106Sdes/** read chunked data from connection */
984238106Sdesstatic BIO*
985238106Sdesdo_chunked_read(SSL* ssl)
986238106Sdes{
987238106Sdes	char buf[1024];
988238106Sdes	size_t len;
989238106Sdes	char* body;
990238106Sdes	BIO* mem = BIO_new(BIO_s_mem());
991238106Sdes	if(verb>=3) printf("do_chunked_read\n");
992238106Sdes	if(!mem) {
993238106Sdes		if(verb) printf("out of memory\n");
994238106Sdes		return NULL;
995238106Sdes	}
996238106Sdes	while(read_ssl_line(ssl, buf, sizeof(buf))) {
997238106Sdes		/* read the chunked start line */
998238106Sdes		if(verb>=2) printf("chunk header: %s\n", buf);
999238106Sdes		if(!parse_chunk_header(buf, &len)) {
1000238106Sdes			BIO_free(mem);
1001238106Sdes			if(verb>=3) printf("could not parse chunk header\n");
1002238106Sdes			return NULL;
1003238106Sdes		}
1004238106Sdes		if(verb>=2) printf("chunk len: %d\n", (int)len);
1005238106Sdes		/* are we done? */
1006238106Sdes		if(len == 0) {
1007238106Sdes			char z = 0;
1008238106Sdes			/* skip end-of-chunk-trailer lines,
1009238106Sdes			 * until the empty line after that */
1010238106Sdes			do {
1011238106Sdes				if(!read_ssl_line(ssl, buf, sizeof(buf))) {
1012238106Sdes					BIO_free(mem);
1013238106Sdes					return NULL;
1014238106Sdes				}
1015238106Sdes			} while (strlen(buf) > 0);
1016238106Sdes			/* end of chunks, zero terminate it */
1017238106Sdes			if(BIO_write(mem, &z, 1) <= 0) {
1018238106Sdes				if(verb) printf("out of memory\n");
1019238106Sdes				BIO_free(mem);
1020238106Sdes				return NULL;
1021238106Sdes			}
1022238106Sdes			return mem;
1023238106Sdes		}
1024238106Sdes		/* read the chunked body */
1025238106Sdes		body = read_data_chunk(ssl, len);
1026238106Sdes		if(!body) {
1027238106Sdes			BIO_free(mem);
1028238106Sdes			return NULL;
1029238106Sdes		}
1030238106Sdes		if(BIO_write(mem, body, (int)len) <= 0) {
1031238106Sdes			if(verb) printf("out of memory\n");
1032238106Sdes			free(body);
1033238106Sdes			BIO_free(mem);
1034238106Sdes			return NULL;
1035238106Sdes		}
1036238106Sdes		free(body);
1037238106Sdes		/* skip empty line after data chunk */
1038238106Sdes		if(!read_ssl_line(ssl, buf, sizeof(buf))) {
1039238106Sdes			BIO_free(mem);
1040238106Sdes			return NULL;
1041238106Sdes		}
1042238106Sdes	}
1043238106Sdes	BIO_free(mem);
1044238106Sdes	return NULL;
1045238106Sdes}
1046238106Sdes
1047238106Sdes/** start HTTP1.1 transaction on SSL */
1048238106Sdesstatic int
1049255586Sdeswrite_http_get(SSL* ssl, const char* pathname, const char* urlname)
1050238106Sdes{
1051238106Sdes	if(write_ssl_line(ssl, "GET /%s HTTP/1.1", pathname) &&
1052238106Sdes	   write_ssl_line(ssl, "Host: %s", urlname) &&
1053238106Sdes	   write_ssl_line(ssl, "User-Agent: unbound-anchor/%s",
1054238106Sdes	   	PACKAGE_VERSION) &&
1055238106Sdes	   /* We do not really do multiple queries per connection,
1056238106Sdes	    * but this header setting is also not needed.
1057238106Sdes	    * write_ssl_line(ssl, "Connection: close", NULL) &&*/
1058238106Sdes	   write_ssl_line(ssl, "", NULL)) {
1059238106Sdes		return 1;
1060238106Sdes	}
1061238106Sdes	return 0;
1062238106Sdes}
1063238106Sdes
1064238106Sdes/** read chunked data and zero terminate; len is without zero */
1065238106Sdesstatic char*
1066238106Sdesread_chunked_zero_terminate(SSL* ssl, size_t* len)
1067238106Sdes{
1068238106Sdes	/* do the chunked version */
1069238106Sdes	BIO* tmp = do_chunked_read(ssl);
1070238106Sdes	char* data, *d = NULL;
1071238106Sdes	size_t l;
1072238106Sdes	if(!tmp) {
1073238106Sdes		if(verb) printf("could not read from https\n");
1074238106Sdes		return NULL;
1075238106Sdes	}
1076238106Sdes	l = (size_t)BIO_get_mem_data(tmp, &d);
1077238106Sdes	if(verb>=2) printf("chunked data is %d\n", (int)l);
1078238106Sdes	if(l == 0 || d == NULL) {
1079238106Sdes		if(verb) printf("out of memory\n");
1080238106Sdes		return NULL;
1081238106Sdes	}
1082238106Sdes	*len = l-1;
1083238106Sdes	data = (char*)malloc(l);
1084238106Sdes	if(data == NULL) {
1085238106Sdes		if(verb) printf("out of memory\n");
1086238106Sdes		return NULL;
1087238106Sdes	}
1088238106Sdes	memcpy(data, d, l);
1089238106Sdes	BIO_free(tmp);
1090238106Sdes	return data;
1091238106Sdes}
1092238106Sdes
1093238106Sdes/** read HTTP result from SSL */
1094238106Sdesstatic BIO*
1095238106Sdesread_http_result(SSL* ssl)
1096238106Sdes{
1097238106Sdes	size_t len = 0;
1098238106Sdes	char* data;
1099238106Sdes	BIO* m;
1100238106Sdes	if(!read_http_headers(ssl, &len)) {
1101238106Sdes		return NULL;
1102238106Sdes	}
1103238106Sdes	if(len == 0) {
1104238106Sdes		data = read_chunked_zero_terminate(ssl, &len);
1105238106Sdes	} else {
1106238106Sdes		data = read_data_chunk(ssl, len);
1107238106Sdes	}
1108238106Sdes	if(!data) return NULL;
1109369939Sgit2svn	if(verb >= 4) print_data("read data", data, len);
1110356345Scy	m = BIO_new(BIO_s_mem());
1111238106Sdes	if(!m) {
1112238106Sdes		if(verb) printf("out of memory\n");
1113356345Scy		free(data);
1114238106Sdes		exit(0);
1115238106Sdes	}
1116356345Scy	BIO_write(m, data, (int)len);
1117356345Scy	free(data);
1118238106Sdes	return m;
1119238106Sdes}
1120238106Sdes
1121238106Sdes/** https to an IP addr, return BIO with pathname or NULL */
1122238106Sdesstatic BIO*
1123356345Scyhttps_to_ip(struct ip_list* ip, const char* pathname, const char* urlname,
1124366095Scy	struct ip_list* src, int use_sni)
1125238106Sdes{
1126238106Sdes	int fd;
1127238106Sdes	SSL* ssl;
1128238106Sdes	BIO* bio;
1129238106Sdes	SSL_CTX* sslctx = setup_sslctx();
1130238106Sdes	if(!sslctx) {
1131238106Sdes		return NULL;
1132238106Sdes	}
1133356345Scy	fd = connect_to_ip(ip, src);
1134238106Sdes	if(fd == -1) {
1135238106Sdes		SSL_CTX_free(sslctx);
1136238106Sdes		return NULL;
1137238106Sdes	}
1138366095Scy	ssl = TLS_initiate(sslctx, fd, urlname, use_sni);
1139238106Sdes	if(!ssl) {
1140238106Sdes		SSL_CTX_free(sslctx);
1141238106Sdes		fd_close(fd);
1142238106Sdes		return NULL;
1143238106Sdes	}
1144238106Sdes	if(!write_http_get(ssl, pathname, urlname)) {
1145238106Sdes		if(verb) printf("could not write to server\n");
1146238106Sdes		SSL_free(ssl);
1147238106Sdes		SSL_CTX_free(sslctx);
1148238106Sdes		fd_close(fd);
1149238106Sdes		return NULL;
1150238106Sdes	}
1151238106Sdes	bio = read_http_result(ssl);
1152238106Sdes	TLS_shutdown(fd, ssl, sslctx);
1153238106Sdes	return bio;
1154238106Sdes}
1155238106Sdes
1156238106Sdes/**
1157238106Sdes * Do a HTTPS, HTTP1.1 over TLS, to fetch a file
1158238106Sdes * @param ip_list: list of IP addresses to use to fetch from.
1159238106Sdes * @param pathname: pathname of file on server to GET.
1160238106Sdes * @param urlname: name to pass as the virtual host for this request.
1161356345Scy * @param src: if nonNULL, source address to bind to.
1162366095Scy * @param use_sni: if SNI will be used.
1163238106Sdes * @return a memory BIO with the file in it.
1164238106Sdes */
1165238106Sdesstatic BIO*
1166356345Scyhttps(struct ip_list* ip_list, const char* pathname, const char* urlname,
1167366095Scy	struct ip_list* src, int use_sni)
1168238106Sdes{
1169238106Sdes	struct ip_list* ip;
1170238106Sdes	BIO* bio = NULL;
1171238106Sdes	/* try random address first, and work through the list */
1172238106Sdes	wipe_ip_usage(ip_list);
1173238106Sdes	while( (ip = pick_random_ip(ip_list)) ) {
1174238106Sdes		ip->used = 1;
1175366095Scy		bio = https_to_ip(ip, pathname, urlname, src, use_sni);
1176238106Sdes		if(bio) break;
1177238106Sdes	}
1178238106Sdes	if(!bio) {
1179238106Sdes		if(verb) printf("could not fetch %s\n", pathname);
1180238106Sdes		exit(0);
1181238106Sdes	} else {
1182238106Sdes		if(verb) printf("fetched %s (%d bytes)\n",
1183238106Sdes			pathname, (int)BIO_ctrl_pending(bio));
1184238106Sdes	}
1185238106Sdes	return bio;
1186238106Sdes}
1187238106Sdes
1188238106Sdes/** XML parse private data during the parse */
1189238106Sdesstruct xml_data {
1190238106Sdes	/** the parser, reference */
1191238106Sdes	XML_Parser parser;
1192238106Sdes	/** the current tag; malloced; or NULL outside of tags */
1193238106Sdes	char* tag;
1194238106Sdes	/** current date to use during the parse */
1195238106Sdes	time_t date;
1196238106Sdes	/** number of keys usefully read in */
1197238106Sdes	int num_keys;
1198238106Sdes	/** the compiled anchors as DS records */
1199238106Sdes	BIO* ds;
1200238106Sdes
1201238106Sdes	/** do we want to use this anchor? */
1202238106Sdes	int use_key;
1203238106Sdes	/** the current anchor: Zone */
1204238106Sdes	BIO* czone;
1205238106Sdes	/** the current anchor: KeyTag */
1206238106Sdes	BIO* ctag;
1207238106Sdes	/** the current anchor: Algorithm */
1208238106Sdes	BIO* calgo;
1209238106Sdes	/** the current anchor: DigestType */
1210238106Sdes	BIO* cdigtype;
1211238106Sdes	/** the current anchor: Digest*/
1212238106Sdes	BIO* cdigest;
1213238106Sdes};
1214238106Sdes
1215238106Sdes/** The BIO for the tag */
1216238106Sdesstatic BIO*
1217238106Sdesxml_selectbio(struct xml_data* data, const char* tag)
1218238106Sdes{
1219238106Sdes	BIO* b = NULL;
1220238106Sdes	if(strcasecmp(tag, "KeyTag") == 0)
1221238106Sdes		b = data->ctag;
1222238106Sdes	else if(strcasecmp(tag, "Algorithm") == 0)
1223238106Sdes		b = data->calgo;
1224238106Sdes	else if(strcasecmp(tag, "DigestType") == 0)
1225238106Sdes		b = data->cdigtype;
1226238106Sdes	else if(strcasecmp(tag, "Digest") == 0)
1227238106Sdes		b = data->cdigest;
1228238106Sdes	return b;
1229238106Sdes}
1230238106Sdes
1231238106Sdes/**
1232238106Sdes * XML handle character data, the data inside an element.
1233238106Sdes * @param userData: xml_data structure
1234238106Sdes * @param s: the character data.  May not all be in one callback.
1235238106Sdes * 	NOT zero terminated.
1236238106Sdes * @param len: length of this part of the data.
1237238106Sdes */
1238255586Sdesstatic void
1239238106Sdesxml_charhandle(void *userData, const XML_Char *s, int len)
1240238106Sdes{
1241238106Sdes	struct xml_data* data = (struct xml_data*)userData;
1242238106Sdes	BIO* b = NULL;
1243238106Sdes	/* skip characters outside of elements */
1244238106Sdes	if(!data->tag)
1245238106Sdes		return;
1246238106Sdes	if(verb>=4) {
1247238106Sdes		int i;
1248238106Sdes		printf("%s%s charhandle: '",
1249238106Sdes			data->use_key?"use ":"",
1250238106Sdes			data->tag?data->tag:"none");
1251238106Sdes		for(i=0; i<len; i++)
1252238106Sdes			printf("%c", s[i]);
1253238106Sdes		printf("'\n");
1254238106Sdes	}
1255238106Sdes	if(strcasecmp(data->tag, "Zone") == 0) {
1256266114Sdes		if(BIO_write(data->czone, s, len) < 0) {
1257238106Sdes			if(verb) printf("out of memory in BIO_write\n");
1258238106Sdes			exit(0);
1259238106Sdes		}
1260238106Sdes		return;
1261238106Sdes	}
1262238106Sdes	/* only store if key is used */
1263238106Sdes	if(!data->use_key)
1264238106Sdes		return;
1265238106Sdes	b = xml_selectbio(data, data->tag);
1266238106Sdes	if(b) {
1267266114Sdes		if(BIO_write(b, s, len) < 0) {
1268238106Sdes			if(verb) printf("out of memory in BIO_write\n");
1269238106Sdes			exit(0);
1270238106Sdes		}
1271238106Sdes	}
1272238106Sdes}
1273238106Sdes
1274238106Sdes/**
1275238106Sdes * XML fetch value of particular attribute(by name) or NULL if not present.
1276238106Sdes * @param atts: attribute array (from xml_startelem).
1277238106Sdes * @param name: name of attribute to look for.
1278238106Sdes * @return the value or NULL. (ptr into atts).
1279238106Sdes */
1280238106Sdesstatic const XML_Char*
1281255586Sdesfind_att(const XML_Char **atts, const XML_Char* name)
1282238106Sdes{
1283238106Sdes	int i;
1284238106Sdes	for(i=0; atts[i]; i+=2) {
1285238106Sdes		if(strcasecmp(atts[i], name) == 0)
1286238106Sdes			return atts[i+1];
1287238106Sdes	}
1288238106Sdes	return NULL;
1289238106Sdes}
1290238106Sdes
1291238106Sdes/**
1292238106Sdes * XML convert DateTime element to time_t.
1293238106Sdes * [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
1294238106Sdes * (with optional .ssssss fractional seconds)
1295238106Sdes * @param str: the string
1296238106Sdes * @return a time_t representation or 0 on failure.
1297238106Sdes */
1298238106Sdesstatic time_t
1299238106Sdesxml_convertdate(const char* str)
1300238106Sdes{
1301238106Sdes	time_t t = 0;
1302238106Sdes	struct tm tm;
1303238106Sdes	const char* s;
1304238106Sdes	/* for this application, ignore minus in front;
1305238106Sdes	 * only positive dates are expected */
1306238106Sdes	s = str;
1307238106Sdes	if(s[0] == '-') s++;
1308238106Sdes	memset(&tm, 0, sizeof(tm));
1309238106Sdes	/* parse initial content of the string (lots of whitespace allowed) */
1310238106Sdes	s = strptime(s, "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t:%t%S%t", &tm);
1311238106Sdes	if(!s) {
1312238106Sdes		if(verb) printf("xml_convertdate parse failure %s\n", str);
1313238106Sdes		return 0;
1314238106Sdes	}
1315238106Sdes	/* parse remainder of date string */
1316238106Sdes	if(*s == '.') {
1317238106Sdes		/* optional '.' and fractional seconds */
1318238106Sdes		int frac = 0, n = 0;
1319238106Sdes		if(sscanf(s+1, "%d%n", &frac, &n) < 1) {
1320238106Sdes			if(verb) printf("xml_convertdate f failure %s\n", str);
1321238106Sdes			return 0;
1322238106Sdes		}
1323238106Sdes		/* fraction is not used, time_t has second accuracy */
1324238106Sdes		s++;
1325238106Sdes		s+=n;
1326238106Sdes	}
1327238106Sdes	if(*s == 'Z' || *s == 'z') {
1328238106Sdes		/* nothing to do for this */
1329238106Sdes		s++;
1330238106Sdes	} else if(*s == '+' || *s == '-') {
1331238106Sdes		/* optional timezone spec: Z or +hh:mm or -hh:mm */
1332238106Sdes		int hr = 0, mn = 0, n = 0;
1333238106Sdes		if(sscanf(s+1, "%d:%d%n", &hr, &mn, &n) < 2) {
1334238106Sdes			if(verb) printf("xml_convertdate tz failure %s\n", str);
1335238106Sdes			return 0;
1336238106Sdes		}
1337238106Sdes		if(*s == '+') {
1338238106Sdes			tm.tm_hour += hr;
1339238106Sdes			tm.tm_min += mn;
1340238106Sdes		} else {
1341238106Sdes			tm.tm_hour -= hr;
1342238106Sdes			tm.tm_min -= mn;
1343238106Sdes		}
1344238106Sdes		s++;
1345238106Sdes		s += n;
1346238106Sdes	}
1347238106Sdes	if(*s != 0) {
1348238106Sdes		/* not ended properly */
1349238106Sdes		/* but ignore, (lenient) */
1350238106Sdes	}
1351238106Sdes
1352289063Sdes	t = sldns_mktime_from_utc(&tm);
1353238106Sdes	if(t == (time_t)-1) {
1354238106Sdes		if(verb) printf("xml_convertdate mktime failure\n");
1355238106Sdes		return 0;
1356238106Sdes	}
1357238106Sdes	return t;
1358238106Sdes}
1359238106Sdes
1360238106Sdes/**
1361238106Sdes * XML handle the KeyDigest start tag, check validity periods.
1362238106Sdes */
1363238106Sdesstatic void
1364238106Sdeshandle_keydigest(struct xml_data* data, const XML_Char **atts)
1365238106Sdes{
1366238106Sdes	data->use_key = 0;
1367238106Sdes	if(find_att(atts, "validFrom")) {
1368238106Sdes		time_t from = xml_convertdate(find_att(atts, "validFrom"));
1369238106Sdes		if(from == 0) {
1370238106Sdes			if(verb) printf("error: xml cannot be parsed\n");
1371238106Sdes			exit(0);
1372238106Sdes		}
1373238106Sdes		if(data->date < from)
1374238106Sdes			return;
1375238106Sdes	}
1376238106Sdes	if(find_att(atts, "validUntil")) {
1377238106Sdes		time_t until = xml_convertdate(find_att(atts, "validUntil"));
1378238106Sdes		if(until == 0) {
1379238106Sdes			if(verb) printf("error: xml cannot be parsed\n");
1380238106Sdes			exit(0);
1381238106Sdes		}
1382238106Sdes		if(data->date > until)
1383238106Sdes			return;
1384238106Sdes	}
1385238106Sdes	/* yes we want to use this key */
1386238106Sdes	data->use_key = 1;
1387238106Sdes	(void)BIO_reset(data->ctag);
1388238106Sdes	(void)BIO_reset(data->calgo);
1389238106Sdes	(void)BIO_reset(data->cdigtype);
1390238106Sdes	(void)BIO_reset(data->cdigest);
1391238106Sdes}
1392238106Sdes
1393238106Sdes/** See if XML element equals the zone name */
1394238106Sdesstatic int
1395255586Sdesxml_is_zone_name(BIO* zone, const char* name)
1396238106Sdes{
1397238106Sdes	char buf[1024];
1398238106Sdes	char* z = NULL;
1399238106Sdes	long zlen;
1400238106Sdes	(void)BIO_seek(zone, 0);
1401238106Sdes	zlen = BIO_get_mem_data(zone, &z);
1402238106Sdes	if(!zlen || !z) return 0;
1403238106Sdes	/* zero terminate */
1404238106Sdes	if(zlen >= (long)sizeof(buf)) return 0;
1405238106Sdes	memmove(buf, z, (size_t)zlen);
1406238106Sdes	buf[zlen] = 0;
1407238106Sdes	/* compare */
1408238106Sdes	return (strncasecmp(buf, name, strlen(name)) == 0);
1409238106Sdes}
1410238106Sdes
1411238106Sdes/**
1412238106Sdes * XML start of element. This callback is called whenever an XML tag starts.
1413238106Sdes * XML_Char is UTF8.
1414238106Sdes * @param userData: the xml_data structure.
1415238106Sdes * @param name: the tag that starts.
1416238106Sdes * @param atts: array of strings, pairs of attr = value, ends with NULL.
1417238106Sdes * 	i.e. att[0]="att[1]" att[2]="att[3]" att[4]isNull
1418238106Sdes */
1419238106Sdesstatic void
1420238106Sdesxml_startelem(void *userData, const XML_Char *name, const XML_Char **atts)
1421238106Sdes{
1422238106Sdes	struct xml_data* data = (struct xml_data*)userData;
1423238106Sdes	BIO* b;
1424238106Sdes	if(verb>=4) printf("xml tag start '%s'\n", name);
1425238106Sdes	free(data->tag);
1426238106Sdes	data->tag = strdup(name);
1427238106Sdes	if(!data->tag) {
1428238106Sdes		if(verb) printf("out of memory\n");
1429238106Sdes		exit(0);
1430238106Sdes	}
1431238106Sdes	if(verb>=4) {
1432238106Sdes		int i;
1433238106Sdes		for(i=0; atts[i]; i+=2) {
1434238106Sdes			printf("  %s='%s'\n", atts[i], atts[i+1]);
1435238106Sdes		}
1436238106Sdes	}
1437238106Sdes	/* handle attributes to particular types */
1438238106Sdes	if(strcasecmp(name, "KeyDigest") == 0) {
1439238106Sdes		handle_keydigest(data, atts);
1440238106Sdes		return;
1441238106Sdes	} else if(strcasecmp(name, "Zone") == 0) {
1442238106Sdes		(void)BIO_reset(data->czone);
1443238106Sdes		return;
1444238106Sdes	}
1445238106Sdes
1446238106Sdes	/* for other types we prepare to pick up the data */
1447238106Sdes	if(!data->use_key)
1448238106Sdes		return;
1449238106Sdes	b = xml_selectbio(data, data->tag);
1450238106Sdes	if(b) {
1451238106Sdes		/* empty it */
1452238106Sdes		(void)BIO_reset(b);
1453238106Sdes	}
1454238106Sdes}
1455238106Sdes
1456238106Sdes/** Append str to bio */
1457238106Sdesstatic void
1458238106Sdesxml_append_str(BIO* b, const char* s)
1459238106Sdes{
1460266114Sdes	if(BIO_write(b, s, (int)strlen(s)) < 0) {
1461238106Sdes		if(verb) printf("out of memory in BIO_write\n");
1462238106Sdes		exit(0);
1463238106Sdes	}
1464238106Sdes}
1465238106Sdes
1466238106Sdes/** Append bio to bio */
1467238106Sdesstatic void
1468238106Sdesxml_append_bio(BIO* b, BIO* a)
1469238106Sdes{
1470238106Sdes	char* z = NULL;
1471238106Sdes	long i, len;
1472238106Sdes	(void)BIO_seek(a, 0);
1473238106Sdes	len = BIO_get_mem_data(a, &z);
1474238106Sdes	if(!len || !z) {
1475238106Sdes		if(verb) printf("out of memory in BIO_write\n");
1476238106Sdes		exit(0);
1477238106Sdes	}
1478238106Sdes	/* remove newlines in the data here */
1479238106Sdes	for(i=0; i<len; i++) {
1480238106Sdes		if(z[i] == '\r' || z[i] == '\n')
1481238106Sdes			z[i] = ' ';
1482238106Sdes	}
1483238106Sdes	/* write to BIO */
1484266114Sdes	if(BIO_write(b, z, len) < 0) {
1485238106Sdes		if(verb) printf("out of memory in BIO_write\n");
1486238106Sdes		exit(0);
1487238106Sdes	}
1488238106Sdes}
1489238106Sdes
1490238106Sdes/** write the parsed xml-DS to the DS list */
1491238106Sdesstatic void
1492238106Sdesxml_append_ds(struct xml_data* data)
1493238106Sdes{
1494238106Sdes	/* write DS to accumulated DS */
1495238106Sdes	xml_append_str(data->ds, ". IN DS ");
1496238106Sdes	xml_append_bio(data->ds, data->ctag);
1497238106Sdes	xml_append_str(data->ds, " ");
1498238106Sdes	xml_append_bio(data->ds, data->calgo);
1499238106Sdes	xml_append_str(data->ds, " ");
1500238106Sdes	xml_append_bio(data->ds, data->cdigtype);
1501238106Sdes	xml_append_str(data->ds, " ");
1502238106Sdes	xml_append_bio(data->ds, data->cdigest);
1503238106Sdes	xml_append_str(data->ds, "\n");
1504238106Sdes	data->num_keys++;
1505238106Sdes}
1506238106Sdes
1507238106Sdes/**
1508238106Sdes * XML end of element. This callback is called whenever an XML tag ends.
1509238106Sdes * XML_Char is UTF8.
1510238106Sdes * @param userData: the xml_data structure
1511238106Sdes * @param name: the tag that ends.
1512238106Sdes */
1513238106Sdesstatic void
1514238106Sdesxml_endelem(void *userData, const XML_Char *name)
1515238106Sdes{
1516238106Sdes	struct xml_data* data = (struct xml_data*)userData;
1517238106Sdes	if(verb>=4) printf("xml tag end   '%s'\n", name);
1518238106Sdes	free(data->tag);
1519238106Sdes	data->tag = NULL;
1520238106Sdes	if(strcasecmp(name, "KeyDigest") == 0) {
1521238106Sdes		if(data->use_key)
1522238106Sdes			xml_append_ds(data);
1523238106Sdes		data->use_key = 0;
1524238106Sdes	} else if(strcasecmp(name, "Zone") == 0) {
1525238106Sdes		if(!xml_is_zone_name(data->czone, ".")) {
1526238106Sdes			if(verb) printf("xml not for the right zone\n");
1527238106Sdes			exit(0);
1528238106Sdes		}
1529238106Sdes	}
1530238106Sdes}
1531238106Sdes
1532249141Sdes/* Stop the parser when an entity declaration is encountered. For safety. */
1533249141Sdesstatic void
1534249141Sdesxml_entitydeclhandler(void *userData,
1535249141Sdes	const XML_Char *ATTR_UNUSED(entityName),
1536249141Sdes	int ATTR_UNUSED(is_parameter_entity),
1537249141Sdes	const XML_Char *ATTR_UNUSED(value), int ATTR_UNUSED(value_length),
1538249141Sdes	const XML_Char *ATTR_UNUSED(base),
1539249141Sdes	const XML_Char *ATTR_UNUSED(systemId),
1540249141Sdes	const XML_Char *ATTR_UNUSED(publicId),
1541249141Sdes	const XML_Char *ATTR_UNUSED(notationName))
1542249141Sdes{
1543292206Sdes#if HAVE_DECL_XML_STOPPARSER
1544249141Sdes	(void)XML_StopParser((XML_Parser)userData, XML_FALSE);
1545292206Sdes#else
1546292206Sdes	(void)userData;
1547292206Sdes#endif
1548249141Sdes}
1549249141Sdes
1550238106Sdes/**
1551238106Sdes * XML parser setup of the callbacks for the tags
1552238106Sdes */
1553238106Sdesstatic void
1554238106Sdesxml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now)
1555238106Sdes{
1556238106Sdes	char buf[1024];
1557238106Sdes	memset(data, 0, sizeof(*data));
1558238106Sdes	XML_SetUserData(parser, data);
1559238106Sdes	data->parser = parser;
1560238106Sdes	data->date = now;
1561238106Sdes	data->ds = BIO_new(BIO_s_mem());
1562238106Sdes	data->ctag = BIO_new(BIO_s_mem());
1563238106Sdes	data->czone = BIO_new(BIO_s_mem());
1564238106Sdes	data->calgo = BIO_new(BIO_s_mem());
1565238106Sdes	data->cdigtype = BIO_new(BIO_s_mem());
1566238106Sdes	data->cdigest = BIO_new(BIO_s_mem());
1567238106Sdes	if(!data->ds || !data->ctag || !data->calgo || !data->czone ||
1568238106Sdes		!data->cdigtype || !data->cdigest) {
1569238106Sdes		if(verb) printf("out of memory\n");
1570238106Sdes		exit(0);
1571238106Sdes	}
1572238106Sdes	snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s",
1573238106Sdes		ctime(&now));
1574266114Sdes	if(BIO_write(data->ds, buf, (int)strlen(buf)) < 0) {
1575238106Sdes		if(verb) printf("out of memory\n");
1576238106Sdes		exit(0);
1577238106Sdes	}
1578249141Sdes	XML_SetEntityDeclHandler(parser, xml_entitydeclhandler);
1579238106Sdes	XML_SetElementHandler(parser, xml_startelem, xml_endelem);
1580238106Sdes	XML_SetCharacterDataHandler(parser, xml_charhandle);
1581238106Sdes}
1582238106Sdes
1583238106Sdes/**
1584238106Sdes * Perform XML parsing of the root-anchors file
1585238106Sdes * Its format description can be read here
1586238106Sdes * https://data.iana.org/root-anchors/draft-icann-dnssec-trust-anchor.txt
1587238106Sdes * It uses libexpat.
1588238106Sdes * @param xml: BIO with xml data.
1589238106Sdes * @param now: the current time for checking DS validity periods.
1590238106Sdes * @return memoryBIO with the DS data in zone format.
1591238106Sdes * 	or NULL if the zone is insecure.
1592238106Sdes * 	(It exit()s on error)
1593238106Sdes */
1594238106Sdesstatic BIO*
1595238106Sdesxml_parse(BIO* xml, time_t now)
1596238106Sdes{
1597238106Sdes	char* pp;
1598238106Sdes	int len;
1599238106Sdes	XML_Parser parser;
1600238106Sdes	struct xml_data data;
1601238106Sdes
1602238106Sdes	parser = XML_ParserCreate(NULL);
1603238106Sdes	if(!parser) {
1604238106Sdes		if(verb) printf("could not XML_ParserCreate\n");
1605238106Sdes		exit(0);
1606238106Sdes	}
1607238106Sdes
1608238106Sdes	/* setup callbacks */
1609238106Sdes	xml_parse_setup(parser, &data, now);
1610238106Sdes
1611238106Sdes	/* parse it */
1612356345Scy	(void)BIO_seek(xml, 0);
1613238106Sdes	len = (int)BIO_get_mem_data(xml, &pp);
1614238106Sdes	if(!len || !pp) {
1615238106Sdes		if(verb) printf("out of memory\n");
1616238106Sdes		exit(0);
1617238106Sdes	}
1618238106Sdes	if(!XML_Parse(parser, pp, len, 1 /*isfinal*/ )) {
1619238106Sdes		const char *e = XML_ErrorString(XML_GetErrorCode(parser));
1620238106Sdes		if(verb) printf("XML_Parse failure %s\n", e?e:"");
1621238106Sdes		exit(0);
1622238106Sdes	}
1623238106Sdes
1624238106Sdes	/* parsed */
1625238106Sdes	if(verb) printf("XML was parsed successfully, %d keys\n",
1626238106Sdes			data.num_keys);
1627238106Sdes	free(data.tag);
1628238106Sdes	XML_ParserFree(parser);
1629238106Sdes
1630238106Sdes	if(verb >= 4) {
1631238106Sdes		(void)BIO_seek(data.ds, 0);
1632238106Sdes		len = BIO_get_mem_data(data.ds, &pp);
1633238106Sdes		printf("got DS bio %d: '", len);
1634238106Sdes		if(!fwrite(pp, (size_t)len, 1, stdout))
1635238106Sdes			/* compilers do not allow us to ignore fwrite .. */
1636238106Sdes			fprintf(stderr, "error writing to stdout\n");
1637238106Sdes		printf("'\n");
1638238106Sdes	}
1639238106Sdes	BIO_free(data.czone);
1640238106Sdes	BIO_free(data.ctag);
1641238106Sdes	BIO_free(data.calgo);
1642238106Sdes	BIO_free(data.cdigtype);
1643238106Sdes	BIO_free(data.cdigest);
1644238106Sdes
1645238106Sdes	if(data.num_keys == 0) {
1646238106Sdes		/* the root zone seems to have gone insecure */
1647238106Sdes		BIO_free(data.ds);
1648238106Sdes		return NULL;
1649238106Sdes	} else {
1650238106Sdes		return data.ds;
1651238106Sdes	}
1652238106Sdes}
1653238106Sdes
1654249141Sdes/* get key usage out of its extension, returns 0 if no key_usage extension */
1655249141Sdesstatic unsigned long
1656249141Sdesget_usage_of_ex(X509* cert)
1657249141Sdes{
1658249141Sdes	unsigned long val = 0;
1659249141Sdes	ASN1_BIT_STRING* s;
1660249141Sdes	if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) {
1661249141Sdes		if(s->length > 0) {
1662249141Sdes			val = s->data[0];
1663249141Sdes			if(s->length > 1)
1664249141Sdes				val |= s->data[1] << 8;
1665249141Sdes		}
1666249141Sdes		ASN1_BIT_STRING_free(s);
1667249141Sdes	}
1668249141Sdes	return val;
1669249141Sdes}
1670249141Sdes
1671249141Sdes/** get valid signers from the list of signers in the signature */
1672249141Sdesstatic STACK_OF(X509)*
1673255586Sdesget_valid_signers(PKCS7* p7, const char* p7signer)
1674249141Sdes{
1675249141Sdes	int i;
1676249141Sdes	STACK_OF(X509)* validsigners = sk_X509_new_null();
1677249141Sdes	STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0);
1678249141Sdes	unsigned long usage = 0;
1679249141Sdes	if(!validsigners) {
1680249141Sdes		if(verb) printf("out of memory\n");
1681249141Sdes		sk_X509_free(signers);
1682249141Sdes		return NULL;
1683249141Sdes	}
1684249141Sdes	if(!signers) {
1685249141Sdes		if(verb) printf("no signers in pkcs7 signature\n");
1686249141Sdes		sk_X509_free(validsigners);
1687249141Sdes		return NULL;
1688249141Sdes	}
1689249141Sdes	for(i=0; i<sk_X509_num(signers); i++) {
1690249141Sdes		X509_NAME* nm = X509_get_subject_name(
1691249141Sdes			sk_X509_value(signers, i));
1692249141Sdes		char buf[1024];
1693249141Sdes		if(!nm) {
1694249141Sdes			if(verb) printf("signer %d: cert has no subject name\n", i);
1695249141Sdes			continue;
1696249141Sdes		}
1697249141Sdes		if(verb && nm) {
1698249141Sdes			char* nmline = X509_NAME_oneline(nm, buf,
1699249141Sdes				(int)sizeof(buf));
1700249141Sdes			printf("signer %d: Subject: %s\n", i,
1701249141Sdes				nmline?nmline:"no subject");
1702249141Sdes			if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
1703249141Sdes				NID_commonName, buf, (int)sizeof(buf)))
1704249141Sdes				printf("commonName: %s\n", buf);
1705249141Sdes			if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
1706249141Sdes				NID_pkcs9_emailAddress, buf, (int)sizeof(buf)))
1707249141Sdes				printf("emailAddress: %s\n", buf);
1708249141Sdes		}
1709249141Sdes		if(verb) {
1710249141Sdes			int ku_loc = X509_get_ext_by_NID(
1711249141Sdes				sk_X509_value(signers, i), NID_key_usage, -1);
1712249141Sdes			if(verb >= 3 && ku_loc >= 0) {
1713249141Sdes				X509_EXTENSION *ex = X509_get_ext(
1714249141Sdes					sk_X509_value(signers, i), ku_loc);
1715249141Sdes				if(ex) {
1716249141Sdes					printf("keyUsage: ");
1717249141Sdes					X509V3_EXT_print_fp(stdout, ex, 0, 0);
1718249141Sdes					printf("\n");
1719249141Sdes				}
1720249141Sdes			}
1721249141Sdes		}
1722249141Sdes		if(!p7signer || strcmp(p7signer, "")==0) {
1723249141Sdes			/* there is no name to check, return all records */
1724249141Sdes			if(verb) printf("did not check commonName of signer\n");
1725249141Sdes		} else {
1726249141Sdes			if(!X509_NAME_get_text_by_NID(nm,
1727249141Sdes				NID_pkcs9_emailAddress,
1728249141Sdes				buf, (int)sizeof(buf))) {
1729249141Sdes				if(verb) printf("removed cert with no name\n");
1730249141Sdes				continue; /* no name, no use */
1731249141Sdes			}
1732249141Sdes			if(strcmp(buf, p7signer) != 0) {
1733249141Sdes				if(verb) printf("removed cert with wrong name\n");
1734249141Sdes				continue; /* wrong name, skip it */
1735249141Sdes			}
1736249141Sdes		}
1737249141Sdes
1738249141Sdes		/* check that the key usage allows digital signatures
1739249141Sdes		 * (the p7s) */
1740249141Sdes		usage = get_usage_of_ex(sk_X509_value(signers, i));
1741249141Sdes		if(!(usage & KU_DIGITAL_SIGNATURE)) {
1742249141Sdes			if(verb) printf("removed cert with no key usage Digital Signature allowed\n");
1743249141Sdes			continue;
1744249141Sdes		}
1745249141Sdes
1746249141Sdes		/* we like this cert, add it to our list of valid
1747249141Sdes		 * signers certificates */
1748249141Sdes		sk_X509_push(validsigners, sk_X509_value(signers, i));
1749249141Sdes	}
1750249141Sdes	sk_X509_free(signers);
1751249141Sdes	return validsigners;
1752249141Sdes}
1753249141Sdes
1754238106Sdes/** verify a PKCS7 signature, false on failure */
1755238106Sdesstatic int
1756255586Sdesverify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer)
1757238106Sdes{
1758238106Sdes	PKCS7* p7;
1759238106Sdes	X509_STORE *store = X509_STORE_new();
1760249141Sdes	STACK_OF(X509)* validsigners;
1761238106Sdes	int secure = 0;
1762238106Sdes	int i;
1763238106Sdes#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1764238106Sdes	X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
1765238106Sdes	if(!param) {
1766238106Sdes		if(verb) printf("out of memory\n");
1767238106Sdes		X509_STORE_free(store);
1768238106Sdes		return 0;
1769238106Sdes	}
1770238106Sdes	/* do the selfcheck on the root certificate; it checks that the
1771238106Sdes	 * input is valid */
1772238106Sdes	X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CHECK_SS_SIGNATURE);
1773238106Sdes	if(store) X509_STORE_set1_param(store, param);
1774238106Sdes#endif
1775238106Sdes	if(!store) {
1776238106Sdes		if(verb) printf("out of memory\n");
1777238106Sdes#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1778238106Sdes		X509_VERIFY_PARAM_free(param);
1779238106Sdes#endif
1780238106Sdes		return 0;
1781238106Sdes	}
1782249141Sdes#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
1783249141Sdes	X509_VERIFY_PARAM_free(param);
1784249141Sdes#endif
1785238106Sdes
1786356345Scy	(void)BIO_seek(p7s, 0);
1787356345Scy	(void)BIO_seek(data, 0);
1788238106Sdes
1789238106Sdes	/* convert p7s to p7 (the signature) */
1790238106Sdes	p7 = d2i_PKCS7_bio(p7s, NULL);
1791238106Sdes	if(!p7) {
1792238106Sdes		if(verb) printf("could not parse p7s signature file\n");
1793238106Sdes		X509_STORE_free(store);
1794238106Sdes		return 0;
1795238106Sdes	}
1796238106Sdes	if(verb >= 2) printf("parsed the PKCS7 signature\n");
1797238106Sdes
1798238106Sdes	/* convert trust to trusted certificate store */
1799238106Sdes	for(i=0; i<sk_X509_num(trust); i++) {
1800238106Sdes		if(!X509_STORE_add_cert(store, sk_X509_value(trust, i))) {
1801238106Sdes			if(verb) printf("failed X509_STORE_add_cert\n");
1802238106Sdes			X509_STORE_free(store);
1803238106Sdes			PKCS7_free(p7);
1804238106Sdes			return 0;
1805238106Sdes		}
1806238106Sdes	}
1807238106Sdes	if(verb >= 2) printf("setup the X509_STORE\n");
1808238106Sdes
1809249141Sdes	/* check what is in the Subject name of the certificates,
1810249141Sdes	 * and build a stack that contains only the right certificates */
1811249141Sdes	validsigners = get_valid_signers(p7, p7signer);
1812249141Sdes	if(!validsigners) {
1813249141Sdes			X509_STORE_free(store);
1814249141Sdes			PKCS7_free(p7);
1815249141Sdes			return 0;
1816249141Sdes	}
1817249141Sdes	if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) {
1818238106Sdes		secure = 1;
1819238106Sdes		if(verb) printf("the PKCS7 signature verified\n");
1820238106Sdes	} else {
1821238106Sdes		if(verb) {
1822238106Sdes			ERR_print_errors_fp(stdout);
1823238106Sdes		}
1824238106Sdes	}
1825238106Sdes
1826249141Sdes	sk_X509_free(validsigners);
1827238106Sdes	X509_STORE_free(store);
1828238106Sdes	PKCS7_free(p7);
1829238106Sdes	return secure;
1830238106Sdes}
1831238106Sdes
1832238106Sdes/** write unsigned root anchor file, a 5011 revoked tp */
1833238106Sdesstatic void
1834255586Sdeswrite_unsigned_root(const char* root_anchor_file)
1835238106Sdes{
1836238106Sdes	FILE* out;
1837238106Sdes	time_t now = time(NULL);
1838238106Sdes	out = fopen(root_anchor_file, "w");
1839238106Sdes	if(!out) {
1840238106Sdes		if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
1841238106Sdes		return;
1842238106Sdes	}
1843238106Sdes	if(fprintf(out, "; autotrust trust anchor file\n"
1844238106Sdes		";;REVOKED\n"
1845238106Sdes		";;id: . 1\n"
1846238106Sdes		"; This file was written by unbound-anchor on %s"
1847238106Sdes		"; It indicates that the root does not use DNSSEC\n"
1848238106Sdes		"; to restart DNSSEC overwrite this file with a\n"
1849238106Sdes		"; valid trustanchor or (empty-it and run unbound-anchor)\n"
1850238106Sdes		, ctime(&now)) < 0) {
1851238106Sdes		if(verb) printf("failed to write 'unsigned' to %s\n",
1852238106Sdes			root_anchor_file);
1853238106Sdes		if(verb && errno != 0) printf("%s\n", strerror(errno));
1854238106Sdes	}
1855292206Sdes	fflush(out);
1856292206Sdes#ifdef HAVE_FSYNC
1857292206Sdes	fsync(fileno(out));
1858292206Sdes#else
1859307729Sdes	FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
1860292206Sdes#endif
1861238106Sdes	fclose(out);
1862238106Sdes}
1863238106Sdes
1864238106Sdes/** write root anchor file */
1865238106Sdesstatic void
1866255586Sdeswrite_root_anchor(const char* root_anchor_file, BIO* ds)
1867238106Sdes{
1868238106Sdes	char* pp = NULL;
1869238106Sdes	int len;
1870238106Sdes	FILE* out;
1871238106Sdes	(void)BIO_seek(ds, 0);
1872238106Sdes	len = BIO_get_mem_data(ds, &pp);
1873238106Sdes	if(!len || !pp) {
1874238106Sdes		if(verb) printf("out of memory\n");
1875238106Sdes		return;
1876238106Sdes	}
1877238106Sdes	out = fopen(root_anchor_file, "w");
1878238106Sdes	if(!out) {
1879238106Sdes		if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
1880238106Sdes		return;
1881238106Sdes	}
1882238106Sdes	if(fwrite(pp, (size_t)len, 1, out) != 1) {
1883238106Sdes		if(verb) printf("failed to write all data to %s\n",
1884238106Sdes			root_anchor_file);
1885238106Sdes		if(verb && errno != 0) printf("%s\n", strerror(errno));
1886238106Sdes	}
1887292206Sdes	fflush(out);
1888292206Sdes#ifdef HAVE_FSYNC
1889292206Sdes	fsync(fileno(out));
1890292206Sdes#else
1891307729Sdes	FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
1892292206Sdes#endif
1893238106Sdes	fclose(out);
1894238106Sdes}
1895238106Sdes
1896238106Sdes/** Perform the verification and update of the trustanchor file */
1897238106Sdesstatic void
1898255586Sdesverify_and_update_anchor(const char* root_anchor_file, BIO* xml, BIO* p7s,
1899255586Sdes	STACK_OF(X509)* cert, const char* p7signer)
1900238106Sdes{
1901238106Sdes	BIO* ds;
1902238106Sdes
1903238106Sdes	/* verify xml file */
1904249141Sdes	if(!verify_p7sig(xml, p7s, cert, p7signer)) {
1905238106Sdes		printf("the PKCS7 signature failed\n");
1906238106Sdes		exit(0);
1907238106Sdes	}
1908238106Sdes
1909238106Sdes	/* parse the xml file into DS records */
1910238106Sdes	ds = xml_parse(xml, time(NULL));
1911238106Sdes	if(!ds) {
1912238106Sdes		/* the root zone is unsigned now */
1913238106Sdes		write_unsigned_root(root_anchor_file);
1914238106Sdes	} else {
1915238106Sdes		/* reinstate 5011 tracking */
1916238106Sdes		write_root_anchor(root_anchor_file, ds);
1917238106Sdes	}
1918238106Sdes	BIO_free(ds);
1919238106Sdes}
1920238106Sdes
1921238106Sdes#ifdef USE_WINSOCK
1922238106Sdesstatic void do_wsa_cleanup(void) { WSACleanup(); }
1923238106Sdes#endif
1924238106Sdes
1925238106Sdes/** perform actual certupdate work */
1926238106Sdesstatic int
1927255586Sdesdo_certupdate(const char* root_anchor_file, const char* root_cert_file,
1928255586Sdes	const char* urlname, const char* xmlname, const char* p7sname,
1929255586Sdes	const char* p7signer, const char* res_conf, const char* root_hints,
1930356345Scy	const char* debugconf, const char* srcaddr, int ip4only, int ip6only,
1931366095Scy	int port, int use_sni)
1932356345Scy
1933238106Sdes{
1934238106Sdes	STACK_OF(X509)* cert;
1935238106Sdes	BIO *xml, *p7s;
1936238106Sdes	struct ip_list* ip_list = NULL;
1937356345Scy	struct ip_list* src = NULL;
1938238106Sdes
1939238106Sdes	/* read pem file or provide builtin */
1940238106Sdes	cert = read_cert_or_builtin(root_cert_file);
1941238106Sdes
1942238106Sdes	/* lookup A, AAAA for the urlname (or parse urlname if IP address) */
1943238106Sdes	ip_list = resolve_name(urlname, port, res_conf, root_hints, debugconf,
1944356345Scy	        srcaddr, ip4only, ip6only);
1945238106Sdes
1946356345Scy	if(srcaddr && !(src = parse_ip_addr(srcaddr, 0))) {
1947356345Scy		if(verb) printf("cannot parse source address: %s\n", srcaddr);
1948356345Scy		exit(0);
1949356345Scy	}
1950356345Scy
1951238106Sdes#ifdef USE_WINSOCK
1952238106Sdes	if(1) { /* libunbound finished, startup WSA for the https connection */
1953238106Sdes		WSADATA wsa_data;
1954238106Sdes		int r;
1955238106Sdes		if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
1956238106Sdes			if(verb) printf("WSAStartup failed: %s\n",
1957238106Sdes				wsa_strerror(r));
1958238106Sdes			exit(0);
1959238106Sdes		}
1960238106Sdes		atexit(&do_wsa_cleanup);
1961238106Sdes	}
1962238106Sdes#endif
1963238106Sdes
1964238106Sdes	/* fetch the necessary files over HTTPS */
1965366095Scy	xml = https(ip_list, xmlname, urlname, src, use_sni);
1966366095Scy	p7s = https(ip_list, p7sname, urlname, src, use_sni);
1967238106Sdes
1968238106Sdes	/* verify and update the root anchor */
1969249141Sdes	verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer);
1970238106Sdes	if(verb) printf("success: the anchor has been updated "
1971238106Sdes			"using the cert\n");
1972238106Sdes
1973356345Scy	BIO_free(xml);
1974356345Scy	BIO_free(p7s);
1975238106Sdes#ifndef S_SPLINT_S
1976238106Sdes	sk_X509_pop_free(cert, X509_free);
1977238106Sdes#endif
1978238106Sdes	ip_list_free(ip_list);
1979238106Sdes	return 1;
1980238106Sdes}
1981238106Sdes
1982238106Sdes/**
1983238106Sdes * Try to read the root RFC5011 autotrust anchor file,
1984238106Sdes * @param file: filename.
1985238106Sdes * @return:
1986238106Sdes * 	0 if does not exist or empty
1987238106Sdes * 	1 if trust-point-revoked-5011
1988238106Sdes * 	2 if it is OK.
1989238106Sdes */
1990238106Sdesstatic int
1991255586Sdestry_read_anchor(const char* file)
1992238106Sdes{
1993238106Sdes	int empty = 1;
1994238106Sdes	char line[10240];
1995238106Sdes	char* p;
1996238106Sdes	FILE* in = fopen(file, "r");
1997238106Sdes	if(!in) {
1998238106Sdes		/* only if the file does not exist, can we fix it */
1999238106Sdes		if(errno != ENOENT) {
2000238106Sdes			if(verb) printf("%s: %s\n", file, strerror(errno));
2001238106Sdes			if(verb) printf("error: cannot access the file\n");
2002238106Sdes			exit(0);
2003238106Sdes		}
2004238106Sdes		if(verb) printf("%s does not exist\n", file);
2005238106Sdes		return 0;
2006238106Sdes	}
2007238106Sdes	while(fgets(line, (int)sizeof(line), in)) {
2008238106Sdes		line[sizeof(line)-1] = 0;
2009238106Sdes		if(strncmp(line, ";;REVOKED", 9) == 0) {
2010238106Sdes			fclose(in);
2011238106Sdes			if(verb) printf("%s : the trust point is revoked\n"
2012238106Sdes				"and the zone is considered unsigned.\n"
2013238106Sdes				"if you wish to re-enable, delete the file\n",
2014238106Sdes				file);
2015238106Sdes			return 1;
2016238106Sdes		}
2017238106Sdes		p=line;
2018238106Sdes		while(*p == ' ' || *p == '\t')
2019238106Sdes			p++;
2020238106Sdes		if(p[0]==0 || p[0]=='\n' || p[0]==';') continue;
2021238106Sdes		/* this line is a line of content */
2022238106Sdes		empty = 0;
2023238106Sdes	}
2024238106Sdes	fclose(in);
2025238106Sdes	if(empty) {
2026238106Sdes		if(verb) printf("%s is empty\n", file);
2027238106Sdes		return 0;
2028238106Sdes	}
2029238106Sdes	if(verb) printf("%s has content\n", file);
2030238106Sdes	return 2;
2031238106Sdes}
2032238106Sdes
2033238106Sdes/** Write the builtin root anchor to a file */
2034238106Sdesstatic void
2035255586Sdeswrite_builtin_anchor(const char* file)
2036238106Sdes{
2037238106Sdes	const char* builtin_root_anchor = get_builtin_ds();
2038238106Sdes	FILE* out = fopen(file, "w");
2039238106Sdes	if(!out) {
2040238106Sdes		if(verb) printf("%s: %s\n", file, strerror(errno));
2041238106Sdes		if(verb) printf("  could not write builtin anchor\n");
2042238106Sdes		return;
2043238106Sdes	}
2044238106Sdes	if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
2045238106Sdes		if(verb) printf("%s: %s\n", file, strerror(errno));
2046238106Sdes		if(verb) printf("  could not complete write builtin anchor\n");
2047238106Sdes	}
2048238106Sdes	fclose(out);
2049238106Sdes}
2050238106Sdes
2051238106Sdes/**
2052238106Sdes * Check the root anchor file.
2053238106Sdes * If does not exist, provide builtin and write file.
2054238106Sdes * If empty, provide builtin and write file.
2055238106Sdes * If trust-point-revoked-5011 file: make the program exit.
2056238106Sdes * @param root_anchor_file: filename of the root anchor.
2057238106Sdes * @param used_builtin: set to 1 if the builtin is written.
2058238106Sdes * @return 0 if trustpoint is insecure, 1 on success.  Exit on failure.
2059238106Sdes */
2060238106Sdesstatic int
2061255586Sdesprovide_builtin(const char* root_anchor_file, int* used_builtin)
2062238106Sdes{
2063238106Sdes	/* try to read it */
2064238106Sdes	switch(try_read_anchor(root_anchor_file))
2065238106Sdes	{
2066238106Sdes		case 0: /* no exist or empty */
2067238106Sdes			write_builtin_anchor(root_anchor_file);
2068238106Sdes			*used_builtin = 1;
2069238106Sdes			break;
2070238106Sdes		case 1: /* revoked tp */
2071238106Sdes			return 0;
2072238106Sdes		case 2: /* it is fine */
2073238106Sdes		default:
2074238106Sdes			break;
2075238106Sdes	}
2076238106Sdes	return 1;
2077238106Sdes}
2078238106Sdes
2079238106Sdes/**
2080238106Sdes * add an autotrust anchor for the root to the context
2081238106Sdes */
2082238106Sdesstatic void
2083255586Sdesadd_5011_probe_root(struct ub_ctx* ctx, const char* root_anchor_file)
2084238106Sdes{
2085238106Sdes	int r;
2086238106Sdes	r = ub_ctx_set_option(ctx, "auto-trust-anchor-file:", root_anchor_file);
2087238106Sdes	if(r) {
2088238106Sdes		if(verb) printf("add 5011 probe to ctx: %s\n", ub_strerror(r));
2089238106Sdes		ub_ctx_delete(ctx);
2090238106Sdes		exit(0);
2091238106Sdes	}
2092238106Sdes}
2093238106Sdes
2094238106Sdes/**
2095238106Sdes * Prime the root key and return the result.  Exit on error.
2096238106Sdes * @param ctx: the unbound context to perform the priming with.
2097238106Sdes * @return: the result of the prime, on error it exit()s.
2098238106Sdes */
2099238106Sdesstatic struct ub_result*
2100238106Sdesprime_root_key(struct ub_ctx* ctx)
2101238106Sdes{
2102238106Sdes	struct ub_result* res = NULL;
2103238106Sdes	int r;
2104238106Sdes	r = ub_resolve(ctx, ".", LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &res);
2105238106Sdes	if(r) {
2106238106Sdes		if(verb) printf("resolve DNSKEY: %s\n", ub_strerror(r));
2107238106Sdes		ub_ctx_delete(ctx);
2108238106Sdes		exit(0);
2109238106Sdes	}
2110238106Sdes	if(!res) {
2111238106Sdes		if(verb) printf("out of memory\n");
2112238106Sdes		ub_ctx_delete(ctx);
2113238106Sdes		exit(0);
2114238106Sdes	}
2115238106Sdes	return res;
2116238106Sdes}
2117238106Sdes
2118238106Sdes/** see if ADDPEND keys exist in autotrust file (if possible) */
2119238106Sdesstatic int
2120255586Sdesread_if_pending_keys(const char* file)
2121238106Sdes{
2122238106Sdes	FILE* in = fopen(file, "r");
2123238106Sdes	char line[8192];
2124238106Sdes	if(!in) {
2125238106Sdes		if(verb>=2) printf("%s: %s\n", file, strerror(errno));
2126238106Sdes		return 0;
2127238106Sdes	}
2128238106Sdes	while(fgets(line, (int)sizeof(line), in)) {
2129238106Sdes		if(line[0]==';') continue;
2130238106Sdes		if(strstr(line, "[ ADDPEND ]")) {
2131238106Sdes			fclose(in);
2132238106Sdes			if(verb) printf("RFC5011-state has ADDPEND keys\n");
2133238106Sdes			return 1;
2134238106Sdes		}
2135238106Sdes	}
2136238106Sdes	fclose(in);
2137238106Sdes	return 0;
2138238106Sdes}
2139238106Sdes
2140238106Sdes/** read last successful probe time from autotrust file (if possible) */
2141238106Sdesstatic int32_t
2142255586Sdesread_last_success_time(const char* file)
2143238106Sdes{
2144238106Sdes	FILE* in = fopen(file, "r");
2145238106Sdes	char line[1024];
2146238106Sdes	if(!in) {
2147238106Sdes		if(verb) printf("%s: %s\n", file, strerror(errno));
2148238106Sdes		return 0;
2149238106Sdes	}
2150238106Sdes	while(fgets(line, (int)sizeof(line), in)) {
2151238106Sdes		if(strncmp(line, ";;last_success: ", 16) == 0) {
2152238106Sdes			char* e;
2153238106Sdes			time_t x = (unsigned int)strtol(line+16, &e, 10);
2154238106Sdes			fclose(in);
2155238106Sdes			if(line+16 == e) {
2156238106Sdes				if(verb) printf("failed to parse "
2157238106Sdes					"last_success probe time\n");
2158238106Sdes				return 0;
2159238106Sdes			}
2160238106Sdes			if(verb) printf("last successful probe: %s", ctime(&x));
2161238106Sdes			return (int32_t)x;
2162238106Sdes		}
2163238106Sdes	}
2164238106Sdes	fclose(in);
2165238106Sdes	if(verb) printf("no last_success probe time in anchor file\n");
2166238106Sdes	return 0;
2167238106Sdes}
2168238106Sdes
2169238106Sdes/**
2170238106Sdes * Read autotrust 5011 probe file and see if the date
2171238106Sdes * compared to the current date allows a certupdate.
2172238106Sdes * If the last successful probe was recent then 5011 cannot be behind,
2173238106Sdes * and the failure cannot be solved with a certupdate.
2174238106Sdes * The debugconf is to validation-override the date for testing.
2175238106Sdes * @param root_anchor_file: filename of root key
2176238106Sdes * @return true if certupdate is ok.
2177238106Sdes */
2178238106Sdesstatic int
2179255586Sdesprobe_date_allows_certupdate(const char* root_anchor_file)
2180238106Sdes{
2181238106Sdes	int has_pending_keys = read_if_pending_keys(root_anchor_file);
2182238106Sdes	int32_t last_success = read_last_success_time(root_anchor_file);
2183238106Sdes	int32_t now = (int32_t)time(NULL);
2184238106Sdes	int32_t leeway = 30 * 24 * 3600; /* 30 days leeway */
2185238106Sdes	/* if the date is before 2010-07-15:00.00.00 then the root has not
2186238106Sdes	 * been signed yet, and thus we refuse to take action. */
2187238106Sdes	if(time(NULL) < xml_convertdate("2010-07-15T00:00:00")) {
2188238106Sdes		if(verb) printf("the date is before the root was first signed,"
2189238106Sdes			" please correct the clock\n");
2190238106Sdes		return 0;
2191238106Sdes	}
2192238106Sdes	if(last_success == 0)
2193238106Sdes		return 1; /* no probe time */
2194238106Sdes	if(has_pending_keys)
2195238106Sdes		return 1; /* key in ADDPEND state, a previous probe has
2196238106Sdes		inserted that, and it was present in all recent probes,
2197238106Sdes		but it has not become active.  The 30 day timer may not have
2198238106Sdes		expired, but we know(for sure) there is a rollover going on.
2199238106Sdes		If we only managed to pickup the new key on its last day
2200238106Sdes		of announcement (for example) this can happen. */
2201238106Sdes	if(now - last_success < 0) {
2202238106Sdes		if(verb) printf("the last successful probe is in the future,"
2203238106Sdes			" clock was modified\n");
2204238106Sdes		return 0;
2205238106Sdes	}
2206238106Sdes	if(now - last_success >= leeway) {
2207238106Sdes		if(verb) printf("the last successful probe was more than 30 "
2208238106Sdes			"days ago\n");
2209238106Sdes		return 1;
2210238106Sdes	}
2211238106Sdes	if(verb) printf("the last successful probe is recent\n");
2212238106Sdes	return 0;
2213238106Sdes}
2214238106Sdes
2215356345Scystatic struct ub_result *
2216356345Scyfetch_root_key(const char* root_anchor_file, const char* res_conf,
2217356345Scy	const char* root_hints, const char* debugconf, const char* srcaddr,
2218356345Scy	int ip4only, int ip6only)
2219356345Scy{
2220356345Scy	struct ub_ctx* ctx;
2221356345Scy	struct ub_result* dnskey;
2222356345Scy
2223356345Scy	ctx = create_unbound_context(res_conf, root_hints, debugconf,
2224356345Scy		srcaddr, ip4only, ip6only);
2225356345Scy	add_5011_probe_root(ctx, root_anchor_file);
2226356345Scy	dnskey = prime_root_key(ctx);
2227356345Scy	ub_ctx_delete(ctx);
2228356345Scy	return dnskey;
2229356345Scy}
2230356345Scy
2231238106Sdes/** perform the unbound-anchor work */
2232238106Sdesstatic int
2233255586Sdesdo_root_update_work(const char* root_anchor_file, const char* root_cert_file,
2234255586Sdes	const char* urlname, const char* xmlname, const char* p7sname,
2235255586Sdes	const char* p7signer, const char* res_conf, const char* root_hints,
2236356345Scy	const char* debugconf, const char* srcaddr, int ip4only, int ip6only,
2237366095Scy	int force, int res_conf_fallback, int port, int use_sni)
2238238106Sdes{
2239238106Sdes	struct ub_result* dnskey;
2240238106Sdes	int used_builtin = 0;
2241356345Scy	int rcode;
2242238106Sdes
2243238106Sdes	/* see if builtin rootanchor needs to be provided, or if
2244238106Sdes	 * rootanchor is 'revoked-trust-point' */
2245238106Sdes	if(!provide_builtin(root_anchor_file, &used_builtin))
2246238106Sdes		return 0;
2247238106Sdes
2248238106Sdes	/* make unbound context with 5011-probe for root anchor,
2249238106Sdes	 * and probe . DNSKEY */
2250356345Scy	dnskey = fetch_root_key(root_anchor_file, res_conf,
2251356345Scy		root_hints, debugconf, srcaddr, ip4only, ip6only);
2252356345Scy	rcode = dnskey->rcode;
2253356345Scy
2254356345Scy	if (res_conf_fallback && res_conf && !dnskey->secure) {
2255356345Scy		if (verb) printf("%s failed, retrying direct\n", res_conf);
2256356345Scy		ub_resolve_free(dnskey);
2257356345Scy		/* try direct query without res_conf */
2258356345Scy		dnskey = fetch_root_key(root_anchor_file, NULL,
2259356345Scy			root_hints, debugconf, srcaddr, ip4only, ip6only);
2260356345Scy		if (rcode != 0 && dnskey->rcode == 0) {
2261356345Scy			res_conf = NULL;
2262356345Scy			rcode = 0;
2263356345Scy		}
2264356345Scy	}
2265356345Scy
2266238106Sdes	/* if secure: exit */
2267238106Sdes	if(dnskey->secure && !force) {
2268238106Sdes		if(verb) printf("success: the anchor is ok\n");
2269238106Sdes		ub_resolve_free(dnskey);
2270238106Sdes		return used_builtin;
2271238106Sdes	}
2272238106Sdes	if(force && verb) printf("debug cert update forced\n");
2273356345Scy	ub_resolve_free(dnskey);
2274238106Sdes
2275238106Sdes	/* if not (and NOERROR): check date and do certupdate */
2276356345Scy	if((rcode == 0 &&
2277238106Sdes		probe_date_allows_certupdate(root_anchor_file)) || force) {
2278238106Sdes		if(do_certupdate(root_anchor_file, root_cert_file, urlname,
2279249141Sdes			xmlname, p7sname, p7signer, res_conf, root_hints,
2280366095Scy			debugconf, srcaddr, ip4only, ip6only, port, use_sni))
2281238106Sdes			return 1;
2282238106Sdes		return used_builtin;
2283238106Sdes	}
2284238106Sdes	if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n");
2285238106Sdes	return used_builtin;
2286238106Sdes}
2287238106Sdes
2288238106Sdes/** getopt global, in case header files fail to declare it. */
2289238106Sdesextern int optind;
2290238106Sdes/** getopt global, in case header files fail to declare it. */
2291238106Sdesextern char* optarg;
2292238106Sdes
2293238106Sdes/** Main routine for unbound-anchor */
2294238106Sdesint main(int argc, char* argv[])
2295238106Sdes{
2296238106Sdes	int c;
2297255586Sdes	const char* root_anchor_file = ROOT_ANCHOR_FILE;
2298255586Sdes	const char* root_cert_file = ROOT_CERT_FILE;
2299255586Sdes	const char* urlname = URLNAME;
2300255586Sdes	const char* xmlname = XMLNAME;
2301255586Sdes	const char* p7sname = P7SNAME;
2302255586Sdes	const char* p7signer = P7SIGNER;
2303255586Sdes	const char* res_conf = NULL;
2304255586Sdes	const char* root_hints = NULL;
2305255586Sdes	const char* debugconf = NULL;
2306356345Scy	const char* srcaddr = NULL;
2307238106Sdes	int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT;
2308356345Scy	int res_conf_fallback = 0;
2309366095Scy	int use_sni = 1;
2310238106Sdes	/* parse the options */
2311366095Scy	while( (c=getopt(argc, argv, "46C:FRSP:a:b:c:f:hln:r:s:u:vx:")) != -1) {
2312238106Sdes		switch(c) {
2313238106Sdes		case 'l':
2314238106Sdes			dolist = 1;
2315238106Sdes			break;
2316238106Sdes		case '4':
2317238106Sdes			ip4only = 1;
2318238106Sdes			break;
2319238106Sdes		case '6':
2320238106Sdes			ip6only = 1;
2321238106Sdes			break;
2322238106Sdes		case 'a':
2323238106Sdes			root_anchor_file = optarg;
2324238106Sdes			break;
2325356345Scy		case 'b':
2326356345Scy			srcaddr = optarg;
2327356345Scy			break;
2328238106Sdes		case 'c':
2329238106Sdes			root_cert_file = optarg;
2330238106Sdes			break;
2331238106Sdes		case 'u':
2332238106Sdes			urlname = optarg;
2333238106Sdes			break;
2334366095Scy		case 'S':
2335366095Scy			use_sni = 0;
2336366095Scy			break;
2337238106Sdes		case 'x':
2338238106Sdes			xmlname = optarg;
2339238106Sdes			break;
2340238106Sdes		case 's':
2341238106Sdes			p7sname = optarg;
2342238106Sdes			break;
2343249141Sdes		case 'n':
2344249141Sdes			p7signer = optarg;
2345249141Sdes			break;
2346238106Sdes		case 'f':
2347238106Sdes			res_conf = optarg;
2348238106Sdes			break;
2349238106Sdes		case 'r':
2350238106Sdes			root_hints = optarg;
2351238106Sdes			break;
2352356345Scy		case 'R':
2353356345Scy			res_conf_fallback = 1;
2354356345Scy			break;
2355238106Sdes		case 'C':
2356238106Sdes			debugconf = optarg;
2357238106Sdes			break;
2358238106Sdes		case 'F':
2359238106Sdes			force = 1;
2360238106Sdes			break;
2361238106Sdes		case 'P':
2362238106Sdes			port = atoi(optarg);
2363238106Sdes			break;
2364238106Sdes		case 'v':
2365238106Sdes			verb++;
2366238106Sdes			break;
2367238106Sdes		case '?':
2368238106Sdes		case 'h':
2369238106Sdes		default:
2370238106Sdes			usage();
2371238106Sdes		}
2372238106Sdes	}
2373238106Sdes	argc -= optind;
2374356345Scy	/* argv += optind; not using further arguments */
2375238106Sdes	if(argc != 0)
2376238106Sdes		usage();
2377238106Sdes
2378307729Sdes#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
2379238106Sdes	ERR_load_crypto_strings();
2380307729Sdes#endif
2381356345Scy#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
2382238106Sdes	ERR_load_SSL_strings();
2383356345Scy#endif
2384307729Sdes#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
2385356345Scy#  ifndef S_SPLINT_S
2386238106Sdes	OpenSSL_add_all_algorithms();
2387356345Scy#  endif
2388307729Sdes#else
2389307729Sdes	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
2390307729Sdes		| OPENSSL_INIT_ADD_ALL_DIGESTS
2391307729Sdes		| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
2392307729Sdes#endif
2393307729Sdes#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
2394238106Sdes	(void)SSL_library_init();
2395307729Sdes#else
2396356345Scy	(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
2397307729Sdes#endif
2398238106Sdes
2399238106Sdes	if(dolist) do_list_builtin();
2400238106Sdes
2401238106Sdes	return do_root_update_work(root_anchor_file, root_cert_file, urlname,
2402249141Sdes		xmlname, p7sname, p7signer, res_conf, root_hints, debugconf,
2403366095Scy		srcaddr, ip4only, ip6only, force, res_conf_fallback, port, use_sni);
2404238106Sdes}
2405