printf("calc keytag for key at %p:\n", key);
ldns_rr_print(stdout, key);
*/
- if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY) {
+ if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY &&
+ ldns_rr_get_type(key) != LDNS_RR_TYPE_KEY
+ ) {
return 0;
}
* apps must call this
*/
ldns_status
-ldns_init_random(FILE *fd, uint16_t bytes)
+ldns_init_random(FILE *fd)
{
- FILE *rand;
- uint8_t *buf;
-
- buf = LDNS_XMALLOC(uint8_t, bytes);
- if (!buf) {
- return LDNS_STATUS_ERR;;
- }
+ /* if fp is given, seed srand with data from file
+ otherwise use /dev/urandom */
+ FILE *rand_f;
+ unsigned int seed;
+ size_t read;
+
if (!fd) {
- if ((rand = fopen("/dev/urandom", "r")) == NULL) {
- LDNS_FREE(buf);
+ if ((rand_f = fopen("/dev/urandom", "r")) == NULL) {
return LDNS_STATUS_ERR;
}
} else {
- rand = fd;
+ rand_f = fd;
}
-
- if ((fread(buf, sizeof(uint8_t), (size_t)bytes, rand) != bytes)) {
- LDNS_FREE(buf);
- if (!fd) {
- fclose(rand);
- }
+
+ read = fread(&seed, sizeof(seed), 1, rand_f);
+ if (read == 0) {
return LDNS_STATUS_ERR;
+ } else {
+ srand(seed);
}
+
if (!fd) {
- fclose(rand);
+ fclose(rand_f);
}
- RAND_seed((const void *)buf, (int)bytes);
- LDNS_FREE(buf);
+
return LDNS_STATUS_OK;
}
.SH OPTIONS
.TP
\fB-R\fR
-Generate a RSA key.
+Generate an RSA key.
.TP
\fB-D\fR
Generate a DSA key.
+.TP
+\fB-D\fR
+Generate an HMAC-MD5 key.
+
.TP
\fB-k\fR
When given generate a key signing key. This just sets the flag field to
.TP
\fb-r \fIdevice\fR
-Make ldns-keygen use this file for its random data. This will default
-to /dev/random.
+Make ldns-keygen use this file to seed the random generator with. This will
+default to /dev/random.
.TP
\fb-v\fR
fprintf(fp, "%s [-D|-R] [-b bits] [-r /dev/random] [-v] domain\n", prog);
fprintf(fp, " generate a new key pair for domain\n");
fprintf(fp, " -D\tgenerate a DSA key\n");
- fprintf(fp, " -R\tgenerate a RSA key\n");
+ fprintf(fp, " -R\tgenerate an RSA key\n");
+ fprintf(fp, " -H\tgenerate an HMAC-MD5 key (for TSIG)\n");
fprintf(fp, " -k\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\n");
+ fprintf(fp, " K<name>+<alg>+<id>.ds\tDS in RR format (only for DNSSEC keys)\n");
fprintf(fp, " The base name (K<name>+<alg>+<id> will be printed to stdout\n");
}
random = NULL;
ksk = false; /* don't create a ksk per default */
- while ((c = getopt(argc, argv, "DRkb:r:v")) != -1) {
+ while ((c = getopt(argc, argv, "DRHkb:r:v")) != -1) {
switch (c) {
case 'D':
if (algorithm != 0) {
- fprintf(stderr, "%s: %s", prog, "Only one -D or -A is allowed\n");
+ fprintf(stderr, "%s: %s", prog, "Only one of -D, -A or -H is allowed\n");
exit(EXIT_FAILURE);
}
algorithm = LDNS_SIGN_DSA;
break;
case 'R':
if (algorithm != 0) {
- fprintf(stderr, "%s: %s", prog, "Only one -D or -A is allowed\n");
+ fprintf(stderr, "%s: %s", prog, "Only one of -D, -A or -H is allowed\n");
exit(EXIT_FAILURE);
}
algorithm = LDNS_SIGN_RSASHA1;
break;
+ case 'H':
+ if (algorithm != 0) {
+ fprintf(stderr, "%s: %s", prog, "Only one of -D, -A or -H is allowed\n");
+ }
+ algorithm = LDNS_SIGN_HMACMD5;
+ break;
case 'b':
bits = (uint16_t) atoi(optarg);
if (bits == 0) {
exit(EXIT_FAILURE);
}
free(prog);
-
- (void)ldns_init_random(random, def_bits * 8 * 2); /* I hope this is enough? */
- if (random) {
- fclose(random);
+
+ 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);
+ fclose(random);
+
/* create an rdf from the domain name */
domain = ldns_dname_new_frm_str(argv[0]);
}
/* print the DS to .ds */
- 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 {
- ldns_rr_print(file, ds);
- fclose(file);
- LDNS_FREE(filename);
- }
-
+ if (algorithm != LDNS_SIGN_HMACMD5) {
+ 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 {
+ ldns_rr_print(file, ds);
+ fclose(file);
+ LDNS_FREE(filename);
+ }
+ }
#if 0
/* TEMP: create PEM format too */
filename = LDNS_XMALLOC(char, strlen(owner) + 17);
break;
case LDNS_SIGN_HMACMD5:
/* is the filefmt specified for TSIG.. don't know */
- goto error;
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: 157 (HMAC_MD5)\n");
+ ldns_buffer_printf(output, "Key: ");
+ i = ldns_key_hmac_size(k);
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, ldns_key_hmac_key(k));
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ break;
}
#endif /* HAVE_SSL */
} else {
ldns_rr *key_rr;
RSA *rsa;
DSA *dsa;
+ unsigned char *hmac;
+ size_t hmac_size;
k = ldns_key_new();
}
if (strncmp(d, "1 RSA", 2) == 0) {
- alg = LDNS_SIGN_RSAMD5; /* md5, really?? */
+ alg = LDNS_SIGN_RSAMD5;
}
if (strncmp(d, "3 DSA", 2) == 0) {
alg = LDNS_SIGN_DSA;
if (strncmp(d, "133 RSASHA1", 4) == 0) {
alg = LDNS_RSASHA1_NSEC3;
}
+ if (strncmp(d, "157 HMAC-MD5", 4) == 0) {
+ alg = LDNS_SIGN_HMACMD5;
+ }
LDNS_FREE(d);
switch(alg) {
- case 0:
- default:
- return LDNS_STATUS_SYNTAX_ALG_ERR;
case LDNS_SIGN_RSAMD5:
case LDNS_SIGN_RSASHA1:
case LDNS_RSASHA1_NSEC3:
ldns_key_set_dsa_key(k, dsa);
DSA_free(dsa);
break;
+ case LDNS_SIGN_HMACMD5:
+ ldns_key_set_algorithm(k, alg);
+ hmac = ldns_key_new_frm_fp_hmac_l(fp, line_nr, &hmac_size);
+ ldns_key_set_hmac_size(k, hmac_size);
+ ldns_key_set_hmac_key(k, hmac);
+ break;
+ case 0:
+ default:
+ return LDNS_STATUS_SYNTAX_ALG_ERR;
+ break;
}
key_rr = ldns_key2rr(k);
return NULL;
}
+unsigned char *
+ldns_key_new_frm_fp_hmac(FILE *f, size_t *hmac_size)
+{
+ return ldns_key_new_frm_fp_hmac_l(f, NULL, hmac_size);
+}
+
+unsigned char *
+ldns_key_new_frm_fp_hmac_l(FILE *f, int *line_nr, size_t *hmac_size)
+{
+ int i;
+ char *d;
+ unsigned char *buf;
+
+ line_nr = line_nr;
+
+ d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN);
+ buf = LDNS_XMALLOC(unsigned char, LDNS_MAX_LINELEN);
+
+ if (ldns_fget_keyword_data_l(f, "Key", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = b64_pton((const char*)d, buf, b64_ntop_calculate_size(strlen(d)));
+
+ *hmac_size = i;
+ return buf;
+
+ error:
+ LDNS_FREE(d);
+ LDNS_FREE(buf);
+ *hmac_size = 0;
+ return NULL;
+}
+
+
ldns_key *
ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
{
ldns_key *k;
DSA *d;
RSA *r;
+ int i;
+ uint16_t offset;
+ unsigned char *hmac;
k = ldns_key_new();
if (!k) {
ldns_key_set_dsa_key(k, d);
break;
case LDNS_SIGN_HMACMD5:
- /* do your hmac thing here */
+ k->_key.key = NULL;
+ size = size / 8;
+ ldns_key_set_hmac_size(k, size);
+
+ hmac = LDNS_XMALLOC(unsigned char, size);
+ offset = 0;
+ while (offset + sizeof(i) < size) {
+ i = rand();
+ memcpy(&hmac[offset], &i, sizeof(i));
+ offset += sizeof(i);
+ }
+ if (offset < size) {
+ i = rand();
+ memcpy(&hmac[offset], &i, size - offset);
+ }
+
+ ldns_key_set_hmac_key(k, hmac);
+
+ ldns_key_set_flags(k, 0);
break;
}
ldns_key_set_algorithm(k, alg);
void
ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac)
{
- k->_key.hmac = hmac;
+ k->_key.hmac.key = hmac;
+}
+
+void
+ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size)
+{
+ k->_key.hmac.size = hmac_size;
}
void
unsigned char *
ldns_key_hmac_key(const ldns_key *k)
{
- return k->_key.hmac;
+ return k->_key.hmac.key;
+}
+
+size_t
+ldns_key_hmac_size(const ldns_key *k)
+{
+ return k->_key.hmac.size;
}
uint32_t
return NULL;
}
- ldns_rr_set_type(pubkey, LDNS_RR_TYPE_DNSKEY);
+ switch (ldns_key_algorithm(k)) {
+ case LDNS_SIGN_HMACMD5:
+ ldns_rr_set_type(pubkey, LDNS_RR_TYPE_KEY);
+ break;
+ default:
+ ldns_rr_set_type(pubkey, LDNS_RR_TYPE_DNSKEY);
+ break;
+ }
/* zero-th rdf - flags */
ldns_rr_push_rdf(pubkey,
ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
break;
case LDNS_SIGN_HMACMD5:
/* tja */
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_SIGN_HMACMD5));
+ size = ldns_key_hmac_size(k);
+ bin = LDNS_XREALLOC(bin, unsigned char, size);
+ memcpy(bin, ldns_key_hmac_key(k), size);
break;
}
/* fourth the key bin material */
/* MIEK, not sure about this +1. I've re-added it--needs checking */
- keybin = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, size + 1, bin);
+ /* TODO: and i've removed it again, it's certainly wrong for HMAC */
+ keybin = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, size, bin);
LDNS_FREE(bin);
ldns_rr_push_rdf(pubkey, keybin);
return pubkey;
if (ldns_key_evp_key(key)) {
EVP_PKEY_free(ldns_key_evp_key(key));
}
+ if (ldns_key_hmac_key(key)) {
+ free(ldns_key_hmac_key(key));
+ }
LDNS_FREE(key);
}
ldns_zone *ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
/**
- * Initialize the random function. This calls OpenSSL
- * \param[in] fd a file providing entropy data
+ * Initialize the random function. This calls the OpenSSL srand() function
+ * If the file descriptor is specified, the random generator is seeded with
+ * data from that file. If not, /dev/urandom is used.
+ * \param[in] fd a file providing entropy data for the seed
* \param[in] bytes number of bytes for the seed
* \return LDNS_STATUS_OK if init succeeds
*/
-ldns_status ldns_init_random(FILE *fd, uint16_t bytes);
+ldns_status ldns_init_random(FILE *fd);
/**
* Tries to build an authentication chain from the given keys down to the queried domain.
LDNS_SIGN_DSA = LDNS_DSA,
LDNS_SIGN_RSASHA1_NSEC3 = LDNS_RSASHA1_NSEC3,
LDNS_SIGN_DSA_NSEC3 = LDNS_DSA_NSEC3,
- LDNS_SIGN_HMACMD5 = 150 /* not official! */
+ LDNS_SIGN_HMACMD5 = 157 /* not official! This type is for TSIG, not DNSSEC */
};
typedef enum ldns_enum_signing_algorithm ldns_signing_algorithm;
ldns_signing_algorithm _alg;
/** Storage pointers for the types of keys supported */
/* TODO remove unions? */
- union {
+ struct {
#ifdef HAVE_SSL
#ifndef S_SPLINT_S
EVP_PKEY *key;
#endif
#endif /* HAVE_SSL */
- unsigned char *hmac;
+ struct {
+ unsigned char *key;
+ size_t size;
+ } hmac;
} _key;
/** Depending on the key we can have extra data */
union {
/**
- * frm_fp helper function. This function parsed the
+ * frm_fp helper function. This function parses the
* remainder of the (RSA) priv. key file generated from bind9
* \param[in] fp the file to parse
* \return NULL on failure otherwise a RSA structure
#ifdef HAVE_SSL
/**
- * frm_fp helper function. This function parsed the
+ * frm_fp helper function. This function parses the
* remainder of the (RSA) priv. key file generated from bind9
* \param[in] fp the file to parse
* \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
#ifdef HAVE_SSL
/**
- * frm_fp helper function. This function parsed the
- * remainder of the (DSA) priv. key file generated from bind9
+ * frm_fp helper function. This function parses the
+ * remainder of the (DSA) priv. key file
* \param[in] fp the file to parse
* \return NULL on failure otherwise a RSA structure
*/
#ifdef HAVE_SSL
/**
- * frm_fp helper function. This function parsed the
- * remainder of the (DSA) priv. key file generated from bind9
+ * frm_fp helper function. This function parses the
+ * remainder of the (DSA) priv. key file
* \param[in] fp the file to parse
* \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
* \return NULL on failure otherwise a RSA structure
DSA *ldns_key_new_frm_fp_dsa_l(FILE *fp, int *line_nr);
#endif /* HAVE_SSL */
+#ifdef HAVE_SSL
+/**
+ * frm_fp helper function. This function parses the
+ * remainder of the (HMAC-MD5) key file
+ * This function allocated a buffer that needs to be freed
+ * \param[in] fp the file to parse
+ * \param[out] hmac_size the number of bits in the resulting buffer
+ * \return NULL on failure otherwise a newly allocated char buffer
+ */
+unsigned char *ldns_key_new_frm_fp_hmac(FILE *fp, size_t *hmac_size);
+#endif
+
+#ifdef HAVE_SSL
+/**
+ * frm_fp helper function. This function parses the
+ * remainder of the (HMAC-MD5) key file
+ * This function allocated a buffer that needs to be freed
+ * \param[in] fp the file to parse
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \param[out] hmac_size the number of bits in the resulting buffer
+ * \return NULL on failure otherwise a newly allocated char buffer
+ */
+unsigned char *ldns_key_new_frm_fp_hmac_l(FILE *fp, int *line_nr, size_t *hmac_size);
+#endif /* HAVE_SSL */
+
/* acces write functions */
/**
* Set the key's algorithm
/**
* Set the key's hmac data
* \param[in] k the key
- * \param[in] hmac the hmac data
+ * \param[in] hmac_size in nr of bytes
*/
void ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac);
+/**
+ * Set the key's hmac size
+ * \param[in] k the key
+ * \param[in] hmac the hmac data
+ */
+void ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size);
/**
* Set the key's original ttl
* \param[in] k the key
* \return the hmac key
*/
unsigned char *ldns_key_hmac_key(const ldns_key *k);
+/**
+ * return the hmac key size
+ * \param[in] k the key size
+ * \return the hmac key size
+ */
+size_t ldns_key_hmac_size(const ldns_key *k);
/**
* return the original ttl of the key
* \param[in] k the key