From 6197fe64852c19670e10451d29566a4035069930 Mon Sep 17 00:00:00 2001 From: Federico Lucifredi Date: Mon, 21 Jan 2008 05:32:35 +0000 Subject: added RSA-SHA1 signature path. git-svn-id: file:///home/lennart/svn/public/avahi/branches/federico2@1736 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/dns.c | 101 +++++++++++++++++++++++++++++++++++++++++------ avahi-core/dns.h | 4 +- avahi-core/domain-util.c | 29 +++++++++++--- avahi-core/domain-util.h | 6 +++ 4 files changed, 122 insertions(+), 18 deletions(-) diff --git a/avahi-core/dns.c b/avahi-core/dns.c index 3b88a20..61f094b 100644 --- a/avahi-core/dns.c +++ b/avahi-core/dns.c @@ -907,12 +907,13 @@ size_t avahi_rdata_serialize(AvahiRecord *record, void *rdata, size_t max_size) } /* TODO: should this be located in this file? */ -/* r = avahi_get_local_zsk_pubkey("riker.local", ) */ -AvahiRecord* avahi_get_local_zsk_pubkey(const unsigned char* keyname, uint32_t ttl){ +/* r = avahi_get_local_zsk_pubkey() */ +AvahiRecord* avahi_get_local_zsk_pubkey(uint32_t ttl){ AvahiRecord *r; - r = avahi_record_new_full(keyname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_DNSKEY, 0); + /* TODO: in merged version into upstream, authority needs to be an external configurable pulled from config file */ + r = avahi_record_new_full("riker.local", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_DNSKEY, 0); if (!r) { /* OOM check */ avahi_log_error("avahi_record_new_full() failed."); @@ -925,7 +926,7 @@ AvahiRecord* avahi_get_local_zsk_pubkey(const unsigned char* keyname, uint32_t t r->data.dnskey.protocol = AVAHI_DNSSEC_PROTO; /* used for "compatibility" with KEY record */ - /* TODO: in merged version into upstream, key needs to be an external configurable pulled from /etc */ + /* TODO: in merged version into upstream, key, algorithm need to be external configurables pulled from config file */ /* in the prototype, we just statically configure */ r->data.dnskey.algorithm = AVAHI_DNSSEC_KEY_SHA1; /* SHA1 is mandatory in the spec, but others do exist */ @@ -938,13 +939,21 @@ AvahiRecord* avahi_get_local_zsk_pubkey(const unsigned char* keyname, uint32_t t return r; } -/* invoke as avahi_dnssec_sign_record(, "reiker.local", ) */ -AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, const char *authority, uint32_t ttl){ +/* invoke as avahi_dnssec_sign_record(, ) */ +AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, uint32_t ttl){ AvahiRecord *r; AvahiRecord *key; int result; + char *canonic; /*used in conversions */ + AvahiDNSPacket *tmp; + + unsigned char signature[EVP_MAX_MD_SIZE]; /*used for signing */ + HMAC_CTX ctx; + unsigned signature_length; + + r = avahi_record_new_full(keyname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_RRSIG, 0); if (!r) { /* OOM check */ @@ -953,7 +962,7 @@ AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, const char *authority, uint } /* type of covered record */ - r->data.rrsig.type_covered = s->key.clazz; + r->data.rrsig.type_covered = s->key.type; /* SHA1 is mandatory in the spec (MUST), but other options are available */ r->data.rrsig.algorithm = AVAHI_DNSSEC_KEY_SHA1; @@ -971,15 +980,85 @@ AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, const char *authority, uint r->data.rrsig.signature_inception = time(NULL) - AVAHI_DNSSEC_TIME_DRIFT; /* retrieve RRSIG record representing localhost's trust */ - key = avahi_get_local_zsk_pubkey(authority, ttl); + key = avahi_get_local_zsk_pubkey(ttl); - /* generate keytag of the localhos's pubkey */ + /* generate keytag of the localhost's pubkey */ r->data.rrsig.keytag = avahi_keytag(key); + /* +".local", to be retrieved from future *private* crypto config file along with local ZSK keypair */ + r->data.rrsig.signers_name = avahi_strdup (key->key->name); + avahi_free(key); - /* +".local", to be retrieved from future *private* crypto config file along with local ZSK keypair */ - r->data.rrsig.signers_name = avahi_strdup (authority); + /* now the signature proper */ + + switch (r->data.dnskey.algorithm){ + + case AVAHI_DNSSEC_KEY_SHA1 : EVP_SigInit(&ctx, EVP_sha1()); + break; /* RSA SHA1 is only mandatory in the spec, others exist */ + + default: avahi_log_error("Unknown algorithm requested from avahi_dnssec_sign_record()"); + return NULL; + } + + /* generate HASH for signing */ + + /*from the RRSIG itself first */ + + /* type of RR covered by signature */ + EVP_SignUpdate(&ctx, avahi_uint16_to_canonical_string(r->data.rrsig.type_covered), 2); + + /* algorithm */ + EVP_SignUpdate(&ctx, &r->data.rrsig.algorithm, 1); + + /* labels count */ + EVP_SignUpdate(&ctx, &r->data.rrsig.labels, 1); + + /* original TTL */ + EVP_SignUpdate(&ctx, avahi_uint32_to_canonical_string(r->data.rrsig.original_ttl), 4); + + /* signature expiration */ + EVP_SignUpdate(&ctx, avahi_uint32_to_canonical_string(r->data.rrsig.signature_expiration), 4); + + /* signature inception */ + EVP_SignUpdate(&ctx, avahi_uint32_to_canonical_string(r->data.rrsig.signature_inception), 4); + + /* type of RR covered by signature */ + EVP_SignUpdate(&ctx, avahi_uint16_to_canonical_string(r->data.rrsig.key_tag), 2); + + /* authority */ + canonic = avahi_c_to_canonical_string(r->data->signers_name); /* signer's name in canonical wire format (DNS labels) */ + EVP_SignUpdate(&ctx, canonic, strlen(canonic) +1); + + /* now the DNS record that we are signing, complete and in wire format */ + tmp = avahi_dns_packet_new_query(0); /* MTU */ + + if (!tmp) { /*OOM check */ + avahi_log_error("avahi_dns_packet_new_query() failed."); + assert(tmp); + } + + /* no TTL binding, leave record unaltered */ + result = avahi_dns_packet_append_record(tmp, s, 0, 0); + + if (!result) { + avahi_log_error("appending of rdata failed."); + assert(result); + } + + /* update RRSET we modified - RRSET is arbitrary in this case */ + avahi_dns_packet_set_field(tmp, AVAHI_DNS_FIELD_ARCOUNT, 1); + + /* now select the right chunk of the packet to get the wire format of the record's RDATA */ + EVP_SignUpdate(&ctx, AVAHI_DNS_PACKET_DATA(tmp) + AVAHI_DNS_PACKET_HEADER_SIZE, tmp->size - AVAHI_DNS_PACKET_HEADER_SIZE); + + /* now get the signature of the secure hash we just generated*/ + EVP_SignFinal(&ctx, signature, &signature_length, private_key); + + avahi_free(tmp); + + /*finally, add the signature to the record */ + r->data.rrsig.signature = avahi_strndup(signature, signature_length); return r; } diff --git a/avahi-core/dns.h b/avahi-core/dns.h index 01c92aa..baabc8a 100644 --- a/avahi-core/dns.h +++ b/avahi-core/dns.h @@ -79,8 +79,8 @@ int avahi_dns_packet_skip(AvahiDnsPacket *p, size_t length); int avahi_dns_packet_is_empty(AvahiDnsPacket *p); size_t avahi_dns_packet_space(AvahiDnsPacket *p); -AvahiRecord* avahi_get_local_zsk_pubkey(const unsigned char* keyname, uint32_t ttl); -AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, const char *authority, uint32_t ttl); +AvahiRecord* avahi_get_local_zsk_pubkey(uint32_t ttl); +AvahiRecord avahi_dnssec_sign_record(AvahiRecord *s, uint32_t ttl); AvahiRecord* avahi_get_local_trust_record(); diff --git a/avahi-core/domain-util.c b/avahi-core/domain-util.c index f4bcdc0..07d1fb1 100644 --- a/avahi-core/domain-util.c +++ b/avahi-core/domain-util.c @@ -224,6 +224,25 @@ unsigned char * avahi_c_to_canonical_string(const char* input) return retval; } +unsigned char * avahi_uint16_to_canonical_string(uint16_t v) { + uint8_t *c = avahi_malloc(2); + + c[0] = (uint8_t) (v >> 8); + c[1] = (uint8_t) v; + return c; +} + +unsigned char * avahi_uint32_to_canonical_string(uint32_t v) { + uint8_t *c = avahi_malloc(4); + + c[0] = (uint8_t) (v >> 24); + c[1] = (uint8_t) (v >> 16); + c[2] = (uint8_t) (v >> 8); + c[3] = (uint8_t) v; + + return c; +} + uint8_t avahi_count_canonical_labels(const char* input){ char *p; uint8_t count; @@ -261,11 +280,11 @@ uint16_t avahi_keytag(AvahiRecord r){ if (r->key.type != AVAHI_DNS_TYPE_RRSIG) return NULL; /* invalid RRTYPE to generate keytag on */ - p = avahi_dns_packet_new_query(0); /* MTU */ + tmp = avahi_dns_packet_new_query(0); /* MTU */ - if (!p) { /*OOM check */ - avahi_log_error("avahi_dns_packet_new_update() failed."); - assert(p); + if (!tmp) { /*OOM check */ + avahi_log_error("avahi_dns_packet_new_query() failed."); + assert(tmp); } /* no TTL binding, leave record unaltered */ @@ -277,7 +296,7 @@ uint16_t avahi_keytag(AvahiRecord r){ } /* update RRSET we modified */ - avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ARCOUNT, 1); + avahi_dns_packet_set_field(tmp, AVAHI_DNS_FIELD_ARCOUNT, 1); /* finally, generate keytag */ /* first arg is rdata address, second arg is rdlength */ diff --git a/avahi-core/domain-util.h b/avahi-core/domain-util.h index 1e71426..1fdb4f0 100644 --- a/avahi-core/domain-util.h +++ b/avahi-core/domain-util.h @@ -45,6 +45,12 @@ int avahi_domain_ends_with(const char *domain, const char *suffix); /** returns canonical DNS representation of C string representing a domain */ unsigned char * avahi_c_to_canonical_string(const char* input); +/** returns canonical wire representation of uint16 */ +unsigned char * avahi_uint16_to_canonical_string(uint16_t v); + +/** returns canonical wire representation of uint32 */ +unsigned char * avahi_uint32_to_canonical_string(uint32_t v); + /** returns the number of labels in a canonical DNS domain */ uint8_t avahi_count_canonical_labels(const char* input); -- cgit