Commit 5ea7ff89 authored by Jan Včelák's avatar Jan Včelák 🚀

libknot: new module for TSIG parameters parsing

parent 19cd92f8
......@@ -53,7 +53,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 = \
......@@ -108,6 +109,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 = \
......
/* 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
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 <assert.h>
#include <string.h>
#include "libknot/errcode.h"
#include "libknot/internal/getline.h"
#include "libknot/internal/macros.h"
#include "libknot/tsig.h"
_public_
void knot_tsig_key_deinit(knot_tsig_key_t *key)
{
if (!key) {
return;
}
knot_dname_free(&key->name, NULL);
dnssec_binary_free(&key->secret);
memset(key, '\0', sizeof(*key));
}
_public_
int knot_tsig_key_init(knot_tsig_key_t *key, const char *algorithm_name,
const char *name, const char *secret_b64)
{
if (!name || !secret_b64 || !key) {
return KNOT_EINVAL;
}
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 *)secret_b64;
b64secret.size = strlen(secret_b64);
dnssec_binary_t secret = { 0 };
int result = dnssec_binary_from_base64(&b64secret, &secret);
if (result != KNOT_EOK) {
knot_dname_free(&dname, NULL);
return result;
}
key->name = dname;
key->algorithm = algorithm;
key->secret = secret;
return KNOT_EOK;
}
_public_
int knot_tsig_key_init_str(knot_tsig_key_t *key, const char *params)
{
if (!params) {
return KNOT_EINVAL;
}
char *copy = strdup(params);
if (!copy) {
return KNOT_ENOMEM;
}
// format [algorithm:]name:secret
char *algorithm = NULL;
char *name = NULL;
char *secret = NULL;
// find secret
char *pos = strrchr(copy, ':');
if (pos) {
*pos = '\0';
secret = pos + 1;
} else {
free(copy);
return KNOT_EMALF;
}
// find name and optionally algorithm
pos = strchr(copy, ':');
if (pos) {
*pos = '\0';
algorithm = copy;
name = pos + 1;
} else {
name = copy;
}
int result = knot_tsig_key_init(key, algorithm, name, secret);
free(copy);
return result;
}
_public_
int knot_tsig_key_init_file(knot_tsig_key_t *key, const char *filename)
{
if (!filename) {
return KNOT_EINVAL;
}
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);
fclose(file);
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);
free(line);
return result;
}
/* 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
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 "libknot/dname.h"
#include "dnssec/tsig.h"
/*!
* \brief TSIG key.
*/
struct knot_tsig_key {
dnssec_tsig_algorithm_t algorithm;
knot_dname_t *name;
dnssec_binary_t secret;
};
typedef struct knot_tsig_key knot_tsig_key_t;
/*!
* \brief Packet signing context.
*/
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 Initialize a new TSIG key from individual key parameters.
*
* \param[out] key Key to be initialized.
* \param[in] algorithm Algorithm name. NULL for default (hmac-md5).
* \param[in] name Key name (domain name in presentation format).
* \param[in] secret_b64 Secret encoded using Base 64.
*
* \return Error code, KNOT_EOK if successful.
*/
int knot_tsig_key_init(knot_tsig_key_t *key, const char *algorithm,
const char *name, const char *secret_b64);
/*!
* \brief Create a new TSIG key from a string encoding all parameters.
*
* \param params Parameters in a form \a [algorithm:]name:base64_secret
*/
int knot_tsig_key_init_str(knot_tsig_key_t *key, const char *params);
/*!
* \brief Create a new TSIG key by reading the parameters from a file.
*
* The file content is parsed by \a tsig_key_create_str.
*/
int knot_tsig_key_init_file(knot_tsig_key_t *key, const char *filename);
/*!
* \brief Deinitialize TSIG key.
*/
void knot_tsig_key_deinit(knot_tsig_key_t *key);
......@@ -35,6 +35,7 @@ rrl
rrset
rrset_wire
server
tsig_key
utils
wire
worker_pool
......
......@@ -39,6 +39,7 @@ check_PROGRAMS = \
rrset \
rrset_wire \
server \
tsig_key \
utils \
wire \
worker_pool \
......
/* 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
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 <tap/basic.h>
#include <assert.h>
#include <stdbool.h>
#include <unistd.h>
#include "libknot/errcode.h"
#include "libknot/tsig.h"
static bool key_is_eq(const knot_tsig_key_t *a, const knot_tsig_key_t *b)
{
if (a == NULL && b == NULL) {
return true;
}
if (a == NULL || b == NULL) {
return false;
}
return a->algorithm == b->algorithm &&
knot_dname_is_equal(a->name, b->name) &&
dnssec_binary_cmp(&a->secret, &b->secret) == 0;
}
#define test_function(function, msg, expected, ...) \
knot_tsig_key_t key = { 0 }; \
int r = function(&key, __VA_ARGS__); \
ok((r != KNOT_EOK && expected == NULL) || \
(r == KNOT_EOK && key_is_eq(&key, expected)), \
"%s: %s", #function, msg); \
knot_tsig_key_deinit(&key);
static void test_init(const char *msg, const knot_tsig_key_t *expected,
const char *algo, const char *name, const char *secret)
{
test_function(knot_tsig_key_init, msg, expected, algo, name, secret);
}
static void test_init_str(const char *msg, const knot_tsig_key_t *expected,
const char *params)
{
test_function(knot_tsig_key_init_str, msg, expected, params);
}
static void test_init_file(const char *msg, const knot_tsig_key_t *expected,
const char *filename)
{
test_function(knot_tsig_key_init_file, msg, expected, filename);
}
static void test_init_file_content(const char *msg,
const knot_tsig_key_t *expected,
const char *content)
{
char filename[] = "testkey.XXXXXX";
int fd = mkstemp(filename);
if (fd == -1) {
bail("failed to create temporary file");
return;
}
write(fd, content, strlen(content));
close(fd);
test_init_file(msg, expected, filename);
unlink(filename);
}
int main(int argc, char *argv[])
{
plan_lazy();
// initialization from parameters
test_init("missing name", NULL, "hmac-md5", NULL, "Wg==");
test_init("missing secret", NULL, "hmac-md5", "name", NULL);
test_init("invalid HMAC", NULL, "hmac-sha11", "name", "Wg==");
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_MD5,
.name = (uint8_t *)"\x3""key""\x4""name",
.secret.size = 1,
.secret.data = (uint8_t *)"\x5a"
};
test_init("default algorithm", &key, NULL, "key.name", "Wg==");
}
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_SHA1,
.name = (uint8_t *)"\x4""knot""\x3""dns",
.secret.size = 6,
.secret.data = (uint8_t *)"secret"
};
test_init("sha1", &key, "hmac-sha1", "knot.dns.", "c2VjcmV0");
}
// initialization from string
test_init_str("missing value", NULL, NULL);
test_init_str("malformed", NULL, "this is malformed");
test_init_str("invalid HMAC", NULL, "hmac-sha51299:key:Wg==");
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_MD5,
.name = (uint8_t *)"\x4""tsig""\x3""key",
.secret.size = 9,
.secret.data = (uint8_t *)"bananakey"
};
test_init_str("default algorithm", &key, "tsig.key:YmFuYW5ha2V5");
}
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_SHA384,
.name = (uint8_t *)"\x6""strong""\x3""key",
.secret.size = 8,
.secret.data = (uint8_t *)"applekey"
};
test_init_str("sha384", &key, "hmac-sha384:strong.key:YXBwbGVrZXk=");
}
// initialization from a file
test_init_file("no filename", NULL, NULL);
test_init_file("not-existing", NULL, "/this-really-should-not-exist");
test_init_file_content("malformed content", NULL, "malformed\n");
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_SHA512,
.name = (uint8_t *)"\x6""django""\x3""one",
.secret.size = 40,
.secret.data = (uint8_t *)"Who's that stumbling around in the dark?"
};
test_init_file_content("sha512", &key,
"hmac-sha512:django.one:V2hvJ3MgdGhhdCB"
"zdHVtYmxpbmcgYXJvdW5kIGluIHRoZSBkYXJrP"
"w==\n\n\n");
}
{
static const knot_tsig_key_t key = {
.algorithm = DNSSEC_TSIG_HMAC_SHA512,
.name = (uint8_t *)"\x6""django""\x3""two",
.secret.size = 22,
.secret.data = (uint8_t *)"Prepare to get winged!"
};
test_init_file_content("sha512 without newline", &key,
"hmac-sha512:django.two:UHJlcGFyZSB0byB"
"nZXQgd2luZ2VkIQ==");
}
return 0;
}
Markdown is supported
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