200 lines
4.6 KiB
C
200 lines
4.6 KiB
C
/*
|
|
* key2ds transforms a public key into its DS
|
|
* It (currently) prints out the public key
|
|
*
|
|
* (c) NLnet Labs, 2005 - 2008
|
|
* See the file LICENSE for the license
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <ldns/ldns.h>
|
|
|
|
#include <errno.h>
|
|
|
|
static void
|
|
usage(FILE *fp, char *prog) {
|
|
fprintf(fp, "%s [-fn] [-1|-2] keyfile\n", prog);
|
|
fprintf(fp, " Generate a DS RR from the DNSKEYS in keyfile\n");
|
|
fprintf(fp, " The following file will be created: ");
|
|
fprintf(fp, "K<name>+<alg>+<id>.ds\n");
|
|
fprintf(fp, " The base name (K<name>+<alg>+<id> will be printed to stdout\n");
|
|
fprintf(fp, "Options:\n");
|
|
fprintf(fp, " -f: ignore SEP flag (i.e. make DS records for any key)\n");
|
|
fprintf(fp, " -n: do not write DS records to file(s) but to stdout\n");
|
|
fprintf(fp, " (default) use similar hash to the key algorithm.\n");
|
|
fprintf(fp, " -1: use SHA1 for the DS hash\n");
|
|
fprintf(fp, " -2: use SHA256 for the DS hash\n");
|
|
#ifdef USE_GOST
|
|
fprintf(fp, " -g: use GOST for the DS hash\n");
|
|
#endif
|
|
#ifdef USE_ECDSA
|
|
fprintf(fp, " -4: use SHA384 for the DS hash\n");
|
|
#endif
|
|
}
|
|
|
|
static int
|
|
is_suitable_dnskey(ldns_rr *rr, int sep_only)
|
|
{
|
|
if (!rr || ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) {
|
|
return 0;
|
|
}
|
|
return !sep_only ||
|
|
(ldns_rdf2native_int16(ldns_rr_dnskey_flags(rr)) &
|
|
LDNS_KEY_SEP_KEY);
|
|
}
|
|
|
|
static ldns_hash
|
|
suitable_hash(ldns_signing_algorithm algorithm)
|
|
{
|
|
switch (algorithm) {
|
|
case LDNS_SIGN_RSASHA256:
|
|
case LDNS_SIGN_RSASHA512:
|
|
return LDNS_SHA256;
|
|
case LDNS_SIGN_ECC_GOST:
|
|
#ifdef USE_GOST
|
|
return LDNS_HASH_GOST;
|
|
#else
|
|
return LDNS_SHA256;
|
|
#endif
|
|
#ifdef USE_ECDSA
|
|
case LDNS_SIGN_ECDSAP256SHA256:
|
|
return LDNS_SHA256;
|
|
case LDNS_SIGN_ECDSAP384SHA384:
|
|
return LDNS_SHA384;
|
|
#endif
|
|
default:
|
|
return LDNS_SHA1;
|
|
}
|
|
return LDNS_SHA1;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
FILE *keyfp, *dsfp;
|
|
char *keyname;
|
|
char *dsname;
|
|
char *owner;
|
|
ldns_rr *k, *ds;
|
|
ldns_signing_algorithm alg;
|
|
ldns_hash h;
|
|
int similar_hash=1;
|
|
char *program = argv[0];
|
|
int nofile = 0;
|
|
ldns_rdf *origin = NULL;
|
|
ldns_status result = LDNS_STATUS_OK;
|
|
int sep_only = 1;
|
|
|
|
alg = 0;
|
|
h = LDNS_SHA1;
|
|
|
|
argv++, argc--;
|
|
while (argc && argv[0][0] == '-') {
|
|
if (strcmp(argv[0], "-1") == 0) {
|
|
h = LDNS_SHA1;
|
|
similar_hash = 0;
|
|
}
|
|
if (strcmp(argv[0], "-2") == 0) {
|
|
h = LDNS_SHA256;
|
|
similar_hash = 0;
|
|
}
|
|
#ifdef USE_GOST
|
|
if (strcmp(argv[0], "-g") == 0) {
|
|
if(!ldns_key_EVP_load_gost_id()) {
|
|
fprintf(stderr, "error: libcrypto does not provide GOST\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
h = LDNS_HASH_GOST;
|
|
similar_hash = 0;
|
|
}
|
|
#endif
|
|
#ifdef USE_ECDSA
|
|
if (strcmp(argv[0], "-4") == 0) {
|
|
h = LDNS_SHA384;
|
|
similar_hash = 0;
|
|
}
|
|
#endif
|
|
if (strcmp(argv[0], "-f") == 0) {
|
|
sep_only = 0;
|
|
}
|
|
if (strcmp(argv[0], "-n") == 0) {
|
|
nofile=1;
|
|
}
|
|
argv++, argc--;
|
|
}
|
|
|
|
if (argc != 1) {
|
|
usage(stderr, program);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
keyname = strdup(argv[0]);
|
|
|
|
keyfp = fopen(keyname, "r");
|
|
if (!keyfp) {
|
|
fprintf(stderr, "Failed to open public key file %s: %s\n", keyname,
|
|
strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while (result == LDNS_STATUS_OK) {
|
|
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
|
while (result == LDNS_STATUS_SYNTAX_ORIGIN ||
|
|
result == LDNS_STATUS_SYNTAX_TTL ||
|
|
(result == LDNS_STATUS_OK && !is_suitable_dnskey(k, sep_only))
|
|
) {
|
|
if (result == LDNS_STATUS_OK) {
|
|
ldns_rr_free(k);
|
|
}
|
|
result = ldns_rr_new_frm_fp(&k, keyfp, 0, &origin, NULL);
|
|
}
|
|
if (result == LDNS_STATUS_SYNTAX_EMPTY) {
|
|
/* we're done */
|
|
break;
|
|
}
|
|
if (result != LDNS_STATUS_OK) {
|
|
fprintf(stderr, "Could not read public key from file %s: %s\n", keyname, ldns_get_errorstr_by_id(result));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
owner = ldns_rdf2str(ldns_rr_owner(k));
|
|
alg = ldns_rdf2native_int8(ldns_rr_dnskey_algorithm(k));
|
|
if(similar_hash)
|
|
h = suitable_hash(alg);
|
|
|
|
ds = ldns_key_rr2ds(k, h);
|
|
if (!ds) {
|
|
fprintf(stderr, "Conversion to a DS RR failed\n");
|
|
ldns_rr_free(k);
|
|
free(owner);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* print the public key RR to .key */
|
|
dsname = LDNS_XMALLOC(char, strlen(owner) + 16);
|
|
snprintf(dsname, strlen(owner) + 15, "K%s+%03u+%05u.ds", owner, alg, (unsigned int) ldns_calc_keytag(k));
|
|
|
|
if (nofile)
|
|
ldns_rr_print(stdout,ds);
|
|
else {
|
|
dsfp = fopen(dsname, "w");
|
|
if (!dsfp) {
|
|
fprintf(stderr, "Unable to open %s: %s\n", dsname, strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
} else {
|
|
ldns_rr_print(dsfp, ds);
|
|
fclose(dsfp);
|
|
fprintf(stdout, "K%s+%03u+%05u\n", owner, alg, (unsigned int) ldns_calc_keytag(k));
|
|
}
|
|
}
|
|
|
|
ldns_rr_free(ds);
|
|
ldns_rr_free(k);
|
|
free(owner);
|
|
LDNS_FREE(dsname);
|
|
}
|
|
fclose(keyfp);
|
|
free(keyname);
|
|
exit(EXIT_SUCCESS);
|
|
}
|