]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
zonemd, digest code calls, secalgo openssl sha384 and sha512.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Oct 2020 09:19:31 +0000 (11:19 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Oct 2020 09:19:31 +0000 (11:19 +0200)
services/authzone.c
validator/val_secalgo.c
validator/val_secalgo.h

index b4217bd55a13fb0a2301de8d20f28061cd6376b4..208c0b82549b46b8395092421f052e4f56965fb6 100644 (file)
@@ -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;
 }
 
index 65bca8b69d6e8a0a7f9800692a04e27520c7eb2e..18509ce8591c43cf68e3080a1f2ada38555c1aed 100644 (file)
@@ -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.
index 52aaeb9f6d36f3091e5258c82849e7d2d96f36fe..8b6080dc24a20419fb21b7ae027c8d0f01830b44 100644 (file)
@@ -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.