summaryrefslogtreecommitdiff
path: root/examples/ldns-keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ldns-keygen.c')
-rw-r--r--examples/ldns-keygen.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/examples/ldns-keygen.c b/examples/ldns-keygen.c
new file mode 100644
index 0000000..62b8d22
--- /dev/null
+++ b/examples/ldns-keygen.c
@@ -0,0 +1,396 @@
+/*
+ * keygen is a small programs that generate a dnskey and private key
+ * for a particular domain.
+ *
+ * (c) NLnet Labs, 2005 - 2008
+ * See the file LICENSE for the license
+ */
+
+#include "config.h"
+
+#include <ldns/ldns.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_SSL
+static void
+usage(FILE *fp, char *prog) {
+ fprintf(fp, "%s -a <algorithm> [-b bits] [-r /dev/random] [-v] domain\n",
+ prog);
+ fprintf(fp, " generate a new key pair for domain\n");
+ fprintf(fp, " -a <alg>\tuse the specified algorithm (-a list to");
+ fprintf(fp, " show a list)\n");
+ fprintf(fp, " -k\t\tset the flags to 257; key signing key\n");
+ fprintf(fp, " -b <bits>\tspecify the keylength\n");
+ fprintf(fp, " -r <random>\tspecify a random device (defaults to /dev/random)\n");
+ fprintf(fp, "\t\tto seed the random generator with\n");
+ fprintf(fp, " -v\t\tshow the version and exit\n");
+ fprintf(fp, " The following files will be created:\n");
+ fprintf(fp, " K<name>+<alg>+<id>.key\tPublic key in RR format\n");
+ fprintf(fp, " K<name>+<alg>+<id>.private\tPrivate key in key format\n");
+ fprintf(fp, " K<name>+<alg>+<id>.ds\tDS in RR format (only for DNSSEC KSK keys)\n");
+ fprintf(fp, " The base name (K<name>+<alg>+<id> will be printed to stdout\n");
+}
+
+static void
+show_algorithms(FILE *out)
+{
+ ldns_lookup_table *lt = ldns_signing_algorithms;
+ fprintf(out, "Possible algorithms:\n");
+
+ while (lt->name) {
+ fprintf(out, "%s\n", lt->name);
+ lt++;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int fd;
+ char *prog;
+
+ /* default key size */
+ uint16_t def_bits = 1024;
+ uint16_t bits = def_bits;
+ bool had_bits = false;
+ bool ksk;
+
+ FILE *file;
+ FILE *random;
+ char *filename;
+ char *owner;
+
+ ldns_signing_algorithm algorithm;
+ ldns_rdf *domain;
+ ldns_rr *pubkey;
+ ldns_key *key;
+ ldns_rr *ds;
+
+ prog = strdup(argv[0]);
+ algorithm = 0;
+ random = NULL;
+ ksk = false; /* don't create a ksk per default */
+
+ while ((c = getopt(argc, argv, "a:kb:r:v")) != -1) {
+ switch (c) {
+ case 'a':
+ if (algorithm != 0) {
+ fprintf(stderr, "The -a argument can only be used once\n");
+ exit(1);
+ }
+ if (strncmp(optarg, "list", 5) == 0) {
+ show_algorithms(stdout);
+ exit(EXIT_SUCCESS);
+ }
+ algorithm = ldns_get_signing_algorithm_by_name(optarg);
+ if (algorithm == 0) {
+ fprintf(stderr, "Algorithm %s not found\n", optarg);
+ show_algorithms(stderr);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'b':
+ bits = (uint16_t) atoi(optarg);
+ if (bits == 0) {
+ fprintf(stderr, "%s: %s %d", prog, "Can not parse the -b argument, setting it to the default\n", (int) def_bits);
+ bits = def_bits;
+ } else
+ had_bits = true;
+ break;
+ case 'k':
+ ksk = true;
+ break;
+ case 'r':
+ random = fopen(optarg, "r");
+ if (!random) {
+ fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'v':
+ printf("DNSSEC key generator version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ usage(stderr, prog);
+ exit(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (algorithm == 0) {
+ printf("Please use the -a argument to provide an algorithm\n");
+ exit(1);
+ }
+
+ if (argc != 1) {
+ usage(stderr, prog);
+ exit(EXIT_FAILURE);
+ }
+ free(prog);
+
+ /* check whether key size is within RFC boundaries */
+ switch (algorithm) {
+ case LDNS_SIGN_RSAMD5:
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+ if (bits < 512 || bits > 4096) {
+ fprintf(stderr, "For RSA, the key size must be between ");
+ fprintf(stderr, " 512 and 4096 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+ if (bits < 512 || bits > 1024) {
+ fprintf(stderr, "For DSA, the key size must be between ");
+ fprintf(stderr, " 512 and 1024 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+#ifdef USE_GOST
+ case LDNS_SIGN_ECC_GOST:
+ if(!ldns_key_EVP_load_gost_id()) {
+ fprintf(stderr, "error: libcrypto does not provide GOST\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+#endif
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ case LDNS_SIGN_ECDSAP384SHA384:
+ break;
+#endif
+ case LDNS_SIGN_HMACMD5:
+ if (!had_bits) {
+ bits = 512;
+ } else if (bits < 1 || bits > 512) {
+ fprintf(stderr, "For hmac-md5, the key size must be ");
+ fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+ case LDNS_SIGN_HMACSHA1:
+ if (!had_bits) {
+ bits = 160;
+ } else if (bits < 1 || bits > 160) {
+ fprintf(stderr, "For hmac-sha1, the key size must be ");
+ fprintf(stderr, "between 1 and 160 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+
+ case LDNS_SIGN_HMACSHA224:
+ if (!had_bits) {
+ bits = 224;
+ } else if (bits < 1 || bits > 224) {
+ fprintf(stderr, "For hmac-sha224, the key size must be ");
+ fprintf(stderr, "between 1 and 224 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+
+ case LDNS_SIGN_HMACSHA256:
+ if (!had_bits) {
+ bits = 256;
+ } else if (bits < 1 || bits > 256) {
+ fprintf(stderr, "For hmac-sha256, the key size must be ");
+ fprintf(stderr, "between 1 and 256 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+
+ case LDNS_SIGN_HMACSHA384:
+ if (!had_bits) {
+ bits = 384;
+ } else if (bits < 1 || bits > 384) {
+ fprintf(stderr, "For hmac-sha384, the key size must be ");
+ fprintf(stderr, "between 1 and 384 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+
+ case LDNS_SIGN_HMACSHA512:
+ if (!had_bits) {
+ bits = 512;
+ } else if (bits < 1 || bits > 512) {
+ fprintf(stderr, "For hmac-sha512, the key size must be ");
+ fprintf(stderr, "between 1 and 512 bits. Aborting.\n");
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!random) {
+ random = fopen("/dev/random", "r");
+ if (!random) {
+ fprintf(stderr, "Cannot open random file %s: %s\n", optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ (void)ldns_init_random(random, (unsigned int) bits/8);
+ fclose(random);
+
+ /* create an rdf from the domain name */
+ domain = ldns_dname_new_frm_str(argv[0]);
+
+ /* generate a new key */
+ key = ldns_key_new_frm_algorithm(algorithm, bits);
+ if(!key) {
+ fprintf(stderr, "cannot generate key of algorithm %s\n",
+ ldns_pkt_algorithm2str((ldns_algorithm)algorithm));
+ exit(EXIT_FAILURE);
+ }
+
+ /* set the owner name in the key - this is a /separate/ step */
+ ldns_key_set_pubkey_owner(key, domain);
+
+ /* ksk flag */
+ if (ksk) {
+ ldns_key_set_flags(key, ldns_key_flags(key) + 1);
+ }
+
+ /* create the public from the ldns_key */
+ pubkey = ldns_key2rr(key);
+ if (!pubkey) {
+ fprintf(stderr, "Could not extract the public key from the key structure...");
+ ldns_key_deep_free(key);
+ exit(EXIT_FAILURE);
+ }
+ owner = ldns_rdf2str(ldns_rr_owner(pubkey));
+
+ /* calculate and set the keytag */
+ ldns_key_set_keytag(key, ldns_calc_keytag(pubkey));
+
+ /* build the DS record */
+ switch (algorithm) {
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP384SHA384:
+ ds = ldns_key_rr2ds(pubkey, LDNS_SHA384);
+ break;
+ case LDNS_SIGN_ECDSAP256SHA256:
+#endif
+#ifdef USE_ED25519
+ case LDNS_SIGN_ED25519:
+#endif
+#ifdef USE_ED448
+ case LDNS_SIGN_ED448:
+#endif
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+ ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
+ break;
+ case LDNS_SIGN_ECC_GOST:
+#ifdef USE_GOST
+ ds = ldns_key_rr2ds(pubkey, LDNS_HASH_GOST);
+#else
+ ds = ldns_key_rr2ds(pubkey, LDNS_SHA256);
+#endif
+ break;
+ default:
+ ds = ldns_key_rr2ds(pubkey, LDNS_SHA1);
+ break;
+ }
+
+ /* print the public key RR to .key */
+ filename = LDNS_XMALLOC(char, strlen(owner) + 17);
+ snprintf(filename, strlen(owner) + 16, "K%s+%03u+%05u.key", owner, algorithm, (unsigned int) ldns_key_keytag(key));
+ file = fopen(filename, "w");
+ if (!file) {
+ fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
+ ldns_key_deep_free(key);
+ free(owner);
+ ldns_rr_free(pubkey);
+ ldns_rr_free(ds);
+ LDNS_FREE(filename);
+ exit(EXIT_FAILURE);
+ } else {
+ /* temporarily set question so that TTL is not printed */
+ ldns_rr_set_question(pubkey, true);
+ ldns_rr_print(file, pubkey);
+ ldns_rr_set_question(pubkey, false);
+ fclose(file);
+ LDNS_FREE(filename);
+ }
+
+ /* print the priv key to stderr */
+ filename = LDNS_XMALLOC(char, strlen(owner) + 21);
+ snprintf(filename, strlen(owner) + 20, "K%s+%03u+%05u.private", owner, algorithm, (unsigned int) ldns_key_keytag(key));
+ /* use open() here to prevent creating world-readable private keys (CVE-2014-3209)*/
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ goto fail;
+ }
+
+ file = fdopen(fd, "w");
+ if (!file) {
+ goto fail;
+ }
+
+ ldns_key_print(file, key);
+ fclose(file);
+ LDNS_FREE(filename);
+
+ /* print the DS to .ds */
+ if (ksk && algorithm != LDNS_SIGN_HMACMD5 &&
+ algorithm != LDNS_SIGN_HMACSHA1 &&
+ algorithm != LDNS_SIGN_HMACSHA224 &&
+ algorithm != LDNS_SIGN_HMACSHA256 &&
+ algorithm != LDNS_SIGN_HMACSHA384 &&
+ algorithm != LDNS_SIGN_HMACSHA512) {
+ filename = LDNS_XMALLOC(char, strlen(owner) + 16);
+ snprintf(filename, strlen(owner) + 15, "K%s+%03u+%05u.ds", owner, algorithm, (unsigned int) ldns_key_keytag(key));
+ file = fopen(filename, "w");
+ if (!file) {
+ fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
+ ldns_key_deep_free(key);
+ free(owner);
+ ldns_rr_free(pubkey);
+ ldns_rr_free(ds);
+ LDNS_FREE(filename);
+ exit(EXIT_FAILURE);
+ } else {
+ /* temporarily set question so that TTL is not printed */
+ ldns_rr_set_question(ds, true);
+ ldns_rr_print(file, ds);
+ ldns_rr_set_question(ds, false);
+ fclose(file);
+ LDNS_FREE(filename);
+ }
+ }
+
+ fprintf(stdout, "K%s+%03u+%05u\n", owner, algorithm, (unsigned int) ldns_key_keytag(key));
+ ldns_key_deep_free(key);
+ free(owner);
+ ldns_rr_free(pubkey);
+ ldns_rr_free(ds);
+ exit(EXIT_SUCCESS);
+
+fail:
+ fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
+ ldns_key_deep_free(key);
+ free(owner);
+ ldns_rr_free(pubkey);
+ ldns_rr_free(ds);
+ LDNS_FREE(filename);
+ exit(EXIT_FAILURE);
+}
+#else
+int
+main(int argc, char **argv)
+{
+ fprintf(stderr, "ldns-keygen needs OpenSSL support, which has not been compiled in\n");
+ return 1;
+}
+#endif /* HAVE_SSL */