Skip to content
Snippets Groups Projects
Commit b11d8186 authored by Libor Peltan's avatar Libor Peltan
Browse files

introduced kkeymgr for manipulating KASP db

parent 98020d0b
Branches
Tags
1 merge request!672Kasp refactor
......@@ -75,6 +75,7 @@
/src/keymgr
/src/khost
/src/kjournalprint
/src/kkeymgr
/src/knot1to2
/src/knotc
/src/knotd
......
......@@ -503,6 +503,11 @@ src/utils/khost/khost_main.c
src/utils/khost/khost_params.c
src/utils/khost/khost_params.h
src/utils/kjournalprint/main.c
src/utils/kkeymgr/bind_privkey.c
src/utils/kkeymgr/bind_privkey.h
src/utils/kkeymgr/functions.c
src/utils/kkeymgr/functions.h
src/utils/kkeymgr/main.c
src/utils/knot1to2/cf-lex.c
src/utils/knot1to2/cf-lex.l
src/utils/knot1to2/cf-parse.tab.c
......
......@@ -3,6 +3,7 @@
# sphinx-build manpages
/man/kdig.1
/man/keymgr.8
/man/kkeymgr.8
/man/pykeymgr.8
/man/khost.1
/man/kjournalprint.1
......
MANPAGES_IN = man/knot.conf.5in man/knotc.8in man/knotd.8in man/kdig.1in man/khost.1in man/kjournalprint.1in man/knsupdate.1in man/knot1to2.1in man/knsec3hash.1in man/keymgr.8in man/pykeymgr.8in man/kzonecheck.1in
MANPAGES_RST = reference.rst man_knotc.rst man_knotd.rst man_kdig.rst man_khost.rst man_kjournalprint.rst man_knsupdate.rst man_knot1to2.rst man_knsec3hash.rst man_keymgr.rst man_pykeymgr.rst man_kzonecheck.rst
MANPAGES_IN = man/knot.conf.5in man/knotc.8in man/knotd.8in man/kdig.1in man/khost.1in man/kjournalprint.1in man/knsupdate.1in man/knot1to2.1in man/knsec3hash.1in man/keymgr.8in man/kkeymgr.8in man/pykeymgr.8in man/kzonecheck.1in
MANPAGES_RST = reference.rst man_knotc.rst man_knotd.rst man_kdig.rst man_khost.rst man_kjournalprint.rst man_knsupdate.rst man_knot1to2.rst man_knsec3hash.rst man_keymgr.rst man_kkeymgr.rst man_pykeymgr.rst man_kzonecheck.rst
EXTRA_DIST = \
conf.py \
......@@ -62,7 +62,7 @@ man_MANS += man/knot.conf.5 man/knotc.8 man/knotd.8
endif # HAVE_DAEMON
if HAVE_UTILS
man_MANS += man/kdig.1 man/khost.1 man/kjournalprint.1 man/knsupdate.1 man/knot1to2.1 man/knsec3hash.1 man/keymgr.8 man/pykeymgr.8 man/kzonecheck.1
man_MANS += man/kdig.1 man/khost.1 man/kjournalprint.1 man/knsupdate.1 man/knot1to2.1 man/knsec3hash.1 man/keymgr.8 man/kkeymgr.8 man/pykeymgr.8 man/kzonecheck.1
endif # HAVE_UTILS
man/knot.conf.5: man/knot.conf.5in
......@@ -75,6 +75,7 @@ man/knsupdate.1: man/knsupdate.1in
man/knot1to2.1: man/knot1to2.1in
man/knsec3hash.1: man/knsec3hash.1in
man/keymgr.8: man/keymgr.8in
man/kkeymgr.8: man/kkeymgr.8in
man/pykeymgr.8: man/pykeymgr.8in
man/kzonecheck.1: man/kzonecheck.1in
......
......@@ -221,6 +221,7 @@ man_pages = [
('reference', 'knot.conf', 'Knot DNS configuration file', author, 5),
('man_kdig', 'kdig', 'Advanced DNS lookup utility', author, 1),
('man_keymgr', 'keymgr', ' DNSSEC key management utility', author, 8),
('man_kkeymgr', 'kkeymgr', ' DNSSEC key management utility', author, 8),
('man_pykeymgr', 'pykeymgr', ' DNSSEC key management utility', author, 8),
('man_khost', 'khost', 'Simple DNS lookup utility', author, 1),
('man_kjournalprint', 'kjournalprint', 'Knot DNS journal print utility', author, 1),
......
......@@ -88,7 +88,7 @@ Access control list (ACL)
An ACL list specifies which remotes are allowed to send the server a specific
request. A remote can be a single IP address or a network subnet. Also a TSIG
key can be assigned (see :doc:`keymgr <man_keymgr>` how to generate a TSIG key).
key can be assigned (see :doc:`kkeymgr <man_kkeymgr>` how to generate a TSIG key).
With no ACL rule, all the actions are denied for the zone. Each ACL rule
can allow one or more actions for given address/subnet/TSIG, or deny them.
......@@ -361,7 +361,7 @@ with manual key management flag has to be set::
dnssec-signing: on
dnssec-policy: manual
To generate signing keys, use the :doc:`keymgr <man_keymgr>` utility.
To generate signing keys, use the :doc:`kkeymgr <man_kkeymgr>` utility.
Let's use the Single-Type Signing scheme with two algorithms. Run:
.. code-block:: console
......
.\" Man page generated from reStructuredText.
.
.TH "KKEYMGR" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS"
.SH NAME
kkeymgr \- DNSSEC key management utility
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
\fBkkeymgr\fP \fIbasic_option\fP [\fIparameters\fP\&...]
.sp
\fBkkeymgr\fP \fIconfig_option\fP \fIconfig_storage\fP \fIzone_name\fP \fIaction\fP \fIparameters\fP\&...
.SH DESCRIPTION
.sp
The \fBkkeymgr\fP utility serves for key management in Knot DNS server.
.sp
Functions for DNSSEC keys and KASP (Key And Signature Policy)
management are provided.
.sp
The DNSSEC and KASP configuration is stored in a so called KASP database.
The databse is backed by LMDB.
.SS Basic options
.INDENT 0.0
.TP
\fB\-h\fP
Print the program help.
.TP
\fB\-t\fP [\fItsig_algorithm\fP] [\fItsig_bits\fP]
Generates TSIG key. TSIG algorithm can be specified by string (default: hmac\-sha256),
bit length of the key by number (default: optimal length given by algorithm).
.UNINDENT
.SS Config options
.INDENT 0.0
.TP
\fB\-d\fP
Use KASP database directory specified by config_storage.
.TP
\fB\-c\fP
Determine KASP database location from Knot DNS configuration file, specified
by config_storage.
.TP
\fB\-C\fP
Determine KASP database location from Knot DNS configuration database,
specified by config_storage.
.UNINDENT
.SS Actions
.INDENT 0.0
.TP
\fBgenerate\fP [\fIarguments\fP\&...]
Generates new DNSSEC key and stores it in KASP database. Prints the key ID.
This action takes some number of arguments (see below). Values for unspecified arguments are taken
from corresponding policy (if \fI\-c\fP or \fI\-C\fP options used) or from Knot policy defaults.
.TP
\fBimport\-bind\fP \fIBIND_key_file\fP
Imports a BIND\-style key into KASP database (converting it to PEM format).
Takes one argument: path to BIND key file (private or public, but both MUST exist).
.UNINDENT
.SS Generate arguments
.sp
Arguments are separated by space, each of them is in format \(aqname=value\(aq.
.INDENT 0.0
.TP
\fBalgorithm\fP
Either an algorithm number (e.g. 14), or text name without dashes (e.g. ECDSAP384SHA384).
.TP
\fBsize\fP
Key length in bits.
.TP
\fBksk\fP
Either \(aqtrue\(aq (KSK will be generated) or \(aqfalse\(aq (ZSK wil be generated).
.TP
\fBcreated\fP
Timestamp of key creation.
.TP
\fBpublish\fP
Timestamp for key to be published.
.TP
\fBactive\fP
Timestamp for key to be activated.
.TP
\fBretire\fP
Timestamp for key to be de\-activated.
.TP
\fBremove\fP
Timestamp for key ot be deleted.
.UNINDENT
.SS Timestamps
.INDENT 0.0
.TP
\fIUNIX_time\fP
Positive number of seconds since 1970.
.TP
\fIYYYYMMDDHHMMSS\fP
Date and time in this format without any punctuation.
.TP
\fIrelative_timestamp\fP
The word "now" followed by sign (+, \-), a number and a shortcut for time unit
(y, mo, d, h, mi, (nothing = seconds)), e.g. now+1mi, now\-2mo, now+10,
now+0, now\-1y, ...
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.IP 1. 3
Generate TSIG key:
.INDENT 3.0
.INDENT 3.5
.sp
.nf
.ft C
$ kkeymgr \-t my_name hmac\-sha384
.ft P
.fi
.UNINDENT
.UNINDENT
.IP 2. 3
Import a key from BIND:
.INDENT 3.0
.INDENT 3.5
.sp
.nf
.ft C
$ kkeymgr \-d ${knot_data_dir}/keys example.com. import\-bind ~/bind/Kharbinge4d5.+007+63089.key
.ft P
.fi
.UNINDENT
.UNINDENT
.IP 3. 3
Generate new key:
.INDENT 3.0
.INDENT 3.5
.sp
.nf
.ft C
$ kkeymgr \-c ${knot_data_dir}/knot.conf example.com. generate algorithm=ECDSAP256SHA256 size=256 \e
ksk=true created=1488034625 publish=20170223205611 retire=now+10mo remove=now+1y
.ft P
.fi
.UNINDENT
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fI\%RFC 6781\fP \- DNSSEC Operational Practices.
.sp
\fBknot.conf(5)\fP,
\fBknotc(8)\fP,
\fBknotd(8)\fP\&.
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
Copyright 2010–2017, CZ.NIC, z.s.p.o.
.\" Generated by docutils manpage writer.
.
.. highlight:: console
kkeymgr – Key management utility
=================================
Synopsis
--------
:program:`kkeymgr` *basic_option* [*parameters*...]
:program:`kkeymgr` *config_option* *config_storage* *zone_name* *action* *parameters*...
Description
-----------
The :program:`kkeymgr` utility serves for key management in Knot DNS server.
Functions for DNSSEC keys and KASP (Key And Signature Policy)
management are provided.
The DNSSEC and KASP configuration is stored in a so called KASP database.
The databse is backed by LMDB.
Basic options
..............
**-h**
Print the program help.
**-t** [*tsig_algorithm*] [*tsig_bits*]
Generates TSIG key. TSIG algorithm can be specified by string (default: hmac-sha256),
bit length of the key by number (default: optimal length given by algorithm).
Config options
..............
**-d**
Use KASP database directory specified by config_storage.
**-c**
Determine KASP database location from Knot DNS configuration file, specified
by config_storage.
**-C**
Determine KASP database location from Knot DNS configuration database,
specified by config_storage.
Actions
.......
**generate** [*arguments*...]
Generates new DNSSEC key and stores it in KASP database. Prints the key ID.
This action takes some number of arguments (see below). Values for unspecified arguments are taken
from corresponding policy (if *-c* or *-C* options used) or from Knot policy defaults.
**import-bind** *BIND_key_file*
Imports a BIND-style key into KASP database (converting it to PEM format).
Takes one argument: path to BIND key file (private or public, but both MUST exist).
Generate arguments
..................
Arguments are separated by space, each of them is in format 'name=value'.
**algorithm**
Either an algorithm number (e.g. 14), or text name without dashes (e.g. ECDSAP384SHA384).
**size**
Key length in bits.
**ksk**
Either 'true' (KSK will be generated) or 'false' (ZSK wil be generated).
**created**
Timestamp of key creation.
**publish**
Timestamp for key to be published.
**active**
Timestamp for key to be activated.
**retire**
Timestamp for key to be de-activated.
**remove**
Timestamp for key ot be deleted.
Timestamps
..........
*UNIX_time*
Positive number of seconds since 1970.
*YYYYMMDDHHMMSS*
Date and time in this format without any punctuation.
*relative_timestamp*
The word "now" followed by sign (+, -), a number and a shortcut for time unit
(y, mo, d, h, mi, (nothing = seconds)), e.g. now+1mi, now-2mo, now+10,
now+0, now-1y, ...
Examples
--------
1. Generate TSIG key::
$ kkeymgr -t my_name hmac-sha384
2. Import a key from BIND::
$ kkeymgr -d ${knot_data_dir}/keys example.com. import-bind ~/bind/Kharbinge4d5.+007+63089.key
3. Generate new key::
$ kkeymgr -c ${knot_data_dir}/knot.conf example.com. generate algorithm=ECDSAP256SHA256 size=256 \
ksk=true created=1488034625 publish=20170223205611 retire=now+10mo remove=now+1y
See Also
--------
:rfc:`6781` - DNSSEC Operational Practices.
:manpage:`knot.conf(5)`,
:manpage:`knotc(8)`,
:manpage:`knotd(8)`.
......@@ -12,6 +12,7 @@ the server. This section collects manual pages for all provided binaries:
man_kdig
man_keymgr
man_kkeymgr
man_pykeymgr
man_khost
man_kjournalprint
......
......@@ -512,7 +512,7 @@ if HAVE_UTILS
bin_PROGRAMS = kdig khost knsec3hash knsupdate
if HAVE_DAEMON
bin_PROGRAMS += kzonecheck kjournalprint
bin_PROGRAMS += kzonecheck kjournalprint kkeymgr
endif # HAVE_DAEMON
kdig_SOURCES = \
......@@ -550,6 +550,13 @@ kzonecheck_SOURCES = \
kjournalprint_SOURCES = \
utils/kjournalprint/main.c
kkeymgr_SOURCES = \
utils/kkeymgr/bind_privkey.c \
utils/kkeymgr/bind_privkey.h \
utils/kkeymgr/functions.c \
utils/kkeymgr/functions.h \
utils/kkeymgr/main.c
# bin programs
kdig_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
kdig_LDADD = $(libidn_LIBS) libknotus.la
......@@ -562,6 +569,9 @@ knsec3hash_LDADD = dnssec/libdnssec.la dnssec/libshared.la
kzonecheck_LDADD = libknotd.la libcontrib.la
kjournalprint_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS) $(liburcu_CFLAGS)
kjournalprint_LDADD = $(libidn_LIBS) $(liburcu_LIBS) libknotd.la libcontrib.la
kkeymgr_CPPFLAGS = $(AM_CPPFLAGS) $(liburcu_CFLAGS) -I$(srcdir)/dnssec/lib/dnssec -I$(srcdir)/dnssec $(gnutls_CFLAGS)
kkeymgr_LDADD = $(libidn_LIBS) $(liburcu_LIBS) libknotd.la libcontrib.la libknotd.la libknotus.la dnssec/libdnssec.la dnssec/libshared.la zscanner/libzscanner.la $(gnutls_LIBS)
# TODO wrap
#######################################
# Optional Knot DNS Utilities modules #
......
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <string.h>
#include "contrib/strtonum.h"
#include "dnssec/binary.h"
#include "dnssec/error.h"
#include "shared/pem.h"
#include "shared/shared.h"
#include "utils/kkeymgr/bind_privkey.h"
/* -- private key params conversion ---------------------------------------- */
/*!
* Private key attribute conversion.
*/
typedef struct param_t {
char *name;
size_t offset;
int (*parse_cb)(char *string, void *data);
void (*free_cb)(void *data);
} param_t;
static int parse_algorithm(char *string, void *_algorithm);
static int parse_binary(char *string, void *_binary);
static int parse_time(char *string, void *_time);
static void binary_free(void *_binary)
{
dnssec_binary_t *binary = _binary;
dnssec_binary_free(binary);
}
/*!
* Know attributes in private key file.
*/
const param_t PRIVKEY_CONVERSION_TABLE[] = {
#define o(field) offsetof(bind_privkey_t, field)
{ "Algorithm", o(algorithm), parse_algorithm, NULL },
{ "Modulus", o(modulus), parse_binary, binary_free },
{ "PublicExponent", o(public_exponent), parse_binary, binary_free },
{ "PrivateExponent", o(private_exponent), parse_binary, binary_free },
{ "Prime1", o(prime_one), parse_binary, binary_free },
{ "Prime2", o(prime_two), parse_binary, binary_free },
{ "Exponent1", o(exponent_one), parse_binary, binary_free },
{ "Exponent2", o(exponent_two), parse_binary, binary_free },
{ "Coefficient", o(coefficient), parse_binary, binary_free },
{ "Prime(p)", o(prime), parse_binary, binary_free },
{ "Subprime(q)", o(subprime), parse_binary, binary_free },
{ "Base(g)", o(base), parse_binary, binary_free },
{ "Private_value(x)",o(private_value), parse_binary, binary_free },
{ "Public_value(y)", o(public_value), parse_binary, binary_free },
{ "PrivateKey", o(private_key), parse_binary, binary_free },
{ "Created", o(time_created), parse_time, NULL },
{ "Publish", o(time_publish), parse_time, NULL },
{ "Activate", o(time_activate), parse_time, NULL },
{ "Revoke", o(time_revoke), parse_time, NULL },
{ "Inactive", o(time_inactive), parse_time, NULL },
{ "Delete", o(time_delete), parse_time, NULL },
{ NULL }
#undef o
};
/* -- attribute parsing ---------------------------------------------------- */
/*!
* Parse key algorithm field.
*
* Example: 7 (NSEC3RSASHA1)
*
* Only the numeric value is decoded, the rest of the value is ignored.
*/
static int parse_algorithm(char *string, void *_algorithm)
{
char *end = string;
while (*end != '\0' && !isspace((int)*end)) {
end += 1;
}
*end = '\0';
uint8_t *algorithm = _algorithm;
int r = str_to_u8(string, algorithm);
return (r == KNOT_EOK ? DNSSEC_EOK : DNSSEC_INVALID_KEY_ALGORITHM);
}
/*!
* Parse binary data encoded in Base64.
*
* Example: AQAB
*/
static int parse_binary(char *string, void *_binary)
{
dnssec_binary_t base64 = {
.data = (uint8_t *)string,
.size = strlen(string)
};
dnssec_binary_t *binary = _binary;
return dnssec_binary_from_base64(&base64, binary);
}
#define LEGACY_DATE_FORMAT "%Y%m%d%H%M%S"
/*!
* Parse timestamp in a format in \ref LEGACY_DATE_FORMAT.
*
* Example: 20140415151855
*/
static int parse_time(char *string, void *_time)
{
struct tm tm = { 0 };
char *end = strptime(string, LEGACY_DATE_FORMAT, &tm);
if (end == NULL || *end != '\0') {
return DNSSEC_MALFORMED_DATA;
}
time_t *time = _time;
*time = timegm(&tm);
return DNSSEC_EOK;
}
/* -- key parsing ---------------------------------------------------------- */
/*!
* Strip string value of left and right whitespaces.
*
* \param[in,out] value Start of the string.
* \param[in,out] length Length of the string.
*
*/
static void strip(char **value, size_t *length)
{
// strip from left
while (*length > 0 && isspace((int)**value)) {
*value += 1;
*length -= 1;
}
// strip from right
while (*length > 0 && isspace((int)(*value)[*length - 1])) {
*length -= 1;
}
}
/*!
* Parse one line of the private key file.
*/
static int parse_line(bind_privkey_t *params, char *line, size_t length)
{
assert(params);
assert(line);
char *separator = memchr(line, ':', length);
if (!separator) {
return DNSSEC_MALFORMED_DATA;
}
char *key = line;
size_t key_length = separator - key;
strip(&key, &key_length);
char *value = separator + 1;
size_t value_length = (line + length) - value;
strip(&value, &value_length);
if (key_length == 0 || value_length == 0) {
return DNSSEC_MALFORMED_DATA;
}
key[key_length] = '\0';
value[value_length] = '\0';
for (const param_t *p = PRIVKEY_CONVERSION_TABLE; p->name != NULL; p++) {
size_t name_length = strlen(p->name);
if (name_length != key_length) {
continue;
}
if (strcasecmp(p->name, key) != 0) {
continue;
}
return p->parse_cb(value, (void *)params + p->offset);
}
// ignore unknown attributes
return DNSSEC_EOK;
}
int bind_privkey_parse(const char *filename, bind_privkey_t *params_ptr)
{
_cleanup_fclose_ FILE *file = fopen(filename, "r");
if (!file) {
return DNSSEC_NOT_FOUND;
}
bind_privkey_t params = { 0 };
_cleanup_free_ char *line = NULL;
size_t size = 0;
ssize_t read = 0;
while ((read = getline(&line, &size, file)) != -1) {
int r = parse_line(&params, line, read);
if (r != DNSSEC_EOK) {
bind_privkey_free(&params);
return r;
}
}
*params_ptr = params;
return DNSSEC_EOK;
}
/* -- freeing -------------------------------------------------------------- */
/*!
* Free private key parameters.
*/
void bind_privkey_free(bind_privkey_t *params)
{
if (!params) {
return;
}
for (const param_t *p = PRIVKEY_CONVERSION_TABLE; p->name != NULL; p++) {
if (p->free_cb) {
p->free_cb((void *)params + p->offset);
}
}
clear_struct(params);
}
/* -- export to PEM -------------------------------------------------------- */
static int rsa_params_to_pem(const bind_privkey_t *params, dnssec_binary_t *pem)
{
_cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
int result = gnutls_x509_privkey_init(&key);
if (result != GNUTLS_E_SUCCESS) {
return DNSSEC_ENOMEM;
}
gnutls_datum_t m = binary_to_datum(&params->modulus);
gnutls_datum_t e = binary_to_datum(&params->public_exponent);
gnutls_datum_t d = binary_to_datum(&params->private_exponent);
gnutls_datum_t p = binary_to_datum(&params->prime_one);
gnutls_datum_t q = binary_to_datum(&params->prime_two);
gnutls_datum_t u = binary_to_datum(&params->coefficient);
result = gnutls_x509_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u);
if (result != GNUTLS_E_SUCCESS) {
return DNSSEC_KEY_IMPORT_ERROR;
}
return pem_from_x509(key, pem);
}
static int dsa_params_to_pem(const bind_privkey_t *params, dnssec_binary_t *pem)
{
_cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
int result = gnutls_x509_privkey_init(&key);
if (result != GNUTLS_E_SUCCESS) {
return DNSSEC_ENOMEM;
}
gnutls_datum_t p = binary_to_datum(&params->prime);
gnutls_datum_t q = binary_to_datum(&params->subprime);
gnutls_datum_t g = binary_to_datum(&params->base);
gnutls_datum_t x = binary_to_datum(&params->private_value);
gnutls_datum_t y = binary_to_datum(&params->public_value);
result = gnutls_x509_privkey_import_dsa_raw(key, &p, &q, &g, &y, &x);
if (result != DNSSEC_EOK) {
return DNSSEC_KEY_IMPORT_ERROR;
}
return pem_from_x509(key, pem);
}
/*!
* \see lib/key/convert.h
*/
static gnutls_ecc_curve_t choose_ecdsa_curve(size_t pubkey_size)
{
switch (pubkey_size) {
case 64: return GNUTLS_ECC_CURVE_SECP256R1;
case 96: return GNUTLS_ECC_CURVE_SECP384R1;
default: return GNUTLS_ECC_CURVE_INVALID;
}
}
static void ecdsa_extract_public_params(dnssec_key_t *key, gnutls_ecc_curve_t *curve,
gnutls_datum_t *x, gnutls_datum_t *y)
{
dnssec_binary_t pubkey = { 0 };
dnssec_key_get_pubkey(key, &pubkey);
*curve = choose_ecdsa_curve(pubkey.size);
size_t param_size = pubkey.size / 2;
x->data = pubkey.data;
x->size = param_size;
y->data = pubkey.data + param_size;
y->size = param_size;
}
static int ecdsa_params_to_pem(dnssec_key_t *dnskey, const bind_privkey_t *params,
dnssec_binary_t *pem)
{
_cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
int result = gnutls_x509_privkey_init(&key);
if (result != GNUTLS_E_SUCCESS) {
return DNSSEC_ENOMEM;
}
gnutls_ecc_curve_t curve = 0;
gnutls_datum_t x = { 0 };
gnutls_datum_t y = { 0 };
ecdsa_extract_public_params(dnskey, &curve, &x, &y);
gnutls_datum_t k = binary_to_datum(&params->private_key);
result = gnutls_x509_privkey_import_ecc_raw(key, curve, &x, &y, &k);
if (result != DNSSEC_EOK) {
return DNSSEC_KEY_IMPORT_ERROR;
}
gnutls_x509_privkey_fix(key);
return pem_from_x509(key, pem);
}
int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary_t *pem)
{
dnssec_key_algorithm_t algorithm = dnssec_key_get_algorithm(key);
switch (algorithm) {
case DNSSEC_KEY_ALGORITHM_DSA_SHA1:
case DNSSEC_KEY_ALGORITHM_DSA_SHA1_NSEC3:
return dsa_params_to_pem(params, pem);
case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
return rsa_params_to_pem(params, pem);
case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
return ecdsa_params_to_pem(key, params, pem);
default:
return DNSSEC_INVALID_KEY_ALGORITHM;
}
}
void bind_privkey_to_timing(bind_privkey_t *params, dnssec_kasp_key_timing_t *timing)
{
// unsupported: time_created, time_revoke
timing->publish = params->time_publish;
timing->active = params->time_activate;
timing->retire = params->time_inactive;
timing->remove = params->time_delete;
}
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <time.h>
#include "dnssec/binary.h"
#include "dnssec/kasp.h"
/*!
* Legacy private key parameters.
*/
typedef struct {
// key information
uint8_t algorithm;
// RSA
dnssec_binary_t modulus;
dnssec_binary_t public_exponent;
dnssec_binary_t private_exponent;
dnssec_binary_t prime_one;
dnssec_binary_t prime_two;
dnssec_binary_t exponent_one;
dnssec_binary_t exponent_two;
dnssec_binary_t coefficient;
// DSA
dnssec_binary_t prime;
dnssec_binary_t subprime;
dnssec_binary_t base;
dnssec_binary_t private_value;
dnssec_binary_t public_value;
// ECDSA
dnssec_binary_t private_key;
// key lifetime
time_t time_created;
time_t time_publish;
time_t time_activate;
time_t time_revoke;
time_t time_inactive;
time_t time_delete;
} bind_privkey_t;
/*!
* Extract parameters from legacy private key file.
*/
int bind_privkey_parse(const char *filename, bind_privkey_t *params);
/*!
* Free private key parameters.
*/
void bind_privkey_free(bind_privkey_t *params);
/*!
* Generate PEM from pub&priv key.
*/
int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary_t *pem);
/*!
* Extract timing info.
*/
void bind_privkey_to_timing(bind_privkey_t *params, dnssec_kasp_key_timing_t *timing);
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils/kkeymgr/functions.h"
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "dnssec/lib/dnssec/dnssec.h"
#include "dnssec/shared/shared.h"
#include "knot/dnssec/zone-keys.h"
#include "utils/kkeymgr/bind_privkey.h"
#include "zscanner/scanner.h"
static time_t arg_timestamp(const char *arg)
{
if (isdigit(arg[0]) && strlen(arg) < 12) {
return atol(arg); // unixtime
}
if (isdigit(arg[0]) && strlen(arg) == 14) {
struct tm tm = { 0 };
char *end = strptime(arg, "%Y%m%d%H%M%S", &tm);
if (end == NULL || *end != '\0') {
return -1;
}
return mktime(&tm); // time format
}
long amount;
if (strncasecmp(arg, "now+", 4) == 0) {
amount = atol(arg + 4);
} else if (strncasecmp(arg, "now-", 4) == 0) {
amount = 0 - atol(arg + 4);
} else if (strncasecmp(arg, "t+", 2) == 0) {
amount = atol(arg + 2);
} else if (strncasecmp(arg, "t-", 2) == 0) {
amount = 0 - atol(arg + 2);
} else if (arg[0] == '+' || arg[0] == '-') {
amount = atol(arg);
} else {
return -1;
}
char *unit = strrchr(arg, '0' + (labs(amount) % 10));
if (unit++ == NULL) {
return -1;
}
time_t now = time(NULL);
switch ((*unit == 'm') ? *(unit + 1) : *unit) {
case 'i':
return now + amount * 60;
case 'h':
return now + amount * 3600;
case 'd':
return now + amount * 3600 * 24;
case 'w':
return now + amount * 3600 * 24 * 7;
case 'o':
return now + amount * 3600 * 24 * 30; // this is lame but same as keymgr
case 'y':
return now + amount * 3600 * 24 * 365;
case '\0':
return now + amount;
}
return -1;
}
static bool genkeyargs(int argc, char *argv[], bool *isksk, dnssec_key_algorithm_t *algorithm,
uint16_t *keysize, dnssec_kasp_key_timing_t *timing)
{
// generate algorithms field
char *algnames[256] = { 0 };
algnames[DNSSEC_KEY_ALGORITHM_DSA_SHA1] = "dsa";
algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1] = "rsasha1";
algnames[DNSSEC_KEY_ALGORITHM_DSA_SHA1_NSEC3] = "dsansec3sha1";
algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3] = "rsasha1nsec3sha1";
algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA256] = "rsasha256";
algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA512] = "rsasha512";
algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256] = "ecdsap256sha256";
algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384] = "ecdsap384sha384";
// parse args
for (int i = 0; i < argc; i++) {
if (strncasecmp(argv[i], "algorithm=", 10) == 0) {
if (isdigit(argv[i][10]) && atol(argv[i] + 10) < 256) {
*algorithm = atol(argv[i] + 10);
continue;
}
int al;
for (al = 0; al < 256; al++) {
if (algnames[al] != NULL &&
strcasecmp(argv[i] + 10, algnames[al]) == 0) {
*algorithm = al;
break;
}
}
if (al == 256) {
printf("Unknown algorithm: %s\n", argv[i] + 10);
return false;
}
} else if (strncasecmp(argv[i], "ksk=", 4) == 0) {
switch (tolower(argv[i][4])) {
case '1':
case 'y':
case 't':
*isksk = true;
break;
default:
*isksk = false;
}
} else if (strncasecmp(argv[i], "size=", 5) == 0) {
*keysize = atol(argv[i] + 5);
} else if (strncasecmp(argv[i], "created=", 8) == 0 ||
strncasecmp(argv[i], "publish=", 8) == 0 ||
strncasecmp(argv[i], "active=", 7) == 0 ||
strncasecmp(argv[i], "retire=", 7) == 0 ||
strncasecmp(argv[i], "remove=", 7) == 0) {
time_t stamp = arg_timestamp(strchr(argv[i], '=') + 1);
if (stamp < 0) {
printf("Invalid timestamp: %s\n", argv[i]);
return false;
}
switch ((argv[i][0] == 'r') ? argv[i][2] : argv[i][0]) {
case 'c':
timing->created = stamp;
break;
case 'a':
timing->active = stamp;
break;
case 'p':
timing->publish = stamp;
break;
case 't':
timing->retire = stamp;
break;
case 'm':
timing->remove = stamp;
break;
}
} else {
printf("Invalid parameter: %s\n", argv[i]);
return false;
}
}
return true;
}
// modifies ctx->policy options, so don't do anything afterwards !
int kkeymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[]) {
time_t now = time(NULL), infty = 0x0fffffffffffff00LLU;
dnssec_kasp_key_timing_t gen_timing = { now, now, now, infty, infty };
bool isksk = false;
uint16_t keysize = 0;
if (!genkeyargs(argc, argv, &isksk, &ctx->policy->algorithm,
&keysize, &gen_timing)) {
return KNOT_EINVAL;
}
if (keysize > 0) {
if (isksk) {
ctx->policy->ksk_size = keysize;
} else {
ctx->policy->zsk_size = keysize;
}
}
printf("alg %d\n", (int)ctx->policy->algorithm);
dnssec_kasp_key_t *key = NULL;
int ret = kdnssec_generate_key(ctx, isksk, &key);
if (ret != KNOT_EOK) {
return ret;
}
key->timing = gen_timing;
ret = kdnssec_ctx_commit(ctx);
if (ret == KNOT_EOK) {
printf("%s\n", key->id);
}
return ret;
}
static void parse_record(zs_scanner_t *scanner)
{
dnssec_key_t *key = scanner->process.data;
if (dnssec_key_get_dname(key) != NULL ||
scanner->r_type != KNOT_RRTYPE_DNSKEY) {
scanner->state = ZS_STATE_STOP;
return;
}
dnssec_binary_t rdata = {
.data = scanner->r_data,
.size = scanner->r_data_length
};
dnssec_key_set_dname(key, scanner->dname);
dnssec_key_set_rdata(key, &rdata);
}
int bind_pubkey_parse(const char *filename, dnssec_key_t **key_ptr)
{
dnssec_key_t *key = NULL;
int result = dnssec_key_new(&key);
if (result != DNSSEC_EOK) {
return KNOT_ENOMEM;
}
uint16_t cls = KNOT_CLASS_IN;
uint32_t ttl = 0;
zs_scanner_t *scanner = malloc(sizeof(zs_scanner_t));
if (scanner == NULL) {
dnssec_key_free(key);
return KNOT_ENOMEM;
}
if (zs_init(scanner, ".", cls, ttl) != 0 ||
zs_set_input_file(scanner, filename) != 0 ||
zs_set_processing(scanner, parse_record, NULL, key) != 0 ||
zs_parse_all(scanner) != 0) {
zs_deinit(scanner);
free(scanner);
dnssec_key_free(key);
return KNOT_ENOENT;
}
zs_deinit(scanner);
free(scanner);
if (dnssec_key_get_dname(key) == NULL) {
dnssec_key_free(key);
return KNOT_INVALID_PUBLIC_KEY;
}
*key_ptr = key;
return KNOT_EOK;
}
static char *genname(const char *orig, const char *wantsuff, const char *altsuff)
{
char *res;
if (orig == NULL || wantsuff == NULL || altsuff == NULL ||
(res = malloc(strlen(orig) + strlen(wantsuff) + 1)) == NULL) {
return NULL;
}
strcpy(res, orig);
char *dot = strrchr(res, '.');
if (dot != NULL && strcmp(dot, wantsuff) == 0) {
;
} else if (dot != NULL && strcmp(dot, altsuff) == 0) {
strcpy(dot, wantsuff);
} else {
strcat(res, wantsuff);
}
return res;
}
int kkeymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file)
{
char *pubname = genname(import_file, ".key", ".private");
char *privname = genname(import_file, ".private", ".key");
if (ctx == NULL || import_file == NULL || pubname == NULL || privname == NULL) {
free(pubname);
free(privname);
return KNOT_EINVAL;
}
char *keyid = NULL;
dnssec_key_t *key = NULL;
int ret = KNOT_EOK;
printf("kkib %s %s\n", pubname, privname);
ret = bind_pubkey_parse(pubname, &key);
if (ret != KNOT_EOK) {
goto fail;
}
bind_privkey_t bpriv = { 0 };
ret = bind_privkey_parse(privname, &bpriv);
if (ret != DNSSEC_EOK) {
goto fail;
}
dnssec_binary_t pem = { 0 };
ret = bind_privkey_to_pem(key, &bpriv, &pem);
if (ret != DNSSEC_EOK) {
bind_privkey_free(&bpriv);
goto fail;
}
dnssec_kasp_key_timing_t timing = { 0 };
bind_privkey_to_timing(&bpriv, &timing); // time created remains always zero
bind_privkey_free(&bpriv);
ret = dnssec_keystore_import(ctx->keystore, &pem, &keyid);
if (ret != DNSSEC_EOK) {
goto fail;
}
dnssec_kasp_key_t *kkey = calloc(1, sizeof(*kkey));
if (!kkey) {
ret = KNOT_ENOMEM;
goto fail;
}
kkey->id = keyid;
kkey->key = key;
kkey->timing = timing;
ret = kasp_zone_append(ctx->zone, kkey);
free(kkey);
if (ret != KNOT_EOK) {
goto fail;
}
ret = kdnssec_ctx_commit(ctx);
// ret fallthrough
if (ret == KNOT_EOK) {
printf("%s\n", keyid);
}
goto cleanup;
fail:
dnssec_key_free(key);
free(keyid);
cleanup:
free(pubname);
free(privname);
return knot_error_from_libdnssec(ret);
}
static void print_tsig(dnssec_tsig_algorithm_t mac, const char *name,
const dnssec_binary_t *secret)
{
assert(name);
assert(secret);
const char *mac_name = dnssec_tsig_algorithm_to_name(mac);
assert(mac_name);
// client format (as a comment)
printf("# %s:%s:%.*s\n", mac_name, name, (int)secret->size, secret->data);
// server format
printf("key:\n");
printf(" - id: %s\n", name);
printf(" algorithm: %s\n", mac_name);
printf(" secret: %.*s\n", (int)secret->size, secret->data);
}
int kkeymgr_generate_tsig(const char *tsig_name, const char *alg_name, int bits)
{
dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_name(alg_name);
if (alg == DNSSEC_TSIG_UNKNOWN) {
return KNOT_INVALID_KEY_ALGORITHM;
}
int optimal_bits = dnssec_tsig_optimal_key_size(alg);
if (bits == 0) {
bits = optimal_bits; // TODO review
}
// round up bits to bytes
bits = (bits + CHAR_BIT - 1) / CHAR_BIT * CHAR_BIT;
if (bits != optimal_bits) {
printf("Notice: Optimal key size for %s is %d bits.",
dnssec_tsig_algorithm_to_name(alg), optimal_bits);
}
assert(bits % CHAR_BIT == 0);
_cleanup_binary_ dnssec_binary_t key = { 0 };
int r = dnssec_binary_alloc(&key, bits / CHAR_BIT);
if (r != DNSSEC_EOK) {
printf("Failed to allocate memory.");
return knot_error_from_libdnssec(r);
}
r = gnutls_rnd(GNUTLS_RND_KEY, key.data, key.size);
if (r != 0) {
printf("Failed to generate secret the key.");
return knot_error_from_libdnssec(r);
}
_cleanup_binary_ dnssec_binary_t key_b64 = { 0 };
r = dnssec_binary_to_base64(&key, &key_b64);
if (r != DNSSEC_EOK) {
printf("Failed to convert the key to Base64.");
return knot_error_from_libdnssec(r);
}
print_tsig(alg, tsig_name, &key_b64);
return KNOT_EOK;
}
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "knot/dnssec/context.h"
int kkeymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[]);
int kkeymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file);
int kkeymgr_generate_tsig(const char *tsig_name, const char *alg_name, int bits);
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "knot/conf/conf.h"
#include "utils/kkeymgr/functions.h"
#include "libknot/libknot.h"
#define PROGRAM_NAME "kkeymgr"
static void print_help(void)
{
printf("Usage: %s [parameter] options/commands...\n"
"\n"
"Parameters:\n"
" -h Display this help.\n"
" -t Generate TSIG key.\n"
" (syntax: -t <tsig_name> [<algorithm>] [<bits>]\n"
" -d Use specified KASP db path.\n"
" (syntax: -d <KASP_dir> <zone> <command> options...)\n"
" -c Use specified Knot config file.\n"
" (syntax: -c <config_file> <zone> <command> options...)\n"
" -C Use specified Knot configuration database.\n"
" (syntax: -C <confdb_dir> <zone> <command> options...)\n"
"\n"
"Commands:\n"
" generate Generate new KASP key.\n"
" (syntax: generate <attribute_name>=<value>...)\n"
" import-bind Import BIND-style key file pair (.key + .private).\n"
" (syntax: import_bind <key_file_name>)\n",
PROGRAM_NAME);
}
static bool init_conf(const char *confdb)
{
conf_flag_t flags = CONF_FNOHOSTNAME;
if (confdb != NULL) {
flags |= CONF_FREADONLY;
}
conf_t *new_conf = NULL;
int ret = conf_new(&new_conf, conf_scheme, confdb, flags);
if (ret != KNOT_EOK) {
printf("Failed opening configuration database %s (%s)\n",
(confdb == NULL ? "" : confdb), knot_strerror(ret));
return false;
}
conf_update(new_conf, CONF_UPD_FNONE);
return true;
}
static bool init_confile(const char *confile)
{
int ret = conf_import(conf(), confile, true);
if (ret != KNOT_EOK) {
printf("Failed opening configuration file %s (%s)\n",
confile, knot_strerror(ret));
return false;
}
return true;
}
int main(int argc, char *argv[])
{
char *kasp_path = NULL;
for (int i = 0; i < argc; i++) {
printf("%s\"%s\"%s", (i == 0 ? "[ " : ""), argv[i], (i == argc - 1 ? " ]\n" : ", "));
}
if (argc <= 1) {
print_help();
return EXIT_SUCCESS;
}
if (strlen(argv[1]) != 2 || argv[1][0] != '-') {
printf("Bad argument: %s\n", argv[1]);
print_help();
return EXIT_FAILURE;
}
#define check_argc_three if (argc < 3) { printf("Option %s requires an argument.\n", argv[1]); print_help(); return EXIT_FAILURE; }
switch (argv[1][1]) {
case 'h':
print_help();
return EXIT_SUCCESS;
case 'd':
check_argc_three
if (!init_conf(NULL)) {
return EXIT_FAILURE;
}
kasp_path = strdup(argv[2]);
break;
case 'c':
check_argc_three
if (!init_conf(NULL) || !init_confile(argv[2])) {
return EXIT_FAILURE;
}
kasp_path = conf_kaspdir(conf());
break;
case 'C':
check_argc_three
if (!init_conf(argv[2])) {
return EXIT_FAILURE;
}
kasp_path = conf_kaspdir(conf());
break;
case 't':
check_argc_three
int tret = kkeymgr_generate_tsig(argv[2], (argc >= 4 ? argv[3] : "hmac-sha256"),
(argc >= 5 ? atol(argv[4]) : 0));
if (tret != KNOT_EOK) {
printf("Failed to generate TSIG (%s)\n", knot_strerror(tret));
}
return (tret == KNOT_EOK ? EXIT_SUCCESS : EXIT_FAILURE);
default:
printf("Wrong option: %s\n", argv[1]);
print_help();
return EXIT_FAILURE;
}
#undef check_argc_three
if (kasp_path == NULL) {
printf("Unable to gather KASP db path from %s\n", argv[2]);
print_help();
return EXIT_FAILURE;
}
if (argc < 5) {
printf("Zone name and/or command not specified.\n");
print_help();
free(kasp_path);
return EXIT_FAILURE;
}
knot_dname_t *zone_name = knot_dname_from_str_alloc(argv[3]);
if (zone_name == NULL) {
free(kasp_path);
return EXIT_FAILURE;
}
(void)knot_dname_to_lower(zone_name);
kdnssec_ctx_t kctx = { 0 };
int ret = kasp_db_init(kaspdb(), kasp_path, 500*1024*1024 /* TODO */);
if (ret != KNOT_EOK) {
printf("Failed to initialize KASP db (%s)\n", knot_strerror(ret));
goto main_end;
}
ret = kdnssec_kasp_init(&kctx, kasp_path, 500*1024*1024 /* TODO */, zone_name, "default");
if (ret != KNOT_EOK) {
printf("Failed to initializize KASP (%s)\n", knot_strerror(ret));
goto main_end;
}
if (strcmp(argv[4], "generate") == 0) {
ret = kkeymgr_generate_key(&kctx, argc - 5, argv + 5);
} else if (strcmp(argv[4], "import-bind") == 0) {
if (argc < 6) {
printf("BIND-style key to import not specified.\n");
ret = KNOT_EINVAL;
goto main_end;
}
ret = kkeymgr_import_bind(&kctx, argv[5]);
} else {
printf("Wrong zone-key command: %s\n", argv[4]);
goto main_end;
}
if (ret == KNOT_EOK) {
printf("OK\n");
} else {
printf("Error (%s)\n", knot_strerror(ret));
}
main_end:
kdnssec_ctx_deinit(&kctx);
kasp_db_close(kaspdb());
free(kasp_path);
free(zone_name);
return (ret == KNOT_EOK ? EXIT_SUCCESS : EXIT_FAILURE);
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment