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