From: W.C.A. Wijngaards Date: Fri, 9 Oct 2020 09:19:31 +0000 (+0200) Subject: zonemd, digest code calls, secalgo openssl sha384 and sha512. X-Git-Tag: release-1.13.2rc1~269^2~71 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb4932a463f594732fd2e91285300b85e97463b1;p=thirdparty%2Funbound.git zonemd, digest code calls, secalgo openssl sha384 and sha512. --- diff --git a/services/authzone.c b/services/authzone.c index b4217bd55..208c0b825 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -6983,19 +6983,79 @@ static int zonemd_scheme_supported(int scheme) } /** initialize hash for hashing with zonemd hash algo */ -static void* zonemd_digest_init(int hashalgo) +static struct secalgo_hash* zonemd_digest_init(int hashalgo, char** reason) { + struct secalgo_hash *h; if(hashalgo == 1) { /* sha384 */ - //return secalgo_digest_start_sha384(); + h = secalgo_hash_create_sha384(); + if(!h) + *reason = "digest sha384 could not be created"; + return h; } else if(hashalgo == 2) { /* sha512 */ - //return secalgo_digest_start_sha512(); + h = secalgo_hash_create_sha512(); + if(!h) + *reason = "digest sha512 could not be created"; + return h; } /* unknown hash algo */ + *reason = "unsupported algorithm"; return NULL; } +/** update the hash for zonemd */ +static int zonemd_digest_update(int hashalgo, struct secalgo_hash* h, + uint8_t* data, size_t len, char** reason) +{ + if(hashalgo == 1) { + if(!secalgo_hash_update(h, data, len)) { + *reason = "digest sha384 failed"; + return 0; + } + return 1; + } else if(hashalgo == 2) { + if(!secalgo_hash_update(h, data, len)) { + *reason = "digest sha512 failed"; + return 0; + } + return 1; + } + /* unknown hash algo */ + *reason = "unsupported algorithm"; + return 0; +} + +/** finish the hash for zonemd */ +static int zonemd_digest_finish(int hashalgo, struct secalgo_hash* h, + uint8_t* result, size_t hashlen, size_t* resultlen, char** reason) +{ + if(hashalgo == 1) { + if(hashlen < 384/8) { + *reason = "digest buffer too small for sha384"; + return 0; + } + if(!secalgo_hash_final(h, result, hashlen, resultlen)) { + *reason = "digest sha384 finish failed"; + return 0; + } + return 1; + } else if(hashalgo == 2) { + if(hashlen < 512/8) { + *reason = "digest buffer too small for sha512"; + return 0; + } + if(!secalgo_hash_final(h, result, hashlen, resultlen)) { + *reason = "digest sha512 finish failed"; + return 0; + } + return 1; + } + /* unknown algo */ + *reason = "unsupported algorithm"; + return 0; +} + /** add rrsets from node to the list */ static size_t authdata_rrsets_to_list(struct auth_rrset** array, size_t arraysize, struct auth_rrset* first) @@ -7043,9 +7103,10 @@ static void addrrsigtype_if_needed(struct auth_rrset** array, } /** collate the RRs in an RRset using the simple scheme */ -static int zonemd_simple_rrset(struct auth_zone* z, void* hash, - struct auth_data* node, struct auth_rrset* rrset, - struct regional* region, struct sldns_buffer* buf, char** reason) +static int zonemd_simple_rrset(struct auth_zone* z, int hashalgo, + struct secalgo_hash* h, struct auth_data* node, + struct auth_rrset* rrset, struct regional* region, + struct sldns_buffer* buf, char** reason) { /* canonicalize */ struct ub_packed_rrset_key key; @@ -7063,6 +7124,10 @@ static int zonemd_simple_rrset(struct auth_zone* z, void* hash, regional_free_all(region); /* hash */ + if(!zonemd_digest_update(hashalgo, h, sldns_buffer_begin(buf), + sldns_buffer_limit(buf), reason)) { + return 0; + } return 1; } @@ -7168,10 +7233,10 @@ static void add_rrset_into_data(struct packed_rrset_data* data, } /** collate the RRSIGs using the simple scheme */ -static int zonemd_simple_rrsig(struct auth_zone* z, void* hash, - struct auth_data* node, struct auth_rrset* rrset, - struct auth_rrset** rrlist, size_t rrnum, struct regional* region, - struct sldns_buffer* buf, char** reason) +static int zonemd_simple_rrsig(struct auth_zone* z, int hashalgo, + struct secalgo_hash* h, struct auth_data* node, + struct auth_rrset* rrset, struct auth_rrset** rrlist, size_t rrnum, + struct regional* region, struct sldns_buffer* buf, char** reason) { /* the rrset pointer can be NULL, this means it is type RRSIG and * there is no ordinary type RRSIG there. The RRSIGs are stored @@ -7194,7 +7259,7 @@ static int zonemd_simple_rrsig(struct auth_zone* z, void* hash, key.entry.data = &data; key.rk.dname = node->name; key.rk.dname_len = node->namelen; - key.rk.type = htons(rrset->type); + key.rk.type = htons(LDNS_RR_TYPE_RRSIG); key.rk.rrset_class = htons(z->dclass); data.count = zonemd_simple_count_rrsig(rrset, rrlist, rrnum, z, node); if(!zonemd_simple_rrsig_allocs(region, &data, data.count)) { @@ -7216,13 +7281,17 @@ static int zonemd_simple_rrsig(struct auth_zone* z, void* hash, regional_free_all(region); /* hash */ + if(!zonemd_digest_update(hashalgo, h, sldns_buffer_begin(buf), + sldns_buffer_limit(buf), reason)) { + return 0; + } return 1; } /** collate a domain's rrsets using the simple scheme */ -static int zonemd_simple_domain(struct auth_zone* z, void* hash, - struct auth_data* node, struct regional* region, - struct sldns_buffer* buf, char** reason) +static int zonemd_simple_domain(struct auth_zone* z, int hashalgo, + struct secalgo_hash* h, struct auth_data* node, + struct regional* region, struct sldns_buffer* buf, char** reason) { const size_t rrlistsize = 65536; struct auth_rrset* rrlist[rrlistsize]; @@ -7243,11 +7312,11 @@ static int zonemd_simple_domain(struct auth_zone* z, void* hash, } if(rrlist[i] == NULL || rrlist[i]->type == LDNS_RR_TYPE_RRSIG) { - if(!zonemd_simple_rrsig(z, hash, node, rrlist[i], - rrlist, rrnum, region, buf, reason)) + if(!zonemd_simple_rrsig(z, hashalgo, h, node, + rrlist[i], rrlist, rrnum, region, buf, reason)) return 0; - } else if(!zonemd_simple_rrset(z, hash, node, rrlist[i], - region, buf, reason)) { + } else if(!zonemd_simple_rrset(z, hashalgo, h, node, + rrlist[i], region, buf, reason)) { return 0; } } @@ -7255,14 +7324,16 @@ static int zonemd_simple_domain(struct auth_zone* z, void* hash, } /** collate the zone using the simple scheme */ -static int zonemd_simple_collate(struct auth_zone* z, void* hash, - struct regional* region, struct sldns_buffer* buf, char** reason) +static int zonemd_simple_collate(struct auth_zone* z, int hashalgo, + struct secalgo_hash* h, struct regional* region, + struct sldns_buffer* buf, char** reason) { /* our tree is sorted in canonical order, so we can just loop over * the tree */ struct auth_data* n; RBTREE_FOR(n, struct auth_data*, &z->data) { - if(!zonemd_simple_domain(z, hash, n, region, buf, reason)) + if(!zonemd_simple_domain(z, hashalgo, h, n, region, buf, + reason)) return 0; } return 1; @@ -7272,23 +7343,26 @@ int auth_zone_generate_zonemd_hash(struct auth_zone* z, int scheme, int hashalgo, uint8_t* hash, size_t hashlen, size_t* resultlen, struct regional* region, struct sldns_buffer* buf, char** reason) { - void* h = zonemd_digest_init(hashalgo); + struct secalgo_hash* h = zonemd_digest_init(hashalgo, reason); if(!h) { - *reason = "digest init fail"; + if(!*reason) + *reason = "digest init fail"; return 0; } if(scheme == 1) { - if(!zonemd_simple_collate(z, h, region, buf, reason)) { + if(!zonemd_simple_collate(z, hashalgo, h, region, buf, reason)) { if(!*reason) *reason = "scheme simple collate fail"; + secalgo_hash_delete(h); return 0; } } - /* - if(!zonemd_digest_finish(hashalgo, hash, hashlen, resultlen)) { + if(!zonemd_digest_finish(hashalgo, h, hash, hashlen, resultlen, + reason)) { + secalgo_hash_delete(h); *reason = "digest finish fail"; return 0; } - */ + secalgo_hash_delete(h); return 1; } diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 65bca8b69..18509ce85 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -141,6 +141,69 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res) #endif } +/** hash structure for keeping track of running hashes */ +struct secalgo_hash { + /** the openssl message digest context */ + EVP_MD_CTX* ctx; +}; + +/** create secalgo hash with hash type */ +static struct secalgo_hash* secalgo_hash_create_md(const EVP_MD* md) +{ + struct secalgo_hash* h; + if(!md) + return NULL; + h = calloc(1, sizeof(*h)); + if(!h) + return NULL; + h->ctx = EVP_MD_CTX_create(); + if(!h->ctx) { + free(h); + return NULL; + } + if(!EVP_DigestInit_ex(h->ctx, md, NULL)) { + EVP_MD_CTX_destroy(h->ctx); + free(h); + return NULL; + } + return h; +} + +struct secalgo_hash* secalgo_hash_create_sha384(void) +{ + return secalgo_hash_create_md(EVP_sha384()); +} + +struct secalgo_hash* secalgo_hash_create_sha512(void) +{ + return secalgo_hash_create_md(EVP_sha512()); +} + +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len) +{ + return EVP_DigestUpdate(hash->ctx, (unsigned char*)data, + (unsigned int)len); +} + +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen) +{ + if(EVP_MD_CTX_size(hash->ctx) > (int)maxlen) { + *resultlen = 0; + log_err("secalgo_hash_final: hash buffer too small"); + return 0; + } + *resultlen = EVP_MD_CTX_size(hash->ctx); + return EVP_DigestFinal_ex(hash->ctx, result, NULL); +} + +void secalgo_hash_delete(struct secalgo_hash* hash) +{ + if(!hash) return; + EVP_MD_CTX_destroy(hash->ctx); + free(hash); +} + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. diff --git a/validator/val_secalgo.h b/validator/val_secalgo.h index 52aaeb9f6..8b6080dc2 100644 --- a/validator/val_secalgo.h +++ b/validator/val_secalgo.h @@ -43,6 +43,7 @@ #ifndef VALIDATOR_VAL_SECALGO_H #define VALIDATOR_VAL_SECALGO_H struct sldns_buffer; +struct secalgo_hash; /** Return size of nsec3 hash algorithm, 0 if not supported */ size_t nsec3_hash_algo_size_supported(int id); @@ -67,6 +68,48 @@ int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, */ void secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res); +/** + * Start a hash of type sha384. Allocates structure, then inits it, + * so that a series of updates can be performed, before the final result. + * @return hash structure. NULL on malloc failure or no support. + */ +struct secalgo_hash* secalgo_hash_create_sha384(void); + +/** + * Start a hash of type sha512. Allocates structure, then inits it, + * so that a series of updates can be performed, before the final result. + * @return hash structure. NULL on malloc failure or no support. + */ +struct secalgo_hash* secalgo_hash_create_sha512(void); + +/** + * Update a hash with more information to add to it. + * @param hash: the hash that is updated. + * @param data: data to add. + * @param len: length of data. + * @return false on failure. + */ +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len); + +/** + * Get the final result of the hash. + * @param hash: the hash that has had updates to it. + * @param result: where to store the result. + * @param maxlen: length of the result buffer, eg. size of the allocation. + * If not large enough the routine fails. + * @param resultlen: the length of the result, returned to the caller. + * How much of maxlen is used. + * @return false on failure. + */ +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen); + +/** + * Delete the hash structure. + * @param hash: the hash to delete. + */ +void secalgo_hash_delete(struct secalgo_hash* hash); + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo.