2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 15:45:25 +00:00

dnssec-settime: Allow manipulating state files

Introduce a new option '-s' for dnssec-settime that when manipulating
timing metadata, it also updates the key state file.

For testing purposes, add options to dnssec-settime to set key
states and when they last changed.

The dst code adds ways to write and read the new key states and
timing metadata. It updates the parsing code for private key files
to not parse the newly introduced metadata (these are for state
files only).

Introduce key goal (the state the key wants to be in).
This commit is contained in:
Matthijs Mekking
2019-09-12 11:57:55 +02:00
parent c55625b035
commit 72042a06d6
10 changed files with 618 additions and 94 deletions

View File

@@ -70,20 +70,21 @@
goto cleanup; \
}
#define NEXTTOKEN_OR_EOF(lex, opt, token) { \
ret = isc_lex_gettoken(lex, opt, token); \
if (ret == ISC_R_EOF) \
break; \
if (ret != ISC_R_SUCCESS) \
goto cleanup; \
}
#define NEXTTOKEN_OR_EOF(lex, opt, token) \
do { \
ret = isc_lex_gettoken(lex, opt, token); \
if (ret == ISC_R_EOF) \
break; \
if (ret != ISC_R_SUCCESS) \
goto cleanup; \
} while ((*token).type == isc_tokentype_eol); \
#define READLINE(lex, opt, token) \
do { \
ret = isc_lex_gettoken(lex, opt, token); \
if (ret == ISC_R_EOF) \
break; \
else if (ret != ISC_R_SUCCESS) \
if (ret != ISC_R_SUCCESS) \
goto cleanup; \
} while ((*token).type != isc_tokentype_eol)
@@ -94,6 +95,10 @@
#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
static const char *numerictags[NUMERIC_NTAGS] = {
"Predecessor:",
"Successor:",
"MaxTTL:",
"RollPeriod:",
"Lifetime:"
};
@@ -108,18 +113,38 @@ static const char *timingtags[TIMING_NTAGS] = {
"Generated:",
"Published:",
"Active:",
"Retired:",
"Revoked:",
"Retired:",
"Removed:",
"DSPublish:",
"SyncPublish:",
"SyncDelete:"
"SyncDelete:",
"DNSKEYChange:",
"ZRRSIGChange:",
"KRRSIGChange:",
"DSChange:"
};
#define KEYSTATES_NTAGS (DST_MAX_KEYSTATES + 1)
static const char *keystatestags[KEYSTATES_NTAGS] = {
"DNSKEYState:",
"ZRRSIGState:",
"KRRSIGState:",
"DSState:",
"GoalState:"
};
#define KEYSTATES_NVALUES 4
static const char *keystates[KEYSTATES_NVALUES] = {
"hidden", "rumoured", "omnipresent", "unretentive",
};
#define STATE_ALGORITHM_STR "Algorithm:"
#define STATE_LENGTH_STR "Length:"
#define MAX_NTAGS (DST_MAX_NUMERIC + DST_MAX_BOOLEAN + DST_MAX_TIMES)
#define MAX_NTAGS (DST_MAX_NUMERIC + DST_MAX_BOOLEAN + \
DST_MAX_TIMES + DST_MAX_KEYSTATES)
static dst_func_t *dst_t_func[DST_MAX_ALGS];
@@ -604,10 +629,23 @@ dst_key_fromnamedfile(const char *filename, const char *dirname,
return (result);
}
key = get_key_struct(pubkey->key_name, pubkey->key_alg,
pubkey->key_flags, pubkey->key_proto,
pubkey->key_size, pubkey->key_class,
pubkey->key_ttl, mctx);
if (key == NULL) {
dst_key_free(&pubkey);
return (ISC_R_NOMEMORY);
}
if (key->func->parse == NULL)
RETERR(DST_R_UNSUPPORTEDALG);
/*
* Read the state file, if requested by type.
*/
if ((type & DST_TYPE_STATE) != 0) {
newfilenamelen = strlen(filename) + 7;
if (dirname != NULL) {
newfilenamelen += strlen(dirname) + 1;
@@ -617,23 +655,17 @@ dst_key_fromnamedfile(const char *filename, const char *dirname,
dirname, filename, ".state");
INSIST(result == ISC_R_SUCCESS);
result = dst_key_read_state(newfilename, mctx, pubkey);
result = dst_key_read_state(newfilename, mctx, &key);
if (result == ISC_R_FILENOTFOUND) {
/* Having no state is valid. */
result = ISC_R_SUCCESS;
}
isc_mem_put(mctx, newfilename, newfilenamelen);
newfilename = NULL;
RETERR(result);
}
key = get_key_struct(pubkey->key_name, pubkey->key_alg,
pubkey->key_flags, pubkey->key_proto, 0,
pubkey->key_class, pubkey->key_ttl, mctx);
if (key == NULL) {
dst_key_free(&pubkey);
return (ISC_R_NOMEMORY);
}
if (key->func->parse == NULL)
RETERR(DST_R_UNSUPPORTEDALG);
newfilenamelen = strlen(filename) + 9;
if (dirname != NULL)
newfilenamelen += strlen(dirname) + 1;
@@ -1611,17 +1643,32 @@ find_timingdata(const char *s) {
return (find_metadata(s, timingtags, TIMING_NTAGS));
}
static int
find_keystatedata(const char *s) {
return (find_metadata(s, keystatestags, KEYSTATES_NTAGS));
}
static isc_result_t
keystate_fromtext(const char *s, dst_key_state_t *state) {
for (int i = 0; i < KEYSTATES_NVALUES; i++) {
if (keystates[i] != NULL && strcasecmp(s, keystates[i]) == 0) {
*state = (dst_key_state_t) i;
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
/*%
* Reads a key state from disk.
*/
isc_result_t
dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t **keyp)
{
isc_lex_t *lex = NULL;
isc_token_t token;
isc_result_t ret;
unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
unsigned int opt = ISC_LEXOPT_EOL;
ret = isc_lex_create(mctx, 1500, &lex);
if (ret != ISC_R_SUCCESS) {
@@ -1634,6 +1681,11 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
goto cleanup;
}
/*
* Read the comment line.
*/
READLINE(lex, opt, &token);
/*
* Read the algorithm line.
*/
@@ -1646,11 +1698,13 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
if (token.type != isc_tokentype_number ||
token.value.as_ulong != (unsigned long) dst_key_alg(key))
token.value.as_ulong != (unsigned long) dst_key_alg(*keyp))
{
BADTOKEN();
}
READLINE(lex, opt, &token);
/*
* Read the length line.
*/
@@ -1663,11 +1717,13 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
if (token.type != isc_tokentype_number ||
token.value.as_ulong != (unsigned long) dst_key_size(key))
token.value.as_ulong != (unsigned long) dst_key_size(*keyp))
{
BADTOKEN();
}
READLINE(lex, opt, &token);
/*
* Read the metadata.
*/
@@ -1675,6 +1731,9 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
int tag;
NEXTTOKEN_OR_EOF(lex, opt, &token);
if (ret == ISC_R_EOF) {
break;
}
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
@@ -1682,12 +1741,14 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
/* Numeric metadata */
tag = find_numericdata(DST_AS_STR(token));
if (tag >= 0) {
INSIST(tag < NUMERIC_NTAGS);
NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
if (token.type != isc_tokentype_number) {
BADTOKEN();
}
dst_key_setnum(key, tag, token.value.as_ulong);
dst_key_setnum(*keyp, tag, token.value.as_ulong);
goto next;
}
@@ -1700,14 +1761,14 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
if (strcmp(DST_AS_STR(token), "yes") == 0) {
dst_key_setbool(key, tag, true);
dst_key_setbool(*keyp, tag, true);
} else if (strcmp(DST_AS_STR(token), "no") == 0) {
dst_key_setbool(key, tag, false);
dst_key_setbool(*keyp, tag, false);
} else {
BADTOKEN();
}
goto next;
}
@@ -1727,13 +1788,35 @@ dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t *key)
if (ret != ISC_R_SUCCESS) {
goto cleanup;
}
dst_key_settime(key, tag, when);
dst_key_settime(*keyp, tag, when);
goto next;
}
/* Keystate metadata */
tag = find_keystatedata(DST_AS_STR(token));
if (tag >= 0) {
dst_key_state_t state;
INSIST(tag < KEYSTATES_NTAGS);
NEXTTOKEN(lex, opt, &token);
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
ret = keystate_fromtext(DST_AS_STR(token), &state);
if (ret != ISC_R_SUCCESS) {
goto cleanup;
}
dst_key_setstate(*keyp, tag, state);
goto next;
}
next:
READLINE(lex, opt, &token);
}
/* Done, successfully parsed the whole file. */
@@ -1847,6 +1930,21 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
fprintf(stream, "%s: (set, unable to display)\n", tag);
}
/*%
* Write key state metadata to a file pointer, preceded by 'tag'
*/
static void
printstate(const dst_key_t *key, int type, const char *tag, FILE *stream) {
isc_result_t result;
dst_key_state_t value = 0;
result = dst_key_getstate(key, type, &value);
if (result != ISC_R_SUCCESS) {
return;
}
fprintf(stream, "%s: %s\n", tag, keystates[value]);
}
/*%
* Writes a key state to disk.
*/
@@ -1898,6 +1996,11 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
fprintf(fp, "Algorithm: %u\n", key->key_alg);
fprintf(fp, "Length: %u\n", key->key_size);
printnum(key, DST_NUM_LIFETIME, "Lifetime", fp);
printbool(key, DST_BOOL_KSK, "KSK", fp);
printbool(key, DST_BOOL_ZSK, "ZSK", fp);
printtime(key, DST_TIME_CREATED, "Generated", fp);
printtime(key, DST_TIME_PUBLISH, "Published", fp);
printtime(key, DST_TIME_ACTIVATE, "Active", fp);
@@ -1905,10 +2008,16 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
printtime(key, DST_TIME_REVOKE, "Revoked", fp);
printtime(key, DST_TIME_DELETE, "Removed", fp);
printnum(key, DST_NUM_LIFETIME, "Lifetime", fp);
printtime(key, DST_TIME_DNSKEY, "DNSKEYChange", fp);
printtime(key, DST_TIME_ZRRSIG, "ZRRSIGChange", fp);
printtime(key, DST_TIME_KRRSIG, "KRRSIGChange", fp);
printtime(key, DST_TIME_DS, "DSChange", fp);
printbool(key, DST_BOOL_KSK, "KSK", fp);
printbool(key, DST_BOOL_ZSK, "ZSK", fp);
printstate(key, DST_KEY_DNSKEY, "DNSKEYState", fp);
printstate(key, DST_KEY_ZRRSIG, "ZRRSIGState", fp);
printstate(key, DST_KEY_KRRSIG, "KRRSIGState", fp);
printstate(key, DST_KEY_DS, "DSState", fp);
printstate(key, DST_KEY_GOAL, "GoalState", fp);
}
fflush(fp);