summaryrefslogtreecommitdiff
path: root/src/libknot/nsec3.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
committerOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
commitc8d5977bb546dae9ed59d81556639c49badd8121 (patch)
tree4c86750db26c1c3502b60f2cd78ca9611cfa01d6 /src/libknot/nsec3.c
downloadknot-upstream/0.8.0_pre1.tar.gz
Imported Upstream version 0.8.0~pre1upstream/0.8.0_pre1
Diffstat (limited to 'src/libknot/nsec3.c')
-rw-r--r--src/libknot/nsec3.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c
new file mode 100644
index 0000000..303d2e6
--- /dev/null
+++ b/src/libknot/nsec3.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#include "nsec3.h"
+#include "common.h"
+#include "util/descriptor.h"
+#include "util/utils.h"
+#include "util/tolower.h"
+#include "util/error.h"
+#include "util/debug.h"
+
+/*----------------------------------------------------------------------------*/
+
+int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
+ const knot_rrset_t *nsec3param)
+{
+ if (params == NULL || nsec3param == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(knot_rrset_type(nsec3param) == KNOT_RRTYPE_NSEC3PARAM);
+ const knot_rdata_t *rdata = knot_rrset_rdata(nsec3param);
+
+ assert(rdata->count == 4);
+
+ params->algorithm = *(uint8_t *)
+ (&knot_rdata_item(rdata, 0)->raw_data[1]);
+ params->flags = *(uint8_t *)
+ (&knot_rdata_item(rdata, 1)->raw_data[1]);
+ params->iterations = knot_wire_read_u16(
+ (uint8_t *)(knot_rdata_item(rdata, 2)->raw_data + 1));
+
+ params->salt_length =
+ ((uint8_t *)knot_rdata_item(rdata, 3)->raw_data)[2];
+
+ if (params->salt_length > 0) {
+ params->salt = (uint8_t *)malloc(params->salt_length);
+ CHECK_ALLOC_LOG(params->salt, -1);
+ memcpy(params->salt,
+ (uint8_t *)knot_rdata_item(rdata, 3)->raw_data + 3,
+ params->salt_length);
+ } else {
+ params->salt = NULL;
+ }
+
+ dbg_nsec3("Parsed NSEC3PARAM:\n");
+ dbg_nsec3("Algorithm: %hu\n", params->algorithm);
+ dbg_nsec3("Flags: %hu\n", params->flags);
+ dbg_nsec3("Iterations: %hu\n", params->iterations);
+ dbg_nsec3("Salt length: %hu\n", params->salt_length);
+ dbg_nsec3("Salt: ");
+ if (params->salt != NULL) {
+ dbg_nsec3_hex((char *)params->salt,
+ params->salt_length);
+ dbg_nsec3("\n");
+ } else {
+ dbg_nsec3("none\n");
+ }
+
+ return KNOT_EOK;
+}
+
+static uint8_t *knot_nsec3_to_lowercase(const uint8_t *data, size_t size)
+{
+ uint8_t *out = (uint8_t *)malloc(size);
+ CHECK_ALLOC_LOG(out, NULL);
+
+ for (int i = 0; i < size; ++i) {
+ out[i] = knot_tolower(data[i]);
+ }
+
+ return out;
+}
+
+/*----------------------------------------------------------------------------*/
+#if KNOT_NSEC3_SHA_USE_EVP
+int knot_nsec3_sha1(const knot_nsec3_params_t *params,
+ const uint8_t *data, size_t size, uint8_t **digest,
+ size_t *digest_size)
+{
+ if (digest == NULL || digest_size == NULL || data == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ uint8_t *salt = params->salt;
+ uint8_t salt_length = params->salt_length;
+ uint16_t iterations = params->iterations;
+
+ EVP_MD_CTX mdctx;
+ EVP_MD_CTX_init(&mdctx);
+
+ *digest = (uint8_t *)malloc(EVP_MD_size(EVP_sha1()));
+ if (*digest == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ uint8_t *data_low = knot_nsec3_to_lowercase(data, size);
+ if (data_low == NULL) {
+ free(*digest);
+ return -1;
+ }
+
+ const uint8_t *in = data_low;
+ unsigned in_size = size;
+
+ int res = 0;
+
+#ifdef KNOT_NSEC3_DEBUG
+ unsigned long long total_time = 0;
+ unsigned long calls = 0;
+ long time = 0;
+#endif
+
+ for (int i = 0; i <= iterations; ++i) {
+#ifdef KNOT_NSEC3_DEBUG
+ perf_begin();
+#endif
+
+ EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL);
+
+ res = EVP_DigestUpdate(&mdctx, in, in_size);
+
+ if (salt_length > 0) {
+ res = EVP_DigestUpdate(&mdctx, salt, salt_length);
+ }
+
+ EVP_DigestFinal_ex(&mdctx, *digest, digest_size);
+ in = *digest;
+ in_size = *digest_size;
+
+#ifdef KNOT_NSEC3_DEBUG
+ perf_end(time);
+ total_time += time;
+ ++calls;
+#endif
+
+ if (res != 1) {
+ dbg_nsec3("Error calculating SHA-1 hash.\n");
+ free(data_low);
+ free(*digest);
+ return -2;
+ }
+ }
+
+ EVP_MD_CTX_cleanup(&mdctx);
+
+ dbg_nsec3("NSEC3 hashing: calls: %lu, avg time per call: %f."
+ "\n", calls, (double)(total_time) / calls);
+
+ free(data_low);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+#else
+
+int knot_nsec3_sha1(const knot_nsec3_params_t *params,
+ const uint8_t *data, size_t size, uint8_t **digest,
+ size_t *digest_size)
+{
+ if (params == NULL || digest == NULL || digest_size == NULL
+ || data == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ uint8_t *salt = params->salt;
+ uint8_t salt_length = params->salt_length;
+ uint16_t iterations = params->iterations;
+
+ dbg_nsec3("Hashing: \n");
+ dbg_nsec3(" Data: %.*s \n", size, data);
+ dbg_nsec3_hex((const char *)data, size);
+ dbg_nsec3(" (size %d)\n Iterations: %u\n", (int)size, iterations);
+ dbg_nsec3(" Salt length: %u\n", salt_length);
+ dbg_nsec3(" Salt: ");
+ if (salt_length > 0) {
+ dbg_nsec3_hex((char *)salt, salt_length);
+ dbg_nsec3("\n");
+ } else {
+ dbg_nsec3("none\n");
+ }
+
+ SHA_CTX ctx;
+
+ *digest = (uint8_t *)malloc(SHA_DIGEST_LENGTH);
+ if (*digest == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ uint8_t *data_low = knot_nsec3_to_lowercase(data, size);
+ if (data_low == NULL) {
+ free(*digest);
+ return KNOT_ENOMEM;
+ }
+
+ const uint8_t *in = data_low;
+ unsigned in_size = size;
+
+ int res = 0;
+
+ // other iterations
+ for (int i = 0; i <= iterations; ++i) {
+ SHA1_Init(&ctx);
+
+ res = SHA1_Update(&ctx, in, in_size);
+
+ if (salt_length > 0) {
+ res = SHA1_Update(&ctx, salt, salt_length);
+ }
+
+ SHA1_Final(*digest, &ctx);
+
+ in = *digest;
+ in_size = SHA_DIGEST_LENGTH;
+
+ if (res != 1) {
+ dbg_nsec3("Error calculating SHA-1 hash.\n");
+ free(data_low);
+ free(*digest);
+ return KNOT_ECRYPTO;
+ }
+ }
+
+ *digest_size = SHA_DIGEST_LENGTH;
+
+ dbg_nsec3("Hash: %.*s\n", *digest_size, *digest);
+ dbg_nsec3_hex((const char *)*digest, *digest_size);
+ dbg_nsec3("\n");
+
+ free(data_low);
+ return KNOT_EOK;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+void knot_nsec3_params_free(knot_nsec3_params_t *params)
+{
+ if (params->salt != NULL) {
+ free(params->salt);
+ }
+}