Commit 7966d896 authored by Jan Včelák's avatar Jan Včelák 🚀

[dnssec] base for legacy key loading

parent 7e457f14
AM_CPPFLAGS = \
noinst_LTLIBRARIES = libutils.la
AM_CFLAGS = \
-include $(top_builddir)/src/config.h \
-I$(srcdir)/../shared \
-I$(srcdir)/../lib/dnssec \
-I$(srcdir)/../lib
LDADD = \
libutils_la_LIBADD = \
$(builddir)/../libshared.la \
$(builddir)/../libdnssec.la
$(builddir)/../libdnssec.la \
$(top_builddir)/src/zscanner/libzscanner.la
libutils_la_CFLAGS = \
$(AM_CFLAGS) \
-I$(top_srcdir)/src/zscanner
libutils_la_SOURCES = \
legacy/legacy.c \
legacy/legacy.h \
legacy/privkey.c \
legacy/privkey.h \
legacy/pubkey.c \
legacy/pubkey.h
LDADD = libutils.la
bin_PROGRAMS = \
generate \
import \
parsekey
#include <stdio.h>
#include <stdlib.h>
#include "dnssec/crypto.h"
#include "dnssec/error.h"
#include "dnssec/key.h"
#include "shared.h"
#include "legacy/legacy.h"
int main(int argc, char *argv[])
{
dnssec_crypto_init();
atexit(dnssec_crypto_cleanup);
if (argc != 2) {
fprintf(stderr, "import <name>\n");
return 1;
}
int r = legacy_key_import(argv[1]);
if (r != DNSSEC_EOK) {
fprintf(stderr, "Key import error: %s\n", dnssec_strerror(r));
return 1;
}
return 0;
// if (legacy_pubkey_parse(filename_bind) != 0) {
// fprintf(stderr, "Unable to parse legacy key.\n");
// }
// dnssec_key_t *key = load_public_key(filename_dnskey);
// if (!key) {
// fprintf(stderr, "Unable to parse public key.\n");
// }
// dnssec_key_free(key);
return 0;
}
#pragma once
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "dnssec/binary.h"
#include "dnssec/error.h"
#include "shared.h"
/** -- **/
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
static gnutls_datum_t binary2datum(const dnssec_binary_t *from)
{
gnutls_datum_t to = { .size = from->size, .data = from->data };
return to;
}
static int rsa_params_to_pem(const key_params_t *params)
{
_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 = binary2datum(&params->modulus);
gnutls_datum_t e = binary2datum(&params->public_exponent);
gnutls_datum_t d = binary2datum(&params->private_exponent);
gnutls_datum_t p = binary2datum(&params->prime_one);
gnutls_datum_t q = binary2datum(&params->prime_two);
gnutls_datum_t u = binary2datum(&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;
}
//result = gnutls_x509_privkey_export_pkcs8(key, pem, NULL, pain
return DNSSEC_NOT_IMPLEMENTED_ERROR;
}
static int params_to_pem(const key_params_t *params, dnssec_binary_t *pem)
{
return DNSSEC_NOT_IMPLEMENTED_ERROR;
}
#include <assert.h>
#include <stdio.h>
#include "dnssec/error.h"
#include "legacy/legacy.h"
#include "legacy/privkey.h"
#include "legacy/pubkey.h"
#include "shared.h"
static void get_key_names(const char *input, char **public_ptr, char **private_ptr)
{
assert(input);
assert(public_ptr);
assert(private_ptr);
asprintf(public_ptr, "%s.key", input);
asprintf(private_ptr, "%s.private", input);
}
int legacy_key_import(const char *filename)
{
if (!filename) {
return DNSSEC_EINVAL;
}
_cleanup_free_ char *filename_dnskey = NULL;
_cleanup_free_ char *filename_private = NULL;
get_key_names(filename, &filename_dnskey, &filename_private);
if (!filename_dnskey || !filename_private) {
return DNSSEC_EINVAL;
}
legacy_privkey_t params = { 0 };
int r = legacy_privkey_parse(filename_private, &params);
if (r != DNSSEC_EOK) {
return r;
}
printf("conversion happens here\n");
legacy_privkey_free(&params);
return DNSSEC_EOK;
}
#pragma once
int legacy_key_import(const char *filename);
#include <ctype.h>
#include <string.h>
#include "dnssec/binary.h"
#include "dnssec/error.h"
#include "legacy/privkey.h"
#include "shared.h"
#include "strtonum.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);
}
#define off(field) offsetof(legacy_privkey_t, field)
/*!
* Know attributes in private key file.
*/
const param_t PRIVKEY_CONVERSION_TABLE[] = {
{ "Algorithm", off(algorithm), parse_algorithm, NULL },
{ "Modulus", off(modulus), parse_binary, binary_free },
{ "PublicExponent", off(public_exponent), parse_binary, binary_free },
{ "PrivateExponent", off(private_exponent), parse_binary, binary_free },
{ "Prime1", off(prime_one), parse_binary, binary_free },
{ "Prime2", off(prime_two), parse_binary, binary_free },
{ "Exponent1", off(exponent_one), parse_binary, binary_free },
{ "Exponent2", off(exponent_two), parse_binary, binary_free },
{ "Coefficient", off(coefficient), parse_binary, binary_free },
{ "Prime(p)", off(prime), parse_binary, binary_free },
{ "Subprime(q)", off(subprime), parse_binary, binary_free },
{ "Base(g)", off(base), parse_binary, binary_free },
{ "Private_value(x)",off(private_value), parse_binary, binary_free },
{ "Public_value(y)", off(public_value), parse_binary, binary_free },
{ "PrivateKey", off(private_key), parse_binary, binary_free },
{ "Created", off(time_created), parse_time, NULL },
{ "Publish", off(time_publish), parse_time, NULL },
{ "Activate", off(time_activate), parse_time, NULL },
{ "Revoke", off(time_revoke), parse_time, NULL },
{ "Inactive", off(time_inactive), parse_time, NULL },
{ "Delete", off(time_delete), parse_time, NULL },
{ NULL }
};
#undef off
/* -- 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(*end)) {
end += 1;
}
*end = '\0';
uint8_t *algorithm = _algorithm;
int r = str_to_u8(string, algorithm);
return (r == DNSSEC_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(**value)) {
*value += 1;
*length -= 1;
}
// strip from right
while (*length > 0 && isspace((*value)[*length - 1])) {
*length -= 1;
}
}
/*!
* Parse one line of the private key file.
*/
static int parse_line(legacy_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 legacy_privkey_parse(const char *filename, legacy_privkey_t *params_ptr)
{
_cleanup_fclose_ FILE *file = fopen(filename, "r");
if (!file) {
return DNSSEC_NOT_FOUND;
}
legacy_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) {
legacy_privkey_free(&params);
return r;
}
}
*params_ptr = params;
return DNSSEC_EOK;
}
/* -- freeing -------------------------------------------------------------- */
/*!
* Free private key parameters.
*/
void legacy_privkey_free(legacy_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);
}
#pragma once
#include <stdint.h>
#include <time.h>
#include "dnssec/binary.h"
/*!
* Legacy private key parameters.
*/
typedef struct legacy_privkey {
// 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;
} legacy_privkey_t;
/*!
* Extract parameters from legacy private key file.
*/
int legacy_privkey_parse(const char *filename, legacy_privkey_t *params);
/*!
* Free private key parameters.
*/
void legacy_privkey_free(legacy_privkey_t *params);
#include <assert.h>
// Knot zone scanner
#include "scanner.h"
#include "loader.h"
#include "dnssec/error.h"
#include "dnssec/binary.h"
#include "dnssec/key.h"
#include "legacy/pubkey.h"
#define CLASS_IN 1
#define RTYPE_DNSKEY 48
/*!
* Parse DNSKEY record.
*
* \todo Currently, the function waits for the first DNSKEY record, and skips
* the others. We should be more strict and report other records as errors.
* However, there is currently no API to stop the scanner.
*/
static void parse_record(const zs_scanner_t *scanner)
{
assert(scanner);
assert(scanner->data);
dnssec_key_t *key = scanner->data;
if (dnssec_key_get_dname(key) != NULL) {
// skip till the the parser finishes
return;
}
if (scanner->r_type != RTYPE_DNSKEY) {
// should report error
return;
}
dnssec_binary_t rdata = {
.const_data = scanner->r_data,
.size = scanner->r_data_length
};
dnssec_key_set_dname(key, scanner->dname);
dnssec_key_set_rdata(key, &rdata);
}
dnssec_key_t *legacy_pubkey_parse(const char *filename)
{
dnssec_key_t *key = NULL;
int r = dnssec_key_new(&key);
if (r != DNSSEC_EOK) {
return NULL;
}
uint16_t class = CLASS_IN;
uint32_t ttl = 0;
zs_loader_t *loader = zs_loader_create(filename, ".", class, ttl,
parse_record, NULL, key);
if (!loader) {
dnssec_key_free(key);
return NULL;
}
zs_loader_process(loader);
zs_loader_free(loader);
return key;
}
#pragma once
#include "dnssec/key.h"
/*!
* Parse public key in legacy (actually zone) format.
*/
dnssec_key_t *legacy_pubkey_parse(const char *filename);
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