mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Implement dnssec-ksr sign
Add code that can create a Signed Key Response (SKR) given a Key Signing Request (KSR), a DNSSEC policy, a set of keys and an interval.
This commit is contained in:
@@ -13,13 +13,16 @@
|
|||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <isc/buffer.h>
|
#include <isc/buffer.h>
|
||||||
#include <isc/commandline.h>
|
#include <isc/commandline.h>
|
||||||
#include <isc/fips.h>
|
#include <isc/fips.h>
|
||||||
|
#include <isc/lex.h>
|
||||||
#include <isc/mem.h>
|
#include <isc/mem.h>
|
||||||
|
|
||||||
|
#include <dns/callbacks.h>
|
||||||
#include <dns/dnssec.h>
|
#include <dns/dnssec.h>
|
||||||
#include <dns/fixedname.h>
|
#include <dns/fixedname.h>
|
||||||
#include <dns/keyvalues.h>
|
#include <dns/keyvalues.h>
|
||||||
@@ -27,6 +30,7 @@
|
|||||||
#include <dns/rdatalist.h>
|
#include <dns/rdatalist.h>
|
||||||
#include <dns/rdataset.h>
|
#include <dns/rdataset.h>
|
||||||
#include <dns/time.h>
|
#include <dns/time.h>
|
||||||
|
#include <dns/ttl.h>
|
||||||
|
|
||||||
#include "dnssectool.h"
|
#include "dnssectool.h"
|
||||||
|
|
||||||
@@ -50,6 +54,7 @@ static dns_name_t *name = NULL;
|
|||||||
struct ksr_ctx {
|
struct ksr_ctx {
|
||||||
const char *policy;
|
const char *policy;
|
||||||
const char *configfile;
|
const char *configfile;
|
||||||
|
const char *file;
|
||||||
const char *keydir;
|
const char *keydir;
|
||||||
dns_keystore_t *keystore;
|
dns_keystore_t *keystore;
|
||||||
isc_stdtime_t now;
|
isc_stdtime_t now;
|
||||||
@@ -65,6 +70,8 @@ struct ksr_ctx {
|
|||||||
time_t propagation;
|
time_t propagation;
|
||||||
time_t publishsafety;
|
time_t publishsafety;
|
||||||
time_t retiresafety;
|
time_t retiresafety;
|
||||||
|
time_t sigrefresh;
|
||||||
|
time_t sigvalidity;
|
||||||
time_t signdelay;
|
time_t signdelay;
|
||||||
time_t ttlsig;
|
time_t ttlsig;
|
||||||
};
|
};
|
||||||
@@ -77,6 +84,29 @@ typedef struct ksr_ctx ksr_ctx_t;
|
|||||||
static int min_rsa = 1024;
|
static int min_rsa = 1024;
|
||||||
static int min_dh = 128;
|
static int min_dh = 128;
|
||||||
|
|
||||||
|
#define KSR_LINESIZE 1500 /* should be long enough for any DNSKEY record */
|
||||||
|
#define DATETIME_INDEX 25
|
||||||
|
|
||||||
|
#define TTL_MAX INT32_MAX
|
||||||
|
#define MAXWIRE (64 * 1024)
|
||||||
|
|
||||||
|
#define STR(t) ((t).value.as_textregion.base)
|
||||||
|
|
||||||
|
#define READLINE(lex, opt, token)
|
||||||
|
|
||||||
|
#define NEXTTOKEN(lex, opt, token) \
|
||||||
|
{ \
|
||||||
|
ret = isc_lex_gettoken(lex, opt, token); \
|
||||||
|
if (ret != ISC_R_SUCCESS) \
|
||||||
|
goto cleanup; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BADTOKEN() \
|
||||||
|
{ \
|
||||||
|
ret = ISC_R_UNEXPECTEDTOKEN; \
|
||||||
|
goto cleanup; \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK(r) \
|
#define CHECK(r) \
|
||||||
ret = (r); \
|
ret = (r); \
|
||||||
if (ret != ISC_R_SUCCESS) { \
|
if (ret != ISC_R_SUCCESS) { \
|
||||||
@@ -91,20 +121,23 @@ usage(int ret) {
|
|||||||
fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
|
fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "Options:\n");
|
fprintf(stderr, "Options:\n");
|
||||||
fprintf(stderr, " -e <date/offset>: end date\n");
|
|
||||||
fprintf(stderr, " -E <engine>: name of an OpenSSL engine to use\n");
|
fprintf(stderr, " -E <engine>: name of an OpenSSL engine to use\n");
|
||||||
|
fprintf(stderr, " -e <date/offset>: end date\n");
|
||||||
fprintf(stderr, " -F: FIPS mode\n");
|
fprintf(stderr, " -F: FIPS mode\n");
|
||||||
|
fprintf(stderr, " -f: KSR file to sign\n");
|
||||||
fprintf(stderr, " -i <date/offset>: start date\n");
|
fprintf(stderr, " -i <date/offset>: start date\n");
|
||||||
fprintf(stderr, " -K <directory>: write keys into directory\n");
|
fprintf(stderr, " -K <directory>: key directory\n");
|
||||||
fprintf(stderr, " -k <policy>: name of a DNSSEC policy\n");
|
fprintf(stderr, " -k <policy>: name of a DNSSEC policy\n");
|
||||||
fprintf(stderr, " -l <file>: file with dnssec-policy config\n");
|
fprintf(stderr, " -l <file>: file with dnssec-policy config\n");
|
||||||
fprintf(stderr, " -h: print usage and exit\n");
|
fprintf(stderr, " -h: print usage and exit\n");
|
||||||
fprintf(stderr, " -v <level>: set verbosity level\n");
|
|
||||||
fprintf(stderr, " -V: print version information\n");
|
fprintf(stderr, " -V: print version information\n");
|
||||||
|
fprintf(stderr, " -v <level>: set verbosity level\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "Commands:\n");
|
fprintf(stderr, "Commands:\n");
|
||||||
fprintf(stderr, " keygen: pregenerate ZSKs\n");
|
fprintf(stderr, " keygen: pregenerate ZSKs\n");
|
||||||
fprintf(stderr, " request: create a Key Signing Request (KSR)\n");
|
fprintf(stderr, " request: create a Key Signing Request (KSR)\n");
|
||||||
|
fprintf(stderr, " sign: sign a KSR, creating a Signed Key "
|
||||||
|
"Response (SKR)\n");
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +241,8 @@ setcontext(ksr_ctx_t *ksr, dns_kasp_t *kasp) {
|
|||||||
ksr->propagation = dns_kasp_zonepropagationdelay(kasp);
|
ksr->propagation = dns_kasp_zonepropagationdelay(kasp);
|
||||||
ksr->publishsafety = dns_kasp_publishsafety(kasp);
|
ksr->publishsafety = dns_kasp_publishsafety(kasp);
|
||||||
ksr->retiresafety = dns_kasp_retiresafety(kasp);
|
ksr->retiresafety = dns_kasp_retiresafety(kasp);
|
||||||
|
ksr->sigvalidity = dns_kasp_sigvalidity_dnskey(kasp);
|
||||||
|
ksr->sigrefresh = dns_kasp_sigrefresh(kasp);
|
||||||
ksr->signdelay = dns_kasp_signdelay(kasp);
|
ksr->signdelay = dns_kasp_signdelay(kasp);
|
||||||
ksr->ttl = dns_kasp_dnskeyttl(kasp);
|
ksr->ttl = dns_kasp_dnskeyttl(kasp);
|
||||||
ksr->ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
ksr->ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||||
@@ -247,6 +282,27 @@ progress(int p) {
|
|||||||
(void)fflush(stderr);
|
(void)fflush(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freerrset(dns_rdataset_t *rdataset) {
|
||||||
|
dns_rdatalist_t *rdlist;
|
||||||
|
dns_rdata_t *rdata;
|
||||||
|
|
||||||
|
if (!dns_rdataset_isassociated(rdataset)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_rdatalist_fromrdataset(rdataset, &rdlist);
|
||||||
|
|
||||||
|
for (rdata = ISC_LIST_HEAD(rdlist->rdata); rdata != NULL;
|
||||||
|
rdata = ISC_LIST_HEAD(rdlist->rdata))
|
||||||
|
{
|
||||||
|
ISC_LIST_UNLINK(rdlist->rdata, rdata, link);
|
||||||
|
isc_mem_put(mctx, rdata, sizeof(*rdata));
|
||||||
|
}
|
||||||
|
isc_mem_put(mctx, rdlist, sizeof(*rdlist));
|
||||||
|
dns_rdataset_disassociate(rdataset);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
||||||
isc_stdtime_t inception, isc_stdtime_t active,
|
isc_stdtime_t inception, isc_stdtime_t active,
|
||||||
@@ -547,6 +603,161 @@ fail:
|
|||||||
return (next_bundle);
|
return (next_bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration,
|
||||||
|
dns_rdataset_t *rrset, dns_dnsseckeylist_t *keys) {
|
||||||
|
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
|
||||||
|
char utc[sizeof("YYYYMMDDHHSSMM")];
|
||||||
|
dns_rdatalist_t *rrsiglist = NULL;
|
||||||
|
dns_rdataset_t rrsigset = DNS_RDATASET_INIT;
|
||||||
|
isc_buffer_t timebuf;
|
||||||
|
isc_buffer_t b;
|
||||||
|
isc_region_t r;
|
||||||
|
isc_result_t ret;
|
||||||
|
|
||||||
|
UNUSED(ksr);
|
||||||
|
|
||||||
|
/* Bundle header */
|
||||||
|
isc_buffer_init(&timebuf, timestr, sizeof(timestr));
|
||||||
|
isc_stdtime_tostring(inception, timestr, sizeof(timestr));
|
||||||
|
isc_buffer_init(&b, utc, sizeof(utc));
|
||||||
|
ret = dns_time32_totext(inception, &b);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
fatal("failed to convert bundle time32 to text: %s",
|
||||||
|
isc_result_totext(ret));
|
||||||
|
}
|
||||||
|
isc_buffer_usedregion(&b, &r);
|
||||||
|
fprintf(stdout, ";; SignedKeyResponse 1.0 %.*s (%s)\n", (int)r.length,
|
||||||
|
r.base, timestr);
|
||||||
|
|
||||||
|
/* DNSKEY RRset */
|
||||||
|
print_rdata(rrset);
|
||||||
|
|
||||||
|
/* Signatures */
|
||||||
|
rrsiglist = isc_mem_get(mctx, sizeof(*rrsiglist));
|
||||||
|
dns_rdatalist_init(rrsiglist);
|
||||||
|
rrsiglist->rdclass = dns_rdataclass_in;
|
||||||
|
rrsiglist->type = dns_rdatatype_rrsig;
|
||||||
|
rrsiglist->ttl = rrset->ttl;
|
||||||
|
for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
|
||||||
|
dk = ISC_LIST_NEXT(dk, link))
|
||||||
|
{
|
||||||
|
isc_buffer_t buf;
|
||||||
|
isc_buffer_t *newbuf = NULL;
|
||||||
|
dns_rdata_t *rdata = NULL;
|
||||||
|
dns_rdata_t *rrsig = NULL;
|
||||||
|
isc_region_t rs;
|
||||||
|
unsigned char rdatabuf[SIG_FORMATSIZE];
|
||||||
|
isc_stdtime_t clockskew = inception - 3600;
|
||||||
|
|
||||||
|
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
||||||
|
rrsig = isc_mem_get(mctx, sizeof(*rrsig));
|
||||||
|
dns_rdata_init(rdata);
|
||||||
|
dns_rdata_init(rrsig);
|
||||||
|
isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
|
||||||
|
ret = dns_dnssec_sign(name, rrset, dk->key, &clockskew,
|
||||||
|
&expiration, mctx, &buf, rdata);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
fatal("failed to sign KSR");
|
||||||
|
}
|
||||||
|
isc_buffer_usedregion(&buf, &rs);
|
||||||
|
isc_buffer_allocate(mctx, &newbuf, rs.length);
|
||||||
|
isc_buffer_putmem(newbuf, rs.base, rs.length);
|
||||||
|
isc_buffer_usedregion(newbuf, &rs);
|
||||||
|
dns_rdata_fromregion(rrsig, dns_rdataclass_in,
|
||||||
|
dns_rdatatype_rrsig, &rs);
|
||||||
|
ISC_LIST_APPEND(rrsiglist->rdata, rrsig, link);
|
||||||
|
isc_buffer_clear(newbuf);
|
||||||
|
}
|
||||||
|
dns_rdatalist_tordataset(rrsiglist, &rrsigset);
|
||||||
|
print_rdata(&rrsigset);
|
||||||
|
freerrset(&rrsigset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sign_bundle(ksr_ctx_t *ksr, isc_stdtime_t inception,
|
||||||
|
isc_stdtime_t next_inception, dns_rdatalist_t *rdatalist,
|
||||||
|
dns_dnsseckeylist_t *keys) {
|
||||||
|
dns_rdataset_t rrset = DNS_RDATASET_INIT;
|
||||||
|
isc_stdtime_t expiration;
|
||||||
|
|
||||||
|
dns_rdataset_init(&rrset);
|
||||||
|
dns_rdatalist_tordataset(rdatalist, &rrset);
|
||||||
|
expiration = inception + ksr->sigvalidity;
|
||||||
|
while (inception <= next_inception) {
|
||||||
|
sign_rrset(ksr, inception, expiration, &rrset, keys);
|
||||||
|
inception = expiration - ksr->sigrefresh;
|
||||||
|
expiration = inception + ksr->sigvalidity;
|
||||||
|
}
|
||||||
|
freerrset(&rrset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isc_result_t
|
||||||
|
parse_dnskey(isc_lex_t *lex, char *owner, isc_buffer_t *buf, dns_ttl_t *ttl) {
|
||||||
|
dns_fixedname_t dfname;
|
||||||
|
dns_name_t *dname = NULL;
|
||||||
|
dns_rdataclass_t rdclass = dns_rdataclass_in;
|
||||||
|
isc_buffer_t b;
|
||||||
|
isc_result_t ret;
|
||||||
|
isc_token_t token;
|
||||||
|
unsigned int opt = ISC_LEXOPT_EOL;
|
||||||
|
|
||||||
|
isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
|
||||||
|
|
||||||
|
/* Read the domain name */
|
||||||
|
if (!strcmp(owner, "@")) {
|
||||||
|
BADTOKEN();
|
||||||
|
}
|
||||||
|
|
||||||
|
dname = dns_fixedname_initname(&dfname);
|
||||||
|
isc_buffer_init(&b, owner, strlen(owner));
|
||||||
|
isc_buffer_add(&b, strlen(owner));
|
||||||
|
ret = dns_name_fromtext(dname, &b, dns_rootname, 0, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
if (dns_name_compare(dname, name) != 0) {
|
||||||
|
return (DNS_R_BADOWNERNAME);
|
||||||
|
}
|
||||||
|
isc_buffer_clear(&b);
|
||||||
|
|
||||||
|
/* Read the next word: either TTL, class, or type */
|
||||||
|
NEXTTOKEN(lex, opt, &token);
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
BADTOKEN();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's a TTL, read the next one */
|
||||||
|
ret = dns_ttl_fromtext(&token.value.as_textregion, ttl);
|
||||||
|
if (ret == ISC_R_SUCCESS) {
|
||||||
|
NEXTTOKEN(lex, opt, &token);
|
||||||
|
}
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
BADTOKEN();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's a class, read the next one */
|
||||||
|
ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
|
||||||
|
if (ret == ISC_R_SUCCESS) {
|
||||||
|
NEXTTOKEN(lex, opt, &token);
|
||||||
|
}
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
BADTOKEN();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must be the type */
|
||||||
|
if (strcasecmp(STR(token), "DNSKEY") != 0) {
|
||||||
|
BADTOKEN();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dns_rdata_fromtext(NULL, rdclass, dns_rdatatype_dnskey, lex, name,
|
||||||
|
0, mctx, buf, NULL);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
isc_lex_setcomments(lex, 0);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
keygen(ksr_ctx_t *ksr) {
|
keygen(ksr_ctx_t *ksr) {
|
||||||
dns_kasp_t *kasp = NULL;
|
dns_kasp_t *kasp = NULL;
|
||||||
@@ -653,6 +864,174 @@ request(ksr_ctx_t *ksr) {
|
|||||||
cleanup(&keys, kasp);
|
cleanup(&keys, kasp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sign(ksr_ctx_t *ksr) {
|
||||||
|
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
|
||||||
|
bool have_bundle = false;
|
||||||
|
dns_dnsseckeylist_t keys;
|
||||||
|
dns_kasp_t *kasp = NULL;
|
||||||
|
dns_rdatalist_t *rdatalist = NULL;
|
||||||
|
isc_result_t ret;
|
||||||
|
isc_stdtime_t inception;
|
||||||
|
isc_lex_t *lex = NULL;
|
||||||
|
isc_lexspecials_t specials;
|
||||||
|
isc_token_t token;
|
||||||
|
unsigned int opt = ISC_LEXOPT_EOL;
|
||||||
|
|
||||||
|
/* Check parameters */
|
||||||
|
checkparams(ksr, "sign");
|
||||||
|
if (ksr->file == NULL) {
|
||||||
|
fatal("'sign' requires a KSR file");
|
||||||
|
}
|
||||||
|
/* Get the policy */
|
||||||
|
getkasp(ksr, &kasp);
|
||||||
|
/* Get keys */
|
||||||
|
get_dnskeys(ksr, &keys);
|
||||||
|
/* Set context */
|
||||||
|
setcontext(ksr, kasp);
|
||||||
|
/* Sign request */
|
||||||
|
inception = ksr->start;
|
||||||
|
isc_lex_create(mctx, KSR_LINESIZE, &lex);
|
||||||
|
memset(specials, 0, sizeof(specials));
|
||||||
|
specials['('] = 1;
|
||||||
|
specials[')'] = 1;
|
||||||
|
specials['"'] = 1;
|
||||||
|
isc_lex_setspecials(lex, specials);
|
||||||
|
ret = isc_lex_openfile(lex, ksr->file);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
fatal("unable to open KSR file %s: %s", ksr->file,
|
||||||
|
isc_result_totext(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ret = isc_lex_gettoken(lex, opt, &token); ret == ISC_R_SUCCESS;
|
||||||
|
ret = isc_lex_gettoken(lex, opt, &token))
|
||||||
|
{
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
fatal("bad KSR file %s(%lu): syntax error", ksr->file,
|
||||||
|
isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(STR(token), ";;") == 0) {
|
||||||
|
char bundle[KSR_LINESIZE];
|
||||||
|
isc_stdtime_t next_inception;
|
||||||
|
|
||||||
|
CHECK(isc_lex_gettoken(lex, opt, &token));
|
||||||
|
if (token.type != isc_tokentype_string ||
|
||||||
|
strcmp(STR(token), "KeySigningRequest") != 0)
|
||||||
|
{
|
||||||
|
fatal("bad KSR file %s(%lu): expected "
|
||||||
|
"'KeySigningRequest'",
|
||||||
|
ksr->file, isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(isc_lex_gettoken(lex, opt, &token));
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
fatal("bad KSR file %s(%lu): expected string",
|
||||||
|
ksr->file, isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(STR(token), "generated") == 0) {
|
||||||
|
/* Final bundle */
|
||||||
|
goto readline;
|
||||||
|
} else if (strcmp(STR(token), "1.0") != 0) {
|
||||||
|
fatal("bad KSR file %s(%lu): expected version",
|
||||||
|
ksr->file, isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
/* Date and time of bundle */
|
||||||
|
CHECK(isc_lex_gettoken(lex, opt, &token));
|
||||||
|
if (token.type != isc_tokentype_string) {
|
||||||
|
fatal("bad KSR file %s(%lu): expected datetime",
|
||||||
|
ksr->file, isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(STR(token), "%s", bundle);
|
||||||
|
next_inception = strtotime(bundle, ksr->now, ksr->now,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (have_bundle) {
|
||||||
|
/* Sign previous bundle */
|
||||||
|
sign_bundle(ksr, inception, next_inception,
|
||||||
|
rdatalist, &keys);
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start next bundle */
|
||||||
|
rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
|
||||||
|
dns_rdatalist_init(rdatalist);
|
||||||
|
rdatalist->rdclass = dns_rdataclass_in;
|
||||||
|
rdatalist->type = dns_rdatatype_dnskey;
|
||||||
|
rdatalist->ttl = TTL_MAX;
|
||||||
|
inception = next_inception;
|
||||||
|
have_bundle = true;
|
||||||
|
|
||||||
|
readline:
|
||||||
|
/* Read remainder of header line */
|
||||||
|
do {
|
||||||
|
ret = isc_lex_gettoken(lex, opt, &token);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
fatal("bad KSR file %s(%lu): bad "
|
||||||
|
"header (%s)",
|
||||||
|
ksr->file,
|
||||||
|
isc_lex_getsourceline(lex),
|
||||||
|
isc_result_totext(ret));
|
||||||
|
}
|
||||||
|
} while (token.type != isc_tokentype_eol);
|
||||||
|
} else {
|
||||||
|
/* Parse DNSKEY */
|
||||||
|
dns_ttl_t ttl = TTL_MAX;
|
||||||
|
isc_buffer_t buf;
|
||||||
|
isc_buffer_t *newbuf = NULL;
|
||||||
|
dns_rdata_t *rdata = NULL;
|
||||||
|
isc_region_t r;
|
||||||
|
u_char rdatabuf[DST_KEY_MAXSIZE];
|
||||||
|
|
||||||
|
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
||||||
|
dns_rdata_init(rdata);
|
||||||
|
isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
|
||||||
|
ret = parse_dnskey(lex, STR(token), &buf, &ttl);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
fatal("bad KSR file %s(%lu): bad DNSKEY (%s)",
|
||||||
|
ksr->file, isc_lex_getsourceline(lex),
|
||||||
|
isc_result_totext(ret));
|
||||||
|
}
|
||||||
|
isc_buffer_usedregion(&buf, &r);
|
||||||
|
isc_buffer_allocate(mctx, &newbuf, r.length);
|
||||||
|
isc_buffer_putmem(newbuf, r.base, r.length);
|
||||||
|
isc_buffer_usedregion(newbuf, &r);
|
||||||
|
dns_rdata_fromregion(rdata, dns_rdataclass_in,
|
||||||
|
dns_rdatatype_dnskey, &r);
|
||||||
|
if (rdatalist != NULL && ttl < rdatalist->ttl) {
|
||||||
|
rdatalist->ttl = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != ISC_R_EOF) {
|
||||||
|
fatal("bad KSR file %s(%lu): trailing garbage data", ksr->file,
|
||||||
|
isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final bundle */
|
||||||
|
if (have_bundle && rdatalist != NULL) {
|
||||||
|
sign_bundle(ksr, inception, ksr->end, rdatalist, &keys);
|
||||||
|
} else {
|
||||||
|
fatal("bad KSR file %s(%lu): no bundles", ksr->file,
|
||||||
|
isc_lex_getsourceline(lex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bundle footer */
|
||||||
|
isc_stdtime_tostring(ksr->now, timestr, sizeof(timestr));
|
||||||
|
fprintf(stdout, ";; SignedKeyResponse 1.0 generated at %s by %s\n",
|
||||||
|
timestr, PACKAGE_VERSION);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* Clean up */
|
||||||
|
isc_lex_destroy(&lex);
|
||||||
|
cleanup(&keys, kasp);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[]) {
|
main(int argc, char *argv[]) {
|
||||||
isc_result_t ret;
|
isc_result_t ret;
|
||||||
@@ -671,19 +1050,22 @@ main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
isc_commandline_errprint = false;
|
isc_commandline_errprint = false;
|
||||||
|
|
||||||
#define OPTIONS "E:e:Fhi:K:k:l:v:V"
|
#define OPTIONS "E:e:Ff:hi:K:k:l:v:V"
|
||||||
while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
|
while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 'E':
|
||||||
|
engine = isc_commandline_argument;
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
ksr.end = strtotime(isc_commandline_argument, ksr.now,
|
ksr.end = strtotime(isc_commandline_argument, ksr.now,
|
||||||
ksr.now, &ksr.setend);
|
ksr.now, &ksr.setend);
|
||||||
break;
|
break;
|
||||||
case 'E':
|
|
||||||
engine = isc_commandline_argument;
|
|
||||||
break;
|
|
||||||
case 'F':
|
case 'F':
|
||||||
set_fips_mode = true;
|
set_fips_mode = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
ksr.file = isc_commandline_argument;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(0);
|
usage(0);
|
||||||
break;
|
break;
|
||||||
@@ -776,6 +1158,8 @@ main(int argc, char *argv[]) {
|
|||||||
keygen(&ksr);
|
keygen(&ksr);
|
||||||
} else if (strcmp(argv[0], "request") == 0) {
|
} else if (strcmp(argv[0], "request") == 0) {
|
||||||
request(&ksr);
|
request(&ksr);
|
||||||
|
} else if (strcmp(argv[0], "sign") == 0) {
|
||||||
|
sign(&ksr);
|
||||||
} else {
|
} else {
|
||||||
fatal("unknown command '%s'", argv[0]);
|
fatal("unknown command '%s'", argv[0]);
|
||||||
}
|
}
|
||||||
|
@@ -114,6 +114,11 @@ Commands
|
|||||||
|
|
||||||
Create a Key Signing Request (KSR), given a DNSSEC policy and an interval.
|
Create a Key Signing Request (KSR), given a DNSSEC policy and an interval.
|
||||||
|
|
||||||
|
.. option:: sign
|
||||||
|
|
||||||
|
Sign a Key Signing Request (KSR), given a DNSSEC policy and an interval,
|
||||||
|
creating a Signed Key Response (SKR).
|
||||||
|
|
||||||
Exit Status
|
Exit Status
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -130,11 +135,21 @@ given a ``dnssec-policy`` named "mypolicy":
|
|||||||
|
|
||||||
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf keygen example.com
|
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf keygen example.com
|
||||||
|
|
||||||
Creating a Key Signing Request for the same zone and period can be done with:
|
Creating a KSR for the same zone and period can be done with:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf request example.com
|
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf request example.com > ksr.txt
|
||||||
|
|
||||||
|
Typically you would now transfer the KSR to the system that has access to the KSK.
|
||||||
|
|
||||||
|
Signing the KSR created above can be done with:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
dnssec-ksr -i now -e +1y -k kskpolicy -l named.conf -f ksr.txt sign example.com
|
||||||
|
|
||||||
|
Make sure that the DNSSEC parameters in ``kskpolicy`` match those in ``mypolicy``.
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
Reference in New Issue
Block a user