/*! * Generate new key with parameters from KASP policy and add it into zone. */ int generate_key(dnssec_event_ctx_t *ctx, bool ksk, dnssec_kasp_key_t **key_ptr) { assert(ctx); assert(ctx->zone); assert(ctx->keystore); assert(ctx->policy); dnssec_key_algorithm_t algorithm = ctx->policy->algorithm; unsigned size = ksk ? ctx->policy->ksk_size : ctx->policy->zsk_size; // generate key in the keystore _cleanup_free_ char *id = NULL; int r = dnssec_keystore_generate_key(ctx->keystore, algorithm, size, &id); if (r != DNSSEC_EOK) { return r; } // create KASP key dnssec_key_t *dnskey = NULL; r = dnssec_key_new(&dnskey); if (r != DNSSEC_EOK) { return r; } r = dnssec_key_set_dname(dnskey, ctx->zone->dname); if (r != DNSSEC_EOK) { dnssec_key_free(dnskey); return r; } dnssec_key_set_flags(dnskey, dnskey_flags(ksk)); r = dnssec_key_import_keystore(dnskey, ctx->keystore, id, algorithm); if (r != DNSSEC_EOK) { dnssec_key_free(dnskey); return r; } dnssec_kasp_key_t *key = calloc(1, sizeof(*key)); if (!key) { dnssec_key_free(dnskey); return DNSSEC_ENOMEM; } key->key = dnskey; key->timing.created = ctx->now; // add into KASP zone dnssec_list_t *keys = dnssec_kasp_zone_get_keys(ctx->zone); dnssec_list_append(keys, key); if (key_ptr) { *key_ptr = key; } return DNSSEC_EOK; }
int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen, const uint8_t *key_b_rdata, size_t key_b_rdlen) { dnssec_key_t *key_a = NULL, *key_b = NULL; int ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_a, NULL, key_a_rdata, key_a_rdlen); if (ret != 0) { return ret; } ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_b, NULL, key_b_rdata, key_b_rdlen); if (ret != 0) { dnssec_key_free(key_a); return ret; } /* If the algorithm and the public key match, we can be sure * that they are the same key. */ ret = kr_error(ENOENT); dnssec_binary_t pk_a, pk_b; if (dnssec_key_get_algorithm(key_a) == dnssec_key_get_algorithm(key_b) && dnssec_key_get_pubkey(key_a, &pk_a) == DNSSEC_EOK && dnssec_key_get_pubkey(key_b, &pk_b) == DNSSEC_EOK) { if (pk_a.size == pk_b.size && memcmp(pk_a.data, pk_b.data, pk_a.size) == 0) { ret = 0; } } dnssec_key_free(key_a); dnssec_key_free(key_b); return ret; }
/*! * Create DNSKEY from parameters. */ static int create_dnskey(const uint8_t *dname, key_params_t *params, dnssec_key_t **key_ptr) { assert(dname); assert(params); assert(key_ptr); int result = key_params_check(params); if (result != DNSSEC_EOK) { return result; } // create key dnssec_key_t *key = NULL; result = dnssec_key_new(&key); if (result != DNSSEC_EOK) { return result; } // set key parameters result = dnssec_key_set_dname(key, dname); if (result != DNSSEC_EOK) { dnssec_key_free(key); return result; } dnssec_key_set_algorithm(key, params->algorithm); uint16_t flags = dnskey_flags(params->is_ksk); dnssec_key_set_flags(key, flags); result = dnssec_key_set_pubkey(key, ¶ms->public_key); if (result != DNSSEC_EOK) { dnssec_key_free(key); return result; } // validate key ID const char *key_id = dnssec_key_get_id(key); if (!key_id) { dnssec_key_free(key); return DNSSEC_INVALID_PUBLIC_KEY; } if (!dnssec_keyid_equal(params->id, key_id)) { dnssec_key_free(key); return DNSSEC_INVALID_KEY_ID; } *key_ptr = key; return DNSSEC_EOK; }
/*! * Parse DNSKEY record. * * \todo Currently, the function waits for the first DNSKEY record, and skips * the others. We should be more strict and report other records as errors. * However, there is currently no API to stop the scanner. */ static void parse_record(zs_scanner_t *scanner) { assert(scanner); assert(scanner->data); dnssec_key_t *key = scanner->data; if (dnssec_key_get_dname(key) != NULL) { // skip till the the parser finishes return; } if (scanner->r_type != RTYPE_DNSKEY) { // should report error return; } dnssec_binary_t rdata = { .data = scanner->r_data, .size = scanner->r_data_length }; dnssec_key_set_dname(key, scanner->dname); dnssec_key_set_rdata(key, &rdata); } int legacy_pubkey_parse(const char *filename, dnssec_key_t **key_ptr) { assert(filename); assert(key_ptr); dnssec_key_t *key = NULL; int result = dnssec_key_new(&key); if (result != DNSSEC_EOK) { return result; } uint16_t cls = CLASS_IN; uint32_t ttl = 0; zs_scanner_t *scanner = zs_scanner_create(".", cls, ttl, parse_record, NULL, key); if (!scanner) { dnssec_key_free(key); return DNSSEC_NOT_FOUND; } result = zs_scanner_parse_file(scanner, filename); zs_scanner_free(scanner); if (result != 0 || dnssec_key_get_dname(key) == NULL) { dnssec_key_free(key); return DNSSEC_INVALID_PUBLIC_KEY; } *key_ptr = key; return DNSSEC_EOK; }
/*! * Load zone keys. */ static int load_zone_keys(const uint8_t *zone, dnssec_list_t **list_ptr, json_t *keys) { if (!keys || !json_is_array(keys)) { return DNSSEC_CONFIG_MALFORMED; } dnssec_list_t *new_keys = dnssec_list_new(); if (!new_keys) { return DNSSEC_ENOMEM; } int result = DNSSEC_EOK; int index; json_t *key; json_array_foreach(keys, index, key) { _cleanup_key_params_ key_params_t params = { 0 }; result = decode_object(KEY_ATTRIBUTES, key, ¶ms); if (result != DNSSEC_EOK) { break; } dnssec_key_t *dnskey = NULL; result = create_dnskey(zone, ¶ms, &dnskey); if (result != DNSSEC_EOK) { break; } result = keyset_add_dnskey(new_keys, dnskey, ¶ms.timing); if (result != DNSSEC_EOK) { dnssec_key_free(dnskey); break; } }
static void* scheduler_queue_dnskey_create_thread(void* data_) { scheduler_dnskey_create *data = (scheduler_dnskey_create*)data_; ya_result return_value; log_info("dnssec: key create (%{dnsname} %hd %hhd %hd)", data->zone->origin, data->flags, data->algorithm, data->size); char origin[MAX_DOMAIN_LENGTH]; dnsname_to_cstr(origin, data->zone->origin); dnssec_key* key; if(ISOK(return_value = dnssec_key_createnew(DNSKEY_ALGORITHM_RSASHA1_NSEC3, data->size, data->flags, origin, &key))) { if(ISOK(return_value = dnssec_key_store_private(key))) { if(ISOK(return_value = dnssec_key_store_dnskey(key))) { log_info("dnssec: key created (%{dnsname} %hd %hhd %hd)", data->zone->origin, data->flags, data->algorithm, data->size); } else { log_err("dnssec: key store public (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value); } } else { log_err("dnssec: key store private (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value); } } else { log_err("dnssec: key create failed (%{dnsname} %hd %hhd %hd): %r", data->zone->origin, data->flags, data->algorithm, data->size, return_value); } if(ISOK(return_value)) { data->key = key; } else { dnssec_key_free(key); data->key = NULL; } scheduler_schedule_task(scheduler_queue_dnskey_create_callback, data); /* WARNING: From this point forward, 'data' cannot be used anymore */ /* * The key is still in the keystore. * */ return NULL; }
int kr_dnssec_key_from_rdata(struct dseckey **key, const knot_dname_t *kown, const uint8_t *rdata, size_t rdlen) { if (!key || !rdata || rdlen == 0) { return kr_error(EINVAL); } dnssec_key_t *new_key = NULL; const dnssec_binary_t binary_key = { .size = rdlen, .data = (uint8_t *)rdata }; int ret = dnssec_key_new(&new_key); if (ret != DNSSEC_EOK) { return kr_error(ENOMEM); } ret = dnssec_key_set_rdata(new_key, &binary_key); if (ret != DNSSEC_EOK) { dnssec_key_free(new_key); return kr_error(ENOMEM); } if (kown) { ret = dnssec_key_set_dname(new_key, kown); if (ret != DNSSEC_EOK) { dnssec_key_free(new_key); return kr_error(ENOMEM); } } *key = (struct dseckey *) new_key; return kr_ok(); } void kr_dnssec_key_free(struct dseckey **key) { assert(key); dnssec_key_free((dnssec_key_t *) *key); *key = NULL; }
/*! * Parse legacy key files and get public key, private key, and key timing. */ int legacy_key_parse(const char *filename, dnssec_key_t **key_ptr, dnssec_binary_t *pem_ptr, dnssec_kasp_key_timing_t *timing) { if (!filename || !key_ptr || !pem_ptr || !timing) { return DNSSEC_EINVAL; } _cleanup_free_ char *filename_public = NULL; _cleanup_free_ char *filename_private = NULL; int result = get_key_names(filename, &filename_public, &filename_private); if (result != DNSSEC_EOK) { return result; } dnssec_key_t *key = NULL; result = legacy_pubkey_parse(filename_public, &key); if (result != DNSSEC_EOK) { return result; } legacy_privkey_t params = { 0 }; result = legacy_privkey_parse(filename_private, ¶ms); if (result != DNSSEC_EOK) { dnssec_key_free(key); return result; } dnssec_binary_t pem = { 0 }; result = params_to_pem(key, ¶ms, &pem); if (result != DNSSEC_EOK) { legacy_privkey_free(¶ms); return result; } *key_ptr = key; *pem_ptr = pem; params_to_timing(¶ms, timing); legacy_privkey_free(¶ms); return DNSSEC_EOK; }
/*! * Parse DNSKEY record. * * \todo Currently, the function waits for the first DNSKEY record, and skips * the others. We should be more strict and report other records as errors. */ static void parse_record(zs_scanner_t *scanner) { assert(scanner); assert(scanner->process.data); dnssec_key_t *key = scanner->process.data; if (dnssec_key_get_dname(key) != NULL) { // should report error scanner->state = ZS_STATE_STOP; return; } if (scanner->r_type != RTYPE_DNSKEY) { // should report error scanner->state = ZS_STATE_STOP; return; } dnssec_binary_t rdata = { .data = scanner->r_data, .size = scanner->r_data_length }; dnssec_key_set_dname(key, scanner->dname); dnssec_key_set_rdata(key, &rdata); } int legacy_pubkey_parse(const char *filename, dnssec_key_t **key_ptr) { assert(filename); assert(key_ptr); dnssec_key_t *key = NULL; int result = dnssec_key_new(&key); if (result != DNSSEC_EOK) { return result; } uint16_t cls = CLASS_IN; uint32_t ttl = 0; zs_scanner_t *scanner = malloc(sizeof(zs_scanner_t)); if (scanner == NULL) { dnssec_key_free(key); return DNSSEC_ENOMEM; } if (zs_init(scanner, ".", cls, ttl) != 0 || zs_set_input_file(scanner, filename) != 0 || zs_set_processing(scanner, parse_record, NULL, key) != 0 || zs_parse_all(scanner) != 0) { zs_deinit(scanner); free(scanner); dnssec_key_free(key); return DNSSEC_NOT_FOUND; } zs_deinit(scanner); free(scanner); if (dnssec_key_get_dname(key) == NULL) { dnssec_key_free(key); return DNSSEC_INVALID_PUBLIC_KEY; } *key_ptr = key; return DNSSEC_EOK; }
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); }
static int tcl_addkey(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { ya_result return_code; zdb_zone* zone; dnssec_key* key; u32 key_size; int argi = 1; u16 key_flags; if(FAIL(read_zone(argv, argc, &argi, &zone))) { return -1; } if(FAIL(read_u32(argv, argc, &argi, &key_size))) { return -2; } if(FAIL(read_u16(argv, argc, &argi, &key_flags))) { return -3; } /* argv[1] is always the origin */ key = dnssec_key_createnew(DNSKEY_ALGORITHM_RSASHA1_NSEC3, key_size, key_flags, argv[1]); if(key == NULL) { fprintf(stdout, "Key generation error\n"); fflush(stdout); return -4; } return_code = dnssec_key_store_private(key); if(FAIL(return_code)) { fprintf(stdout, ERROR_CODE_HEX_DEC, return_code, return_code); fflush(stdout); dnssec_key_free(key); return -5; } return_code = dnssec_key_store_dnskey(key); if(FAIL(return_code)) { fprintf(stdout, ERROR_CODE_HEX_DEC, return_code, return_code); fflush(stdout); dnssec_key_free(key); return -6; } dnssec_key_addrecord(zone, key); return TCL_OK; }