ldnssec-utils/ldnssec-keygen.c

310 lines
5.8 KiB
C

/*
* ldnssec-utils
*
* Written in 2021 by Lucas
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ldns/ldns.h>
#include "util.h"
static void
usage(void)
{
const char *p = getprogname();
fprintf(stderr, "usage:\n"
"\t%s dnskey [-d domain] [-k]\n"
"\t%s ds [-a algorithm] [-d domain]\n"
"\t%s filename [-d domain] [-k]\n"
"\t%s gen [-a algorithm] [-b bits]\n",
p, p, p, p);
exit(1);
}
static void
cmd_dnskey_usage(void)
{
fprintf(stderr, "usage: %s dnskey [-d domain] [-k]\n", getprogname());
exit(1);
}
static void
cmd_ds_usage(void)
{
fprintf(stderr, "usage: %s ds [-a algorithm] [-d domain]\n",
getprogname());
exit(1);
}
static void
cmd_filename_usage(void)
{
fprintf(stderr, "usage: %s filename [-d domain] [-k]\n",
getprogname());
exit(1);
}
static void
cmd_gen_usage(void)
{
fprintf(stderr, "usage: %s gen [-a algorithm] [-b bits]\n",
getprogname());
exit(1);
}
static void
ds_dnskey_rr_filename_print(const char *domain, int sep, ldns_hash hash,
int do_filename)
{
ldns_key *key;
ldns_rr *dnskey_rr, *ds_rr = NULL;
ldns_rdf *rdf_dname;
ldns_status s;
char *str;
uint16_t flags;
int do_ds, line_nr;
s = ldns_key_new_frm_fp_l(&key, stdin, &line_nr);
if (s != LDNS_STATUS_OK)
errx(1, "ldns_key_new_frm_fp_l: (stdin) line %d: %s",
line_nr, ldns_get_errorstr_by_id(s));
s = ldns_str2rdf_dname(&rdf_dname, domain);
if (s != LDNS_STATUS_OK)
errx(1, "ldns_str2rdf_dname: %s: %s", domain,
ldns_get_errorstr_by_id(s));
flags = LDNS_KEY_ZONE_KEY;
if (sep)
flags |= LDNS_KEY_SEP_KEY;
ldns_key_set_pubkey_owner(key, rdf_dname);
ldns_key_set_flags(key, flags);
dnskey_rr = ldns_key2rr(key);
if (dnskey_rr == NULL)
errx(1, "ldns_key2rr");
if (do_filename) {
ldns_key_set_keytag(key, ldns_calc_keytag(dnskey_rr));
str = ldns_key_get_file_base_name(key);
if (str == NULL)
errx(1, "ldns_key_get_file_base_name");
printf("%s\n", str);
} else {
do_ds = hash != 0;
if (do_ds) {
ds_rr = ldns_key_rr2ds(dnskey_rr, hash);
if (ds_rr == NULL)
errx(1, "ldns_key_rr2ds");
}
str = ldns_rr2str(do_ds ? ds_rr : dnskey_rr);
if (str == NULL)
errx(1, "ldns_rr2str");
fputs(str, stdout);
}
free(str);
ldns_rr_free(dnskey_rr);
ldns_rr_free(ds_rr);
ldns_key_deep_free(key);
}
static int
cmd_dnskey_main(int argc, char *argv[])
{
const char *domain;
int ch, sep;
domain = ".";
sep = 0;
while ((ch = getopt(argc, argv, "d:k")) != -1) {
switch (ch) {
case 'd':
domain = optarg;
break;
case 'k':
sep = 1;
break;
default:
cmd_dnskey_usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0)
cmd_ds_usage();
ds_dnskey_rr_filename_print(domain, sep, 0, 0);
return 0;
}
static int
cmd_ds_main(int argc, char *argv[])
{
ldns_hash alg;
const char *domain;
int ch;
alg = LDNS_SHA256;
domain = ".";
while ((ch = getopt(argc, argv, "a:d:")) != -1) {
switch (ch) {
case 'a':
alg = ldnssec_get_hash_algorithm_by_name(optarg);
if (ldns_lookup_by_id(ldnssec_hashes, alg) == NULL)
errx(1, "-a: unsupported algorithm %s",
optarg);
break;
case 'd':
domain = optarg;
break;
default:
cmd_ds_usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0)
cmd_ds_usage();
ds_dnskey_rr_filename_print(domain, 1, alg, 0);
return 0;
}
static int
cmd_filename_main(int argc, char *argv[])
{
const char *domain;
int ch, sep;
domain = ".";
sep = 0;
while ((ch = getopt(argc, argv, "d:k")) != -1) {
switch (ch) {
case 'd':
domain = optarg;
break;
case 'k':
sep = 1;
break;
default:
cmd_filename_usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0)
cmd_filename_usage();
ds_dnskey_rr_filename_print(domain, sep, 0, 1);
return 0;
}
static int
cmd_gen_main(int argc, char *argv[])
{
ldns_key *key;
ldns_signing_algorithm alg;
const char *errstr;
char *str;
long long n;
int ch;
uint16_t bits;
alg = LDNS_SIGN_ECDSAP256SHA256;
bits = 0;
while ((ch = getopt(argc, argv, "a:b:")) != -1) {
switch (ch) {
case 'a':
alg = ldns_get_signing_algorithm_by_name(optarg);
/*
* ldns_key_algo_supported can't be used here as
* it uses ldns_signing_algorithms lookup table, which
* includes algorithms for TSIG.
*/
if (ldns_lookup_by_id(ldns_algorithms, alg) == NULL)
errx(1, "-a: unsupported algorithm %s",
optarg);
break;
case 'b':
n = strtonum(optarg, 0, UINT16_MAX, &errstr);
if (errstr != NULL)
errx(1, "-b: bits is %s: %s", errstr, optarg);
bits = n;
break;
default:
cmd_gen_usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0)
cmd_gen_usage();
key = ldns_key_new_frm_algorithm(alg, bits);
if (key == NULL)
errx(1, "error generating key of type %s", argv[0]);
/* ldns_key_print uses stdout to signal errors */
str = ldns_key2str(key);
if (str == NULL)
errx(1, "ldns_key2str");
fputs(str, stdout);
free(str);
ldns_key_deep_free(key);
return 0;
}
int
main(int argc, char *argv[])
{
const char *cmd;
int rc;
if (argc < 2)
usage();
cmd = argv[1];
rc = 1;
optind = 2;
if (strcmp(cmd, "ds") == 0)
rc = cmd_ds_main(argc, argv);
else if (strcmp(cmd, "dnskey") == 0)
rc = cmd_dnskey_main(argc, argv);
else if (strcmp(cmd, "filename") == 0)
rc = cmd_filename_main(argc, argv);
else if (strcmp(cmd, "gen") == 0)
rc = cmd_gen_main(argc, argv);
else
usage();
return rc;
}