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