/*! * Export GnuTLS X.509 private key to PEM binary. */ int pem_gnutls_x509_export(gnutls_x509_privkey_t key, dnssec_binary_t *pem_ptr) { assert(key); assert(pem_ptr); dnssec_binary_t pem = { 0 }; int r = try_export_pem(key, &pem); if (r != GNUTLS_E_SHORT_MEMORY_BUFFER || pem.size == 0) { return DNSSEC_KEY_EXPORT_ERROR; } r = dnssec_binary_alloc(&pem, pem.size); if (r != DNSSEC_EOK) { return r; } r = try_export_pem(key, &pem); if (r != GNUTLS_E_SUCCESS) { dnssec_binary_free(&pem); return DNSSEC_KEY_EXPORT_ERROR; } *pem_ptr = pem; return DNSSEC_EOK; }
/*! * Free allocated key parameters and clear the structure. */ static void key_params_free(key_params_t *params) { assert(params); free(params->id); dnssec_binary_free(¶ms->public_key); clear_struct(params); }
static int pkcs8_dir_read(void *_handle, const char *id, dnssec_binary_t *pem) { if (!_handle || !id || !pem) { return DNSSEC_EINVAL; } pkcs8_dir_handle_t *handle = _handle; // open file and get it's size _cleanup_close_ int file = 0; int result = key_open_read(handle->dir_name, id, &file); if (result != DNSSEC_EOK) { return result; } size_t size = 0; result = file_size(file, &size); if (result != DNSSEC_EOK) { return result; } if (size == 0) { return DNSSEC_MALFORMED_DATA; } // read the stored data dnssec_binary_t read_pem = { 0 }; result = dnssec_binary_alloc(&read_pem, size); if (result != DNSSEC_EOK) { return result; } ssize_t read_count = read(file, read_pem.data, read_pem.size); if (read_count == -1) { dnssec_binary_free(&read_pem); return dnssec_errno_to_error(errno); } assert(read_count == read_pem.size); *pem = read_pem; return DNSSEC_EOK; }
static int authenticate_ds(const dnssec_key_t *key, dnssec_binary_t *ds_rdata, uint8_t digest_type) { /* Compute DS RDATA from the DNSKEY. */ dnssec_binary_t computed_ds = {0, }; int ret = dnssec_key_create_ds(key, digest_type, &computed_ds); if (ret != DNSSEC_EOK) { ret = kr_error(ENOMEM); goto fail; } /* DS records contain algorithm, key tag and the digest. * Therefore the comparison of the two DS is sufficient. */ ret = (ds_rdata->size == computed_ds.size) && (memcmp(ds_rdata->data, computed_ds.data, ds_rdata->size) == 0); ret = ret ? kr_ok() : kr_error(ENOENT); fail: dnssec_binary_free(&computed_ds); return ret; }
/*! * Generate new key and export it in the PEM format. */ int pem_generate(gnutls_pk_algorithm_t algorithm, unsigned bits, dnssec_binary_t *pem_ptr, char **id_ptr) { assert(pem_ptr); assert(id_ptr); // generate key _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL; int r = gnutls_x509_privkey_init(&key); if (r != GNUTLS_E_SUCCESS) { return DNSSEC_ENOMEM; } r = gnutls_x509_privkey_generate(key, algorithm, bits, 0); if (r != GNUTLS_E_SUCCESS) { return DNSSEC_KEY_GENERATE_ERROR; } // convert to PEM and export the ID dnssec_binary_t pem = { 0 }; r = pem_gnutls_x509_export(key, &pem); if (r != DNSSEC_EOK) { return r; } // export key ID char *id = gnutls_x509_privkey_hex_key_id(key); if (!id) { dnssec_binary_free(&pem); return DNSSEC_ENOMEM; } *pem_ptr = pem; *id_ptr = id; return DNSSEC_EOK; }
/*! * \brief Create NSEC3 owner name from regular owner name. * * \param owner Node owner name. * \param zone_apex Zone apex name. * \param params Params for NSEC3 hashing function. * * \return NSEC3 owner name, NULL in case of error. */ knot_dname_t *knot_create_nsec3_owner(const knot_dname_t *owner, const knot_dname_t *zone_apex, const knot_nsec3_params_t *params) { if (owner == NULL || zone_apex == NULL || params == NULL) { return NULL; } int owner_size = knot_dname_size(owner); if (owner_size < 0) { return NULL; } dnssec_binary_t data = { 0 }; data.data = (uint8_t *)owner; data.size = owner_size; dnssec_binary_t hash = { 0 }; dnssec_nsec3_params_t xparams = { .algorithm = params->algorithm, .flags = params->flags, .iterations = params->iterations, .salt = { .data = params->salt, .size = params->salt_length } }; int r = dnssec_nsec3_hash(&data, &xparams, &hash); if (r != DNSSEC_EOK) { return NULL; } knot_dname_t *result = knot_nsec3_hash_to_dname(hash.data, hash.size, zone_apex); dnssec_binary_free(&hash); return result; }
/*! * \brief Parse NSEC3 parameters and fill structure with NSEC3 parameters. */ static bool parse_nsec3_params(dnssec_nsec3_params_t *params, const char *salt_str, const char *algorithm_str, const char *iterations_str) { uint8_t algorithm = 0; int r = str_to_u8(algorithm_str, &algorithm); if (r != DNSSEC_EOK) { error("Invalid algorithm number."); return false; } uint16_t iterations = 0; r = str_to_u16(iterations_str, &iterations); if (r != DNSSEC_EOK) { error("Invalid iteration count, %s.", dnssec_strerror(r)); return false; } dnssec_binary_t salt = { 0 }; r = str_to_salt(salt_str, &salt); if (r != DNSSEC_EOK) { error("Invalid salt, %s.", dnssec_strerror(r)); return false; } if (salt.size > UINT8_MAX) { error("Invalid salt, maximum length is %d bytes.", UINT8_MAX); dnssec_binary_free(&salt); return false; } params->algorithm = algorithm; params->iterations = iterations; params->salt = salt; params->flags = 0; return true; }
/*! * \brief Entry point of 'knsec3hash'. */ int main(int argc, char *argv[]) { struct option options[] = { { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { NULL } }; int opt = 0; int li = 0; while ((opt = getopt_long(argc, argv, "hV", options, &li)) != -1) { switch(opt) { case 'V': printf("%s, version %s\n", PROGRAM_NAME, PACKAGE_VERSION); return 0; case 'h': usage(stdout); return 0; default: usage(stderr); return 1; } } // knsec3hash <salt> <algorithm> <iterations> <domain> if (argc != 5) { usage(stderr); return 1; } int exit_code = 1; dnssec_nsec3_params_t nsec3_params = { 0 }; dnssec_binary_t dname = { 0 }; dnssec_binary_t digest = { 0 }; dnssec_binary_t digest_print = { 0 }; if (!parse_nsec3_params(&nsec3_params, argv[1], argv[2], argv[3])) { goto fail; } dname.data = dname_from_ascii(argv[4]); dname.size = dname_length(dname.data); if (dname.data == NULL) { error("Cannot parse domain name."); goto fail; } dname_normalize(dname.data); int r = dnssec_nsec3_hash(&dname, &nsec3_params, &digest); if (r != DNSSEC_EOK) { error("Cannot compute NSEC3 hash, %s.", dnssec_strerror(r)); goto fail; } r = base32hex_encode(&digest, &digest_print); if (r != DNSSEC_EOK) { error("Cannot encode computed hash, %s.", dnssec_strerror(r)); goto fail; } exit_code = 0; printf("%.*s (salt=%s, hash=%d, iterations=%d)\n", (int)digest_print.size, digest_print.data, argv[1], nsec3_params.algorithm, nsec3_params.iterations); fail: dnssec_nsec3_params_free(&nsec3_params); dnssec_binary_free(&dname); dnssec_binary_free(&digest); dnssec_binary_free(&digest_print); return exit_code; }
static void test_sign(dnssec_key_t *p11_key, dnssec_key_t *soft_key) { int r; static const dnssec_binary_t input = { .data = (uint8_t *)"So Long, and Thanks for All the Fish.", .size = 37 }; dnssec_binary_t sign = { 0 }; // usage constraints ok(dnssec_key_can_sign(p11_key), MSG_PKCS11 " dnssec_key_can_sign()"); ok(dnssec_key_can_verify(p11_key), MSG_PKCS11 " dnssec_key_can_verify()"); ok(!dnssec_key_can_sign(soft_key), MSG_SOFTWARE " dnssec_key_can_sign()"); ok(dnssec_key_can_verify(soft_key), MSG_SOFTWARE " dnssec_key_can_verify()"); // PKCS #11 key signature dnssec_sign_ctx_t *ctx = NULL; r = dnssec_sign_new(&ctx, p11_key); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_init() "); r = dnssec_sign_add(ctx, &input); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_add()"); r = dnssec_sign_write(ctx, &sign); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_write()"); // PKCS #11 key verification r = dnssec_sign_init(ctx); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_init()"); r = dnssec_sign_add(ctx, &input); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_add()"); r = dnssec_sign_verify(ctx, &sign); ok(r == DNSSEC_EOK, MSG_PKCS11 " dnssec_sign_verify()"); // software verification dnssec_sign_free(ctx); ctx = NULL; r = dnssec_sign_new(&ctx, soft_key); ok(r == DNSSEC_EOK, MSG_SOFTWARE " dnssec_sign_init()"); r = dnssec_sign_add(ctx, &input); ok(r == DNSSEC_EOK, MSG_SOFTWARE " dnssec_sign_add()"); r = dnssec_sign_verify(ctx, &sign); ok(r == DNSSEC_EOK, MSG_SOFTWARE " dnssec_sign_verify()"); dnssec_binary_free(&sign); dnssec_sign_free(ctx); } static void test_key_use(dnssec_keystore_t *store, dnssec_key_algorithm_t algorithm, const char *keyid) { dnssec_key_t *p11_key = NULL; dnssec_key_t *soft_key = NULL; create_dnskeys(store, algorithm, keyid, &p11_key, &soft_key); test_sign(p11_key, soft_key); dnssec_key_free(p11_key); dnssec_key_free(soft_key); }