them, the same format as in the zone file. Has to be on a single line, with
"" around it. A TTL can be specified for ease of cut and paste, but is ignored.
A class can be specified, but class IN is default.
+.It \fBtrusted-keys-file:\fR <filename>
+File with trusted keys for validation. Specify more than one file
+with several entries, one file per entry. Like \fBtrust-anchor-file\fR
+but has a different file format. Format is BIND-9 style format,
+the trusted-keys { name flag proto algo "key"; }; clauses are read.
.It \fBval-override-date:\fR <rrsig-style date spec>
Default is "" or "0", which disables this debugging feature. If enabled by
giving a RRSIG style date, that date is used for verifying RRSIG inception
%token VAR_TRUST_ANCHOR_FILE VAR_TRUST_ANCHOR VAR_VAL_OVERRIDE_DATE
%token VAR_BOGUS_TTL VAR_VAL_CLEAN_ADDITIONAL VAR_VAL_PERMISSIVE_MODE
%token VAR_INCOMING_NUM_TCP VAR_MSG_BUFFER_SIZE VAR_KEY_CACHE_SIZE
-%token VAR_KEY_CACHE_SLABS
+%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_trust_anchor | server_val_override_date | server_bogus_ttl |
server_val_clean_additional | server_val_permissive_mode |
server_incoming_num_tcp | server_msg_buffer_size |
- server_key_cache_size | server_key_cache_slabs
+ server_key_cache_size | server_key_cache_slabs |
+ server_trusted_keys_file
;
stubstart: VAR_STUB_ZONE
{
yyerror("out of memory");
}
;
+server_trusted_keys_file: VAR_TRUSTED_KEYS_FILE STRING
+ {
+ OUTYY(("P(server_trusted_keys_file:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ trusted_keys_file_list, $2))
+ yyerror("out of memory");
+ }
+ ;
server_trust_anchor: VAR_TRUST_ANCHOR STRING
{
OUTYY(("P(server_trust_anchor:%s)\n", $2));
return ok;
}
+/** skip file to end of line */
+static void
+skip_to_eol(FILE* in)
+{
+ int c;
+ while((c = getc(in)) != EOF ) {
+ if(c == '\n')
+ return;
+ }
+}
+
+/** true for special characters in bind configs */
+static int
+is_bind_special(int c)
+{
+ switch(c) {
+ case '{':
+ case '}':
+ case '"':
+ case ';':
+ return 1;
+ }
+ return 0;
+}
+
+/** Read a keyword skipping bind comments; spaces, specials, restkeywords. */
+static int
+readkeyword_bindfile(FILE* in, ldns_buffer* buf, int* line)
+{
+ int c;
+ int numdone = 0;
+ while((c = getc(in)) != EOF ) {
+ if(c == '#') { /* # blabla */
+ skip_to_eol(in);
+ (*line)++;
+ continue;
+ } else if(c=='/' && numdone>0 && /* /_/ blabla */
+ ldns_buffer_read_u8_at(buf,
+ ldns_buffer_position(buf)-1) == '/') {
+ ldns_buffer_skip(buf, -1);
+ numdone--;
+ skip_to_eol(in);
+ (*line)++;
+ continue;
+ } else if(c=='*' && numdone>0 && /* /_* blabla *_/ */
+ ldns_buffer_read_u8_at(buf,
+ ldns_buffer_position(buf)-1) == '/') {
+ ldns_buffer_skip(buf, -1);
+ /* skip to end of comment */
+ while(c != EOF && (c=getc(in)) != EOF ) {
+ if(c == '*') {
+ if((c=getc(in)) == '/')
+ break;
+ }
+ if(c == '\n')
+ (*line)++;
+ }
+ continue;
+ }
+ /* not a comment, complete the keyword */
+ if(numdone > 0) {
+ /* check same type */
+ if(isspace(c)) {
+ ungetc(c, in);
+ return numdone;
+ }
+ if(is_bind_special(c)) {
+ ungetc(c, in);
+ return numdone;
+ }
+ }
+ if(c == '\n')
+ (*line)++;
+ if(ldns_buffer_remaining(buf) < 1) {
+ fatal_exit("trusted-keys, %d, string too long", *line);
+ }
+ ldns_buffer_write_u8(buf, c);
+ numdone++;
+ if(isspace(c))
+ return numdone;
+ if(is_bind_special(c))
+ return numdone;
+ }
+ return numdone;
+}
+
+/** skip through file to { */
+static int
+skip_to_brace_open(FILE* in, int* line)
+{
+ int c;
+ while((c = getc(in)) != EOF ) {
+ if(c == '\n')
+ (*line)++;
+ if(isspace(c))
+ continue;
+ if(c != '{') {
+ log_err("trusted-keys, line %d, expected {", *line);
+ return 0;
+ }
+ return 1;
+ }
+ log_err("trusted-keys, line %d, expected {", *line);
+ return 0;
+}
+
+static int
+process_bind_contents(struct val_anchors* anchors, ldns_buffer* buffer,
+ int* line)
+{
+ char* str = 0;
+ if(!anchor_store_str(anchors, buffer, str)) {
+ }
+}
+
+/**
+ * Read a BIND9 like file with trust anchors in named.conf format.
+ * @param anchors: anchor storage.
+ * @param buffer: parsing buffer.
+ * @param fname: string.
+ * @return false on error.
+ */
+static int
+anchor_read_bind_file(struct val_anchors* anchors, ldns_buffer* buffer,
+ const char* fname)
+{
+ int line_nr = 1;
+ FILE* in = fopen(fname, "r");
+ int rdlen = 0;
+ if(!in) {
+ log_err("error opening file %s: %s", fname, strerror(errno));
+ return 0;
+ }
+ fclose(in);
+ /* scan for trusted-keys keyword, ignore everything else */
+ ldns_buffer_clear(buffer);
+ while((rdlen=readkeyword_bindfile(in, buffer, &line_nr)) != 0) {
+ if(rdlen != 12 || strncmp((char*)ldns_buffer_begin(buffer),
+ "trusted-keys", 12) != 0) {
+ ldns_buffer_clear(buffer);
+ /* ignore everything but trusted-keys */
+ continue;
+ }
+ if(!skip_to_brace_open(in, &line_nr)) {
+ log_err("error in trusted key: \"%s\"", fname);
+ return 0;
+ }
+ /* process contents */
+ if(!process_bind_contents(anchors, buffer, &line_nr)) {
+ log_err("error in trusted key: \"%s\"", fname);
+ return 0;
+ }
+ ldns_buffer_clear(buffer);
+ }
+ return 1;
+}
+
/**
* Assemble an rrset structure for the type
* @param region: allocated in this region.
return 0;
}
}
+ for(f = cfg->trusted_keys_file_list; f; f = f->next) {
+ if(!f->str || f->str[0] == 0) /* empty "" */
+ continue;
+ if(!anchor_read_bind_file(anchors, parsebuf, f->str)) {
+ log_err("error reading trusted-keys-file: %s", f->str);
+ ldns_buffer_free(parsebuf);
+ return 0;
+ }
+ }
for(f = cfg->trust_anchor_list; f; f = f->next) {
if(!f->str || f->str[0] == 0) /* empty "" */
continue;