unbound-anchor work

git-svn-id: file:///svn/unbound/trunk@2251 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2010-09-27 14:54:22 +00:00
parent 224d547178
commit c007b34cc1
2 changed files with 323 additions and 4 deletions

View file

@ -1,3 +1,6 @@
27 September 2010: Wouter
- iana portlist updated.
24 September 2010: Wouter 24 September 2010: Wouter
- bug#329: in example.conf show correct ipv4 link-local 169.254/16. - bug#329: in example.conf show correct ipv4 link-local 169.254/16.

View file

@ -1068,6 +1068,258 @@ free_file_bio(BIO* bio)
BIO_free(bio); BIO_free(bio);
} }
/** XML parse private data during the parse */
struct xml_data {
/** the parser, reference */
XML_Parser parser;
/** the current tag; malloced; or NULL outside of tags */
char* tag;
/** current date to use during the parse */
time_t date;
/** do we want to use this anchor? */
int use_key;
/** number of keys usefully read in */
int num_keys;
/** the compiled anchors as DS records */
BIO* ds;
};
/**
* XML handle character data, the data inside an element.
* @param userData: xml_data structure
* @param s: the character data. May not all be in one callback.
* NOT zero terminated.
* @param len: length of this part of the data.
*/
void
xml_charhandle(void *userData, const XML_Char *s, int len)
{
struct xml_data* data = (struct xml_data*)userData;
/* skip characters outside of elements */
if(!data->tag)
return;
if(verb>=4) {
int i;
printf("%s%s charhandle: '",
data->use_key?"use ":"",
data->tag?data->tag:"none");
for(i=0; i<len; i++)
printf("%c", s[i]);
printf("'\n");
}
/* only store if key is used */
if(!data->use_key)
return;
if(strcasecmp(data->tag, "KeyTag") == 0 ||
strcasecmp(data->tag, "Algorithm") == 0 ||
strcasecmp(data->tag, "DigestType") == 0 ||
strcasecmp(data->tag, "Digest") == 0) {
if(BIO_write(data->ds, s, len) <= 0) {
if(verb) printf("out of memory in BIO_write\n");
exit(0);
}
}
}
/**
* XML fetch value of particular attribute(by name) or NULL if not present.
* @param atts: attribute array (from xml_startelem).
* @param name: name of attribute to look for.
* @return the value or NULL. (ptr into atts).
*/
static const XML_Char*
find_att(const XML_Char **atts, XML_Char* name)
{
int i;
for(i=0; atts[i]; i+=2) {
if(strcasecmp(atts[i], name) == 0)
return atts[i+1];
}
return NULL;
}
/**
* XML handle the KeyDigest start tag, check validity periods.
*/
static void
handle_keydigest(struct xml_data* data, const XML_Char **atts)
{
const char* s = ". IN DS";
data->use_key = 0;
if(find_att(atts, "validFrom")) {
/* TODO */
}
if(find_att(atts, "validUntil")) {
/* TODO */
}
/* yes we want to use this key */
data->use_key = 1;
data->num_keys++;
if(BIO_write(data->ds, s, (int)strlen(s)) <= 0) {
if(verb) printf("out of memory in BIO_write\n");
exit(0);
}
}
/**
* XML start of element. This callback is called whenever an XML tag starts.
* XML_Char is UTF8.
* @param userData: the xml_data structure.
* @param name: the tag that starts.
* @param atts: array of strings, pairs of attr = value, ends with NULL.
* i.e. att[0]="att[1]" att[2]="att[3]" att[4]isNull
*/
static void
xml_startelem(void *userData, const XML_Char *name, const XML_Char **atts)
{
struct xml_data* data = (struct xml_data*)userData;
if(verb>=4) printf("xml tag start '%s'\n", name);
free(data->tag);
data->tag = strdup(name);
if(!data->tag) {
if(verb) printf("out of memory\n");
exit(0);
}
if(verb>=4) {
int i;
for(i=0; atts[i]; i+=2) {
printf(" %s='%s'\n", atts[i], atts[i+1]);
}
}
/* handle attributes to particular types */
if(strcasecmp(name, "KeyDigest") == 0) {
handle_keydigest(data, atts);
}
/* write whitespace separators to outputBIO here */
if(!data->use_key)
return;
if(strcasecmp(data->tag, "KeyTag") == 0 ||
strcasecmp(data->tag, "Algorithm") == 0 ||
strcasecmp(data->tag, "DigestType") == 0 ||
strcasecmp(data->tag, "Digest") == 0) {
if(BIO_write(data->ds, " ", 1) <= 0) {
if(verb) printf("out of memory in BIO_write\n");
exit(0);
}
}
}
/**
* XML end of element. This callback is called whenever an XML tag ends.
* XML_Char is UTF8.
* @param userData: the xml_data structure
* @param name: the tag that ends.
*/
static void
xml_endelem(void *userData, const XML_Char *name)
{
struct xml_data* data = (struct xml_data*)userData;
if(verb>=4) printf("xml tag end '%s'\n", name);
free(data->tag);
data->tag = NULL;
if(strcasecmp(name, "KeyDigest") == 0) {
data->use_key = 0;
if(BIO_write(data->ds, "\n", 1) <= 0) {
if(verb) printf("out of memory in BIO_write\n");
exit(0);
}
}
}
/**
* XML parser setup of the callbacks for the tags
*/
static void
xml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now)
{
char buf[1024];
memset(data, 0, sizeof(*data));
XML_SetUserData(parser, data);
data->parser = parser;
data->date = now;
data->ds = BIO_new(BIO_s_mem());
if(!data->ds) {
if(verb) printf("out of memory\n");
exit(0);
}
snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s",
ctime(&now));
if(BIO_write(data->ds, buf, (int)strlen(buf)) <= 0) {
if(verb) printf("out of memory\n");
exit(0);
}
XML_SetElementHandler(parser, xml_startelem, xml_endelem);
XML_SetCharacterDataHandler(parser, xml_charhandle);
}
/**
* Perform XML parsing of the root-anchors file
* Its format description can be read here
* https://data.iana.org/root-anchors/draft-icann-dnssec-trust-anchor.txt
* It uses libexpat.
* @param xml: BIO with xml data.
* @param now: the current time for checking DS validity periods.
* @return memoryBIO with the DS data in zone format.
* or NULL if the zone is insecure.
* (It exit()s on error)
*/
static BIO*
xml_parse(BIO* xml, time_t now)
{
char* pp;
int len;
XML_Parser parser;
struct xml_data data;
parser = XML_ParserCreate(NULL);
if(!parser) {
if(verb) printf("could not XML_ParserCreate\n");
exit(0);
}
/* setup callbacks */
xml_parse_setup(parser, &data, now);
/* parse it */
BIO_reset(xml);
len = (int)BIO_get_mem_data(xml, &pp);
if(!len || !pp) {
if(verb) printf("out of memory\n");
exit(0);
}
if(!XML_Parse(parser, pp, len, 1 /*isfinal*/ )) {
const char *e = XML_ErrorString(XML_GetErrorCode(parser));
if(verb) printf("XML_Parse failure %s\n",
e?e:"");
exit(0);
}
/* parsed */
if(verb) printf("XML was parsed successfully, %d keys\n",
data.num_keys);
free(data.tag);
XML_ParserFree(parser);
if(verb >= 4) {
char* pp = NULL;
int len;
BIO_seek(data.ds, 0);
len = BIO_get_mem_data(data.ds, &pp);
printf("got DS bio %d: '", len);
(void)fwrite(pp, (size_t)len, 1, stdout);
printf("'\n");
}
if(data.num_keys == 0) {
/* the root zone seems to have gone insecure */
BIO_free(data.ds);
return NULL;
} else {
return data.ds;
}
}
/** verify a PKCS7 signature, false on failure */ /** verify a PKCS7 signature, false on failure */
static int static int
verify_p7sig(BIO* data, BIO* p7s, BIO* pem, STACK_OF(X509)* trust, time_t now) verify_p7sig(BIO* data, BIO* p7s, BIO* pem, STACK_OF(X509)* trust, time_t now)
@ -1132,6 +1384,58 @@ verify_p7sig(BIO* data, BIO* p7s, BIO* pem, STACK_OF(X509)* trust, time_t now)
return secure; return secure;
} }
/** write unsigned root anchor file, a 5011 revoked tp */
static void
write_unsigned_root(char* root_anchor_file)
{
FILE* out;
time_t now = time(NULL);
out = fopen(root_anchor_file, "w");
if(!out) {
if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
return;
}
if(fprintf(out, "; autotrust trust anchor file\n"
";;REVOKED\n"
";;id: . 1\n"
"; This file was written by unbound-anchor on %s"
"; It indicates that the root does not use DNSSEC\n"
"; to restart DNSSEC overwrite this file with a\n"
"; valid trustanchor or (empty-it and run unbound-anchor)\n"
, ctime(&now)) < 0) {
if(verb) printf("failed to write 'unsigned' to %s\n",
root_anchor_file);
if(verb && errno != 0) printf("%s\n", strerror(errno));
}
fclose(out);
}
/** write root anchor file */
static void
write_root_anchor(char* root_anchor_file, BIO* ds)
{
char* pp = NULL;
int len;
FILE* out;
BIO_seek(ds, 0);
len = BIO_get_mem_data(ds, &pp);
if(!len || !pp) {
if(verb) printf("out of memory\n");
return;
}
out = fopen(root_anchor_file, "w");
if(!out) {
if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
return;
}
if(fwrite(pp, (size_t)len, 1, out) != 1) {
if(verb) printf("failed to write all data to %s\n",
root_anchor_file);
if(verb && errno != 0) printf("%s\n", strerror(errno));
}
fclose(out);
}
/** Perform the verification and update of the trustanchor file */ /** Perform the verification and update of the trustanchor file */
static void static void
verify_and_update_anchor(char* root_anchor_file, char* debugconf, verify_and_update_anchor(char* root_anchor_file, char* debugconf,
@ -1139,6 +1443,7 @@ verify_and_update_anchor(char* root_anchor_file, char* debugconf,
STACK_OF(X509)* cert) STACK_OF(X509)* cert)
{ {
time_t now = get_time_now(debugconf); time_t now = get_time_now(debugconf);
BIO* ds;
/* verify xml file */ /* verify xml file */
if(!verify_p7sig(xml, p7s, pem, cert, now)) { if(!verify_p7sig(xml, p7s, pem, cert, now)) {
@ -1146,10 +1451,19 @@ verify_and_update_anchor(char* root_anchor_file, char* debugconf,
exit(0); exit(0);
} }
/* parse the xml file into DS records */
ds = xml_parse(xml, now);
if(!ds) {
/* the root zone is unsigned now */
write_unsigned_root(root_anchor_file);
} else {
/* see if xml file verifies the dnskey that was probed */ /* see if xml file verifies the dnskey that was probed */
/* TODO */
/* reinstate 5011 tracking */ /* reinstate 5011 tracking */
write_root_anchor(root_anchor_file, ds);
}
BIO_free(ds);
} }
/** perform actual certupdate work */ /** perform actual certupdate work */
@ -1176,7 +1490,7 @@ do_certupdate(char* root_anchor_file, char* root_cert_file,
pem = https(ip_list, pemname, urlname); pem = https(ip_list, pemname, urlname);
/* update the pem file (optional) */ /* update the pem file (optional) */
/*do_pem_update(cert, pem, &write_cert);*/ /*do_pem_update(cert, pem, &write_cert); TODO */
if(write_cert) { if(write_cert) {
(void)write_cert_file(root_cert_file, cert); (void)write_cert_file(root_cert_file, cert);
if(verb) printf("wrote cert to %s\n", root_cert_file); if(verb) printf("wrote cert to %s\n", root_cert_file);
@ -1519,10 +1833,12 @@ int main(int argc, char* argv[])
argv += optind; argv += optind;
if(argc != 0) if(argc != 0)
usage(); usage();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
ERR_load_SSL_strings(); ERR_load_SSL_strings();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
(void)SSL_library_init(); (void)SSL_library_init();
return do_root_update_work(root_anchor_file, root_cert_file, return do_root_update_work(root_anchor_file, root_cert_file,
urlname, xmlname, p7sname, pemname, urlname, xmlname, p7sname, pemname,
res_conf, root_hints, debugconf, ip4only, ip6only, force); res_conf, root_hints, debugconf, ip4only, ip6only, force);