Commit 44b106e0 authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'tsig-keyfile' into 'master'

utilities: support for TSIG key in file

See merge request !382
parents 3c12f7e1 285e7564
......@@ -322,8 +322,6 @@ src/libknot/descriptor.c
src/libknot/descriptor.h
src/libknot/dname.c
src/libknot/dname.h
src/libknot/dnssec/key.c
src/libknot/dnssec/key.h
src/libknot/errcode.c
src/libknot/errcode.h
src/libknot/internal/array-sort.h
......@@ -417,6 +415,8 @@ src/libknot/rrtype/tsig.c
src/libknot/rrtype/tsig.h
src/libknot/tsig-op.c
src/libknot/tsig-op.h
src/libknot/tsig.c
src/libknot/tsig.h
src/libknot/yparser/yparser.c
src/libknot/yparser/yparser.h
src/libknot/yparser/ypbody.c
......@@ -439,6 +439,8 @@ src/utils/common/params.c
src/utils/common/params.h
src/utils/common/resolv.c
src/utils/common/resolv.h
src/utils/common/sign.c
src/utils/common/sign.h
src/utils/common/strtonum.h
src/utils/common/token.c
src/utils/common/token.h
......@@ -512,6 +514,7 @@ tests/rrset.c
tests/rrset_wire.c
tests/server.c
tests/test_conf.h
tests/tsig_key.c
tests/utils.c
tests/wire.c
tests/worker_pool.c
......
......@@ -86,11 +86,9 @@ Enable debug messages.
Print help and usage.
.TP
\fB\-k\fP \fIkeyfile\fP
Use TSIG or SIG\-0 key stored in a file \fIkeyfile\fP to authenticate the request.
Supported file format is the same as generated by ISC \fBdnssec\-keygen\fP\&.
The key comprises of public (.key extension) and private part (.private
extension). Either of these file names or a name without the extension can be
specified as \fIkeyfile\fP parameter.
Use TSIG key stored in a file \fIkeyfile\fP to authenticate the request. The
file must contain the key in the same format, which is accepted by the
\fB\-y\fP option.
.TP
\fB\-p\fP \fIport\fP
Set nameserver port number or service name to send a query to. The default
......
......@@ -50,10 +50,12 @@ Remote UNIX socket/IP address (default is \fB@run_dir@/knot.sock\fP).
Remote server port (only for IP).
.TP
\fB\-y\fP, \fB\-\-key\fP [\fIalg\fP:]\fIname\fP:\fIkey\fP
Use key specified on the command line (default algorithm is hmac\-md5).
Use TSIG key specified on the command line (default algorithm is hmac\-md5).
.TP
\fB\-k\fP, \fB\-\-keyfile\fP \fIfile\fP
Use key file.
Use TSIG key stored in a file \fIfile\fP to authenticate the request. The
file must contain the key in the same format, which is accepted by the
\fB\-y\fP option.
.TP
\fB\-f\fP, \fB\-\-force\fP
Force operation. Overrides some checks.
......
......@@ -52,11 +52,9 @@ Enable debug messages.
Print help and usage.
.TP
\fB\-k\fP \fIkeyfile\fP
Use TSIG or SIG\-0 key stored in a file \fIkeyfile\fP to authenticate the request.
Supported file format is the same as generated by ISC \fBdnssec\-keygen\fP\&.
The key comprises of public (.key extension) and private part (.private
extension). Either of these file names or a name without the extension can be
specified as \fIkeyfile\fP parameter.
Use TSIG key stored in a file \fIkeyfile\fP to authenticate the request. The
file should contain the key in the same format, which is accepted by the
\fB\-y\fP option.
.TP
\fB\-p\fP \fIport\fP
Set the port to use for connections to the server (if not explicitly specified
......
......@@ -63,11 +63,9 @@ Options
Print help and usage.
**-k** *keyfile*
Use TSIG or SIG-0 key stored in a file *keyfile* to authenticate the request.
Supported file format is the same as generated by ISC :program:`dnssec-keygen`.
The key comprises of public (.key extension) and private part (.private
extension). Either of these file names or a name without the extension can be
specified as *keyfile* parameter.
Use TSIG key stored in a file *keyfile* to authenticate the request. The
file must contain the key in the same format, which is accepted by the
**-y** option.
**-p** *port*
Set nameserver port number or service name to send a query to. The default
......
......@@ -27,10 +27,12 @@ Parameters
Remote server port (only for IP).
**-y**, **--key** [*alg*:]\ *name*:*key*
Use key specified on the command line (default algorithm is hmac-md5).
Use TSIG key specified on the command line (default algorithm is hmac-md5).
**-k**, **--keyfile** *file*
Use key file.
Use TSIG key stored in a file *file* to authenticate the request. The
file must contain the key in the same format, which is accepted by the
**-y** option.
**-f**, **--force**
Force operation. Overrides some checks.
......
......@@ -29,11 +29,9 @@ Options
Print help and usage.
**-k** *keyfile*
Use TSIG or SIG-0 key stored in a file *keyfile* to authenticate the request.
Supported file format is the same as generated by ISC :program:`dnssec-keygen`.
The key comprises of public (.key extension) and private part (.private
extension). Either of these file names or a name without the extension can be
specified as *keyfile* parameter.
Use TSIG key stored in a file *keyfile* to authenticate the request. The
file should contain the key in the same format, which is accepted by the
**-y** option.
**-p** *port*
Set the port to use for connections to the server (if not explicitly specified
......
......@@ -28,7 +28,6 @@ nobase_libknot_la_HEADERS = \
libknot/consts.h \
libknot/descriptor.h \
libknot/dname.h \
libknot/dnssec/key.h \
libknot/errcode.h \
libknot/libknot.h \
libknot/packet/compr.h \
......@@ -53,7 +52,8 @@ nobase_libknot_la_HEADERS = \
libknot/rrtype/rrsig.h \
libknot/rrtype/soa.h \
libknot/rrtype/tsig.h \
libknot/tsig-op.h
libknot/tsig-op.h \
libknot/tsig.h
libknot_internal_ladir = $(includedir)
nobase_libknot_internal_la_HEADERS = \
......@@ -91,7 +91,6 @@ libknot_la_SOURCES = \
libknot/consts.c \
libknot/descriptor.c \
libknot/dname.c \
libknot/dnssec/key.c \
libknot/errcode.c \
libknot/packet/compr.c \
libknot/packet/pkt.c \
......@@ -108,6 +107,7 @@ libknot_la_SOURCES = \
libknot/rrtype/opt.c \
libknot/rrtype/tsig.c \
libknot/tsig-op.c \
libknot/tsig.c \
$(nobase_libknot_la_HEADERS)
libknot_yparser_la_SOURCES = \
......@@ -408,6 +408,8 @@ libknotus_la_SOURCES = \
utils/common/params.h \
utils/common/resolv.c \
utils/common/resolv.h \
utils/common/sign.c \
utils/common/sign.h \
utils/common/strtonum.h \
utils/common/token.c \
utils/common/token.h
......
......@@ -117,7 +117,7 @@ void help(void)
" -p, --port <port> Remote server port (only for IP).\n"
" -y, --key <[hmac:]name:key> Use key specified on the command line.\n"
" (default algorithm is hmac-md5)\n"
" -k, --keyfile <file> Use key file (as in config section 'keys').\n"
" -k, --keyfile <file> Read key from file (same format as -y).\n"
" -f, --force Force operation - override some checks.\n"
" -v, --verbose Verbose mode - additional runtime information.\n"
" -V, --version Print %s server version.\n"
......@@ -303,125 +303,6 @@ static int cmd_remote(struct sockaddr_storage *addr, knot_tsig_key_t *key,
return rc;
}
static int tsig_parse_str(knot_tsig_key_t *key, const char *str)
{
char *h = strdup(str);
if (!h) {
return KNOT_ENOMEM;
}
char *k = NULL, *s = NULL;
if ((k = (char*)strchr(h, ':'))) { /* Second part - NAME|SECRET */
*k++ = '\0'; /* String separator */
s = (char*)strchr(k, ':'); /* Thirt part - |SECRET */
}
/* Determine algorithm. */
int algorithm = DNSSEC_TSIG_HMAC_MD5;
if (s) {
*s++ = '\0'; /* Last part separator */
dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_name(h);
if (alg != DNSSEC_TSIG_UNKNOWN) {
algorithm = alg;
} else {
free(h);
return KNOT_EINVAL;
}
} else {
s = k; /* Ignore first part, push down. */
k = h;
}
/* Parse key name. */
int result = knot_tsig_create_key(k, algorithm, s, key);
free(h);
return result;
}
static int tsig_parse_line(knot_tsig_key_t *k, char *l)
{
const char *n, *a, *s;
n = a = s = NULL;
int fw = 1; /* 0 = reading word, 1 = between words */
while (*l != '\0') {
if (isspace((unsigned char)(*l)) || *l == '"') {
*l = '\0';
fw = 1; /* End word. */
} else if (fw) {
if (!n) { n = l; }
else if (!a) { a = l; }
else { s = l; }
fw = 0; /* Start word. */
}
l++;
}
/* No name parsed - assume wrong format. */
if (!n) {
return KNOT_EMALF;
}
/* Assume hmac-md5 if no algo specified. */
if (!s) {
s = a;
a = "hmac-md5";
}
/* Lookup algorithm. */
dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_name(a);
if (alg == DNSSEC_TSIG_UNKNOWN) {
return KNOT_EMALF;
}
/* Create the key data. */
return knot_tsig_create_key(n, alg, s, k);
}
static int tsig_parse_file(knot_tsig_key_t *k, const char *f)
{
FILE* fp = fopen(f, "r");
if (!fp) {
log_error("failed to open key-file '%s'", f);
return KNOT_EINVAL;
}
int c = 0;
int ret = KNOT_EOK;
char *line = malloc(64);
size_t llen = 0;
size_t lres = 0;
if (line) {
lres = 64;
}
while ((c = fgetc(fp)) != EOF) {
if (mreserve(&line, sizeof(char), llen + 1, 512, &lres) != 0) {
ret = KNOT_ENOMEM;
break;
}
if (c == '\n') {
if (k->name) {
log_error("only one key definition allowed "
"in '%s'", f);
ret = KNOT_EMALF;
break;
}
line[llen] = '\0';
ret = tsig_parse_line(k, line);
llen = 0;
} else {
line[llen++] = (char)c;
}
}
free(line);
fclose(fp);
return ret;
}
int main(int argc, char **argv)
{
/* Parse command line arguments */
......@@ -470,14 +351,14 @@ int main(int argc, char **argv)
r_port = atoi(optarg);
break;
case 'y':
if (tsig_parse_str(&r_key, optarg) != KNOT_EOK) {
if (knot_tsig_key_init_str(&r_key, optarg) != KNOT_EOK) {
rc = 1;
log_error("failed to parse TSIG key '%s'", optarg);
goto exit;
}
break;
case 'k':
if (tsig_parse_file(&r_key, optarg) != KNOT_EOK) {
if (knot_tsig_key_init_file(&r_key, optarg) != KNOT_EOK) {
rc = 1;
log_error("failed to parse TSIG key file '%s'", optarg);
goto exit;
......@@ -624,7 +505,7 @@ int main(int argc, char **argv)
exit:
/* Finish */
knot_tsig_key_free(&r_key);
knot_tsig_key_deinit(&r_key);
conf_free(conf(), false);
log_close();
......
......@@ -909,7 +909,7 @@ int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
sockaddr_tostr(addr_str, sizeof(addr_str), &ss);
/* Prepare tsig parameters. */
knot_tsig_key_t tsig = { NULL };
knot_tsig_key_t tsig = { 0 };
if (pkt->tsig_rr) {
tsig.name = pkt->tsig_rr->owner;
tsig.algorithm = knot_tsig_rdata_alg(pkt->tsig_rr);
......
......@@ -28,7 +28,6 @@
#include "libknot/packet/pkt.h"
#include "libknot/rrset.h"
#include "libknot/dnssec/key.h"
#include "knot/server/server.h"
/*! \brief Default connection control parameters. */
......
......@@ -25,7 +25,6 @@
#include "dnssec/sign.h"
#include "knot/dnssec/rrset-sign.h"
#include "libknot/descriptor.h"
#include "libknot/dnssec/key.h"
#include "libknot/libknot.h"
#include "libknot/packet/rrset-wire.h"
#include "libknot/packet/wire.h"
......
......@@ -556,7 +556,7 @@ bool process_query_acl_check(const knot_dname_t *zone_name, acl_action_t action,
{
knot_pkt_t *query = qdata->query;
const struct sockaddr_storage *query_source = qdata->param->remote;
knot_tsig_key_t tsig = { NULL };
knot_tsig_key_t tsig = { 0 };
/* Skip if already checked and valid. */
if (qdata->sign.tsig_key.name != NULL) {
......
......@@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -131,6 +132,31 @@ char *strcdup(const char *s1, const char *s2)
return dst;
}
char *strstrip(const char *str)
{
// leading white-spaces
const char *scan = str;
while (isspace((int)scan[0])) {
scan += 1;
}
// trailing white-spaces
size_t len = strlen(scan);
while (len > 1 && isspace((int)scan[len - 1])) {
len -= 1;
}
char *trimmed = malloc(len + 1);
if (!trimmed) {
return NULL;
}
memcpy(trimmed, scan, len + 1);
trimmed[len] = '\0';
return trimmed;
}
#ifdef MEM_DEBUG
/*
* ((destructor)) attribute executes this function after main().
......
......@@ -80,3 +80,10 @@ char *sprintf_alloc(const char *fmt, ...);
* \retval NULL on error.
*/
char *strcdup(const char *s1, const char *s2);
/*!
* \brief Create a copy of a string skipping leading and trailing white spaces.
*
* \return Newly allocated string, NULL in case of error.
*/
char *strstrip(const char *str);
......@@ -30,7 +30,6 @@
#include "libknot/rrset-dump.h"
#include "libknot/consts.h"
#include "libknot/descriptor.h"
#include "libknot/dnssec/key.h"
#include "libknot/errcode.h"
#include "libknot/internal/base64.h"
#include "libknot/internal/base32hex.h"
......
......@@ -33,14 +33,7 @@
#include "libknot/binary.h"
#include "libknot/consts.h"
#include "libknot/rrset.h"
struct knot_tsig_key {
knot_dname_t *name;
dnssec_tsig_algorithm_t algorithm;
dnssec_binary_t secret;
};
typedef struct knot_tsig_key knot_tsig_key_t;
#include "libknot/tsig.h"
enum tsig_consts {
KNOT_TSIG_ITEM_COUNT = 7,
......@@ -54,19 +47,6 @@ enum tsig_consts {
+ 6 // time signed
};
/*! \brief Packet signing context.
* \todo This should be later moved to TSIG files when refactoring. */
typedef struct knot_sign_context {
knot_tsig_key_t tsig_key;
uint8_t *tsig_buf;
uint8_t *tsig_digest;
size_t tsig_buflen;
size_t tsig_digestlen;
uint8_t tsig_runlen;
uint64_t tsig_time_signed;
size_t pkt_count;
} knot_sign_context_t;
/*!
* \brief Create TSIG RDATA.
*
......
......@@ -28,7 +28,6 @@
#include "libknot/packet/wire.h"
#include "libknot/consts.h"
#include "libknot/descriptor.h"
#include "libknot/dnssec/key.h"
#include "libknot/packet/wire.h"
#include "libknot/rrtype/tsig.h"
#include "libknot/tsig-op.h"
......
......@@ -28,7 +28,6 @@
#include <stdint.h>
#include "libknot/dnssec/key.h"
#include "libknot/rrtype/tsig.h"
#include "libknot/rrset.h"
......
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2015 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
......@@ -17,40 +17,52 @@
#include <assert.h>
#include <string.h>
#include "dnssec/binary.h"
#include "libknot/dnssec/key.h"
#include "dnssec/error.h"
#include "libknot/errcode.h"
#include "libknot/internal/getline.h"
#include "libknot/internal/macros.h"
#include "libknot/internal/mem.h"
#include "libknot/tsig.h"
#include "libknot/descriptor.h"
#include "libknot/errcode.h"
#include "libknot/binary.h"
#include "libknot/dname.h"
#include "libknot/dnssec/key.h"
#include "libknot/errcode.h"
#include "libknot/rrtype/tsig.h"
_public_
void knot_tsig_key_deinit(knot_tsig_key_t *key)
{
if (!key) {
return;
}
knot_dname_free(&key->name, NULL);
memset(key->secret.data, 0, key->secret.size);
dnssec_binary_free(&key->secret);
memset(key, '\0', sizeof(*key));
}
/*!
* \brief Creates TSIG key.
*/
_public_
int knot_tsig_create_key(const char *name, dnssec_tsig_algorithm_t algorithm,
const char *b64secret_str, knot_tsig_key_t *key)
int knot_tsig_key_init(knot_tsig_key_t *key, const char *algorithm_name,
const char *name, const char *secret_b64)
{
if (!name || !b64secret_str || !key) {
if (!name || !secret_b64 || !key) {
return KNOT_EINVAL;
}
knot_dname_t *dname;
dname = knot_dname_from_str_alloc(name);
dnssec_tsig_algorithm_t algorithm = DNSSEC_TSIG_HMAC_MD5;
if (algorithm_name != NULL) {
algorithm = dnssec_tsig_algorithm_from_name(algorithm_name);
if (algorithm == DNSSEC_TSIG_UNKNOWN) {
return KNOT_EMALF;
}
}
knot_dname_t *dname = knot_dname_from_str_alloc(name);
if (!dname) {
return KNOT_ENOMEM;
}
dnssec_binary_t b64secret = { 0 };
b64secret.data = (uint8_t *)b64secret_str;
b64secret.size = strlen(b64secret_str);
b64secret.data = (uint8_t *)secret_b64;
b64secret.size = strlen(secret_b64);
dnssec_binary_t secret = { 0 };
int result = dnssec_binary_from_base64(&b64secret, &secret);
......@@ -66,89 +78,116 @@ int knot_tsig_create_key(const char *name, dnssec_tsig_algorithm_t algorithm,
return KNOT_EOK;
}
/*!
* \brief Frees TSIG key.
*/
_public_
int knot_tsig_key_free(knot_tsig_key_t *key)
int knot_tsig_key_init_str(knot_tsig_key_t *key, const char *params)
{
if (!key) {
if (!params) {
return KNOT_EINVAL;
}
knot_dname_free(&key->name, NULL);
dnssec_binary_free(&key->secret);
memset(key, '\0', sizeof(knot_tsig_key_t));
char *copy = strstrip(params);
if (!copy) {
return KNOT_ENOMEM;
}
return KNOT_EOK;
}
size_t copy_size = strlen(copy) + 1;
_public_
int knot_copy_key_params(const knot_key_params_t *src, knot_key_params_t *dst)
{
if (src == NULL || dst == NULL) {
return KNOT_EINVAL;
}
// format [algorithm:]name:secret
knot_key_params_t copy = { 0 };
copy.algorithm = src->algorithm;
char *algorithm = NULL;
char *name = NULL;
char *secret = NULL;
if (src->name) {
copy.name = knot_dname_copy(src->name, NULL);
if (!copy.name) {
return KNOT_ENOMEM;
}
// find secret
char *pos = strrchr(copy, ':');
if (pos) {
*pos = '\0';
secret = pos + 1;
} else {
memset(copy, 0, copy_size);
free(copy);
return KNOT_EMALF;
}
int ret = dnssec_binary_dup(&src->secret, &copy.secret);
if (ret != KNOT_EOK) {
knot_dname_free(&copy.name, NULL);
// find name and optionally algorithm
pos = strchr(copy, ':');
if (pos) {
*pos = '\0';
algorithm = copy;
name = pos + 1;
} else {
name = copy;
}
*dst = copy;
int result = knot_tsig_key_init(key, algorithm, name, secret);
return KNOT_EOK;
memset(copy, 0, copy_size);
free(copy);
return result;
}
_public_
int knot_free_key_params(knot_key_params_t *key_params)
int knot_tsig_key_init_file(knot_tsig_key_t *key, const char *filename)
{
if (!key_params) {
if (!filename) {
return KNOT_EINVAL;
}
knot_dname_free(&key_params->name, NULL);
dnssec_binary_free(&key_params->secret);
FILE *file = fopen(filename, "r");
if (!file) {
return KNOT_EACCES;
}
char *line = NULL;
size_t line_size = 0;
ssize_t read = knot_getline(&line, &line_size, file);
memset(key_params, '\0', sizeof(*key_params));
fclose(file);
return KNOT_EOK;
if (read == -1) {
return KNOT_EMALF;
}
// strip trailing newline
assert(line);
if (read > 0 && line[read - 1] == '\n') {
line[read - 1] = '\0';
read -= 1;
}
int result = knot_tsig_key_init_str(key, line);
memset(line, 0, line_size);
free(line);
return result;
}
_public_
int knot_tsig_key_from_params(const knot_key_params_t *params,
knot_tsig_key_t *key_ptr)
int knot_tsig_key_copy(knot_tsig_key_t *dst, const knot_tsig_key_t *src)
{
if (!params || !key_ptr) {
if (!src || !dst) {
return KNOT_EINVAL;
}
knot_tsig_key_t key = { 0 };
key.algorithm = params->algorithm;
knot_tsig_key_t copy = { 0 };
copy.algorithm = src->algorithm;
key.name = knot_dname_copy(params->name, NULL);
if (!key.name) {
copy.name = knot_dname_copy(src->name, NULL);
if (!copy.name) {
return KNOT_ENOMEM;
}
int result = dnssec_binary_dup(&params->secret, &key.secret);
if (result != KNOT_EOK) {
knot_dname_free(&key.name, NULL);
return result;
if (dnssec_binary_dup(&src->secret, &copy.secret) != DNSSEC_EOK) {
knot_tsig_key_deinit(&copy);
return KNOT_ENOMEM;
}
*key_ptr = key;
*dst = copy;
return KNOT_EOK;
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2015 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
......@@ -12,86 +12,70 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file key.h
*
* \author Jan Vcelak <jan.vcelak@nic.cz>
*
* \brief Interface for loading of DNSSEC keys.
*
* \addtogroup dnssec
* @{
*/