isc_result_t dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) { dns_name_t downname; unsigned char data[256]; isc_buffer_t buffer; isc_result_t result; isc_region_t r; /* * Send 'name' in DNSSEC canonical form to 'digest'. */ REQUIRE(VALID_NAME(name)); REQUIRE(digest != NULL); DNS_NAME_INIT(&downname, NULL); isc_buffer_init(&buffer, data, sizeof(data)); result = dns_name_downcase(name, &downname, &buffer); if (result != ISC_R_SUCCESS) return (result); isc_buffer_usedregion(&buffer, &r); return ((digest)(arg, &r)); }
int main(int argc, char **argv) { dns_fixedname_t fixed; dns_name_t *name; isc_buffer_t buffer; isc_region_t region; isc_result_t result; unsigned char hash[NSEC3_MAX_HASH_LENGTH]; unsigned char salt[DNS_NSEC3_SALTSIZE]; unsigned char text[1024]; unsigned int hash_alg; unsigned int length; unsigned int iterations; unsigned int salt_length; if (argc != 5) usage(); if (strcmp(argv[1], "-") == 0) { salt_length = 0; salt[0] = 0; } else { isc_buffer_init(&buffer, salt, sizeof(salt)); result = isc_hex_decodestring(argv[1], &buffer); check_result(result, "isc_hex_decodestring(salt)"); salt_length = isc_buffer_usedlength(&buffer); if (salt_length > DNS_NSEC3_SALTSIZE) fatal("salt too long"); } hash_alg = atoi(argv[2]); if (hash_alg > 255U) fatal("hash algorithm too large"); iterations = atoi(argv[3]); if (iterations > 0xffffU) fatal("iterations to large"); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); isc_buffer_init(&buffer, argv[4], strlen(argv[4])); isc_buffer_add(&buffer, strlen(argv[4])); result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL); check_result(result, "dns_name_fromtext() failed"); dns_name_downcase(name, name, NULL); length = isc_iterated_hash(hash, hash_alg, iterations, salt, salt_length, name->ndata, name->length); if (length == 0) fatal("isc_iterated_hash failed"); region.base = hash; region.length = length; isc_buffer_init(&buffer, text, sizeof(text)); isc_base32hexnp_totext(®ion, 1, "", &buffer); fprintf(stdout, "%.*s (salt=%s, hash=%u, iterations=%u)\n", (int)isc_buffer_usedlength(&buffer), text, argv[1], hash_alg, iterations); return(0); }
isc_result_t dns_nsec3_hashname(dns_fixedname_t *result, unsigned char rethash[NSEC3_MAX_HASH_LENGTH], size_t *hash_length, dns_name_t *name, dns_name_t *origin, dns_hash_t hashalg, unsigned int iterations, const unsigned char *salt, size_t saltlength) { unsigned char hash[NSEC3_MAX_HASH_LENGTH]; unsigned char nametext[DNS_NAME_FORMATSIZE]; dns_fixedname_t fixed; dns_name_t *downcased; isc_buffer_t namebuffer; isc_region_t region; size_t len; if (rethash == NULL) rethash = hash; memset(rethash, 0, NSEC3_MAX_HASH_LENGTH); dns_fixedname_init(&fixed); downcased = dns_fixedname_name(&fixed); dns_name_downcase(name, downcased, NULL); /* hash the node name */ len = isc_iterated_hash(rethash, hashalg, iterations, salt, saltlength, downcased->ndata, downcased->length); if (len == 0U) return (DNS_R_BADALG); if (hash_length != NULL) *hash_length = len; /* convert the hash to base32hex */ region.base = rethash; region.length = len; isc_buffer_init(&namebuffer, nametext, sizeof nametext); isc_base32hex_totext(®ion, 1, "", &namebuffer); /* convert the hex to a domain name */ dns_fixedname_init(result); return (dns_name_fromtext(dns_fixedname_name(result), &namebuffer, origin, 0, NULL)); }
static isc_result_t digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) { isc_region_t r; isc_result_t ret; dns_fixedname_t fname; dns_rdata_toregion(sigrdata, &r); INSIST(r.length >= 19); r.length = 18; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) return (ret); dns_fixedname_init(&fname); RUNTIME_CHECK(dns_name_downcase(&sig->signer, dns_fixedname_name(&fname), NULL) == ISC_R_SUCCESS); dns_name_toregion(dns_fixedname_name(&fname), &r); return (dst_context_adddata(ctx, &r)); }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); REQUIRE(key != NULL || ring != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA1_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA224_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA224) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA256_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA256) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA384_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA384) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA512_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA512) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (dstkey != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = NULL; if (dstkey != NULL) dst_key_attach(dstkey, &tkey->key); tkey->ring = ring; if (key != NULL) refs = 1; if (ring != NULL) refs++; ret = isc_refcount_init(&tkey->refs, refs); if (ret != ISC_R_SUCCESS) goto cleanup_creator; tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = NULL; isc_mem_attach(mctx, &tkey->mctx); ISC_LINK_INIT(tkey, link); tkey->magic = TSIG_MAGIC; if (ring != NULL) { ret = keyring_add(ring, name, tkey); if (ret != ISC_R_SUCCESS) goto cleanup_refs; } /* * Ignore this if it's a GSS key, since the key size is meaningless. */ if (dstkey != NULL && dst_key_size(dstkey) < 64 && !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_refs: tkey->magic = 0; while (refs-- > 0) isc_refcount_decrement(&tkey->refs, NULL); isc_refcount_destroy(&tkey->refs); cleanup_creator: if (tkey->key != NULL) dst_key_free(&tkey->key); if (tkey->creator != NULL) { dns_name_free(tkey->creator, mctx); isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); } cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (key != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = dstkey; tkey->ring = ring; if (ring != NULL) { RWLOCK(&ring->lock, isc_rwlocktype_write); ret = dns_rbt_addname(ring->keys, name, tkey); if (ret != ISC_R_SUCCESS) { RWUNLOCK(&ring->lock, isc_rwlocktype_write); goto cleanup_algorithm; } refs++; RWUNLOCK(&ring->lock, isc_rwlocktype_write); } if (key != NULL) refs++; isc_refcount_init(&tkey->refs, refs); tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = mctx; tkey->magic = TSIG_MAGIC; if (dstkey != NULL && dst_key_size(dstkey) < 64) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
isc_result_t dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, isc_boolean_t ignoretime, isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild) { dns_rdata_rrsig_t sig; dns_fixedname_t fnewname; isc_region_t r; isc_buffer_t envbuf; dns_rdata_t *rdatas; int nrdatas, i; isc_stdtime_t now; isc_result_t ret; unsigned char data[300]; dst_context_t *ctx = NULL; int labels = 0; isc_uint32_t flags; REQUIRE(name != NULL); REQUIRE(set != NULL); REQUIRE(key != NULL); REQUIRE(mctx != NULL); REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig); ret = dns_rdata_tostruct(sigrdata, &sig, NULL); if (ret != ISC_R_SUCCESS) return (ret); if (isc_serial_lt(sig.timeexpire, sig.timesigned)) return (DNS_R_SIGINVALID); if (!ignoretime) { isc_stdtime_get(&now); /* * Is SIG temporally valid? */ if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) return (DNS_R_SIGFUTURE); else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) return (DNS_R_SIGEXPIRED); } /* * Is the key allowed to sign data? */ flags = dst_key_flags(key); if (flags & DNS_KEYTYPE_NOAUTH) return (DNS_R_KEYUNAUTHORIZED); if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) return (DNS_R_KEYUNAUTHORIZED); ret = dst_context_create(key, mctx, &ctx); if (ret != ISC_R_SUCCESS) goto cleanup_struct; /* * Digest the SIG rdata (not including the signature). */ ret = digest_sig(ctx, sigrdata, &sig); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * If the name is an expanded wildcard, use the wildcard name. */ dns_fixedname_init(&fnewname); labels = dns_name_countlabels(name) - 1; RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), NULL) == ISC_R_SUCCESS); if (labels - sig.labels > 0) dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, NULL, dns_fixedname_name(&fnewname)); dns_name_toregion(dns_fixedname_name(&fnewname), &r); /* * Create an envelope for each rdata: <name|type|class|ttl>. */ isc_buffer_init(&envbuf, data, sizeof(data)); if (labels - sig.labels > 0) { isc_buffer_putuint8(&envbuf, 1); isc_buffer_putuint8(&envbuf, '*'); memcpy(data + 2, r.base, r.length); } else memcpy(data, r.base, r.length); isc_buffer_add(&envbuf, r.length); isc_buffer_putuint16(&envbuf, set->type); isc_buffer_putuint16(&envbuf, set->rdclass); isc_buffer_putuint32(&envbuf, sig.originalttl); ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_usedregion(&envbuf, &r); for (i = 0; i < nrdatas; i++) { isc_uint16_t len; isc_buffer_t lenbuf; isc_region_t lenr; /* * Skip duplicates. */ if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0) continue; /* * Digest the envelope. */ ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_array; /* * Digest the rdata length. */ isc_buffer_init(&lenbuf, &len, sizeof(len)); INSIST(rdatas[i].length < 65536); isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length); isc_buffer_usedregion(&lenbuf, &lenr); /* * Digest the rdata. */ ret = dst_context_adddata(ctx, &lenr); if (ret != ISC_R_SUCCESS) goto cleanup_array; ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); if (ret != ISC_R_SUCCESS) goto cleanup_array; } r.base = sig.signature; r.length = sig.siglen; ret = dst_context_verify(ctx, &r); if (ret == DST_R_VERIFYFAILURE) ret = DNS_R_SIGINVALID; cleanup_array: isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t)); cleanup_context: dst_context_destroy(&ctx); cleanup_struct: dns_rdata_freestruct(&sig); if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { if (wild != NULL) RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, dns_fixedname_name(&fnewname), wild, NULL) == ISC_R_SUCCESS); ret = DNS_R_FROMWILDCARD; } return (ret); }
isc_result_t dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, isc_stdtime_t *inception, isc_stdtime_t *expire, isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata) { dns_rdata_rrsig_t sig; dns_rdata_t tmpsigrdata; dns_rdata_t *rdatas; int nrdatas, i; isc_buffer_t sigbuf, envbuf; isc_region_t r; dst_context_t *ctx = NULL; isc_result_t ret; isc_buffer_t *databuf = NULL; char data[256 + 8]; isc_uint32_t flags; unsigned int sigsize; dns_fixedname_t fnewname; REQUIRE(name != NULL); REQUIRE(dns_name_countlabels(name) <= 255); REQUIRE(set != NULL); REQUIRE(key != NULL); REQUIRE(inception != NULL); REQUIRE(expire != NULL); REQUIRE(mctx != NULL); REQUIRE(sigrdata != NULL); if (*inception >= *expire) return (DNS_R_INVALIDTIME); /* * Is the key allowed to sign data? */ flags = dst_key_flags(key); if (flags & DNS_KEYTYPE_NOAUTH) return (DNS_R_KEYUNAUTHORIZED); if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) return (DNS_R_KEYUNAUTHORIZED); sig.mctx = mctx; sig.common.rdclass = set->rdclass; sig.common.rdtype = dns_rdatatype_rrsig; ISC_LINK_INIT(&sig.common, link); dns_name_init(&sig.signer, NULL); dns_name_clone(dst_key_name(key), &sig.signer); sig.covered = set->type; sig.algorithm = dst_key_alg(key); sig.labels = dns_name_countlabels(name) - 1; if (dns_name_iswildcard(name)) sig.labels--; sig.originalttl = set->ttl; sig.timesigned = *inception; sig.timeexpire = *expire; sig.keyid = dst_key_id(key); ret = dst_key_sigsize(key, &sigsize); if (ret != ISC_R_SUCCESS) return (ret); sig.siglen = sigsize; /* * The actual contents of sig.signature are not important yet, since * they're not used in digest_sig(). */ sig.signature = isc_mem_get(mctx, sig.siglen); if (sig.signature == NULL) return (ISC_R_NOMEMORY); ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dns_rdata_init(&tmpsigrdata); ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass, sig.common.rdtype, &sig, databuf); if (ret != ISC_R_SUCCESS) goto cleanup_databuf; ret = dst_context_create(key, mctx, &ctx); if (ret != ISC_R_SUCCESS) goto cleanup_databuf; /* * Digest the SIG rdata. */ ret = digest_sig(ctx, &tmpsigrdata, &sig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_fixedname_init(&fnewname); RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), NULL) == ISC_R_SUCCESS); dns_name_toregion(dns_fixedname_name(&fnewname), &r); /* * Create an envelope for each rdata: <name|type|class|ttl>. */ isc_buffer_init(&envbuf, data, sizeof(data)); memcpy(data, r.base, r.length); isc_buffer_add(&envbuf, r.length); isc_buffer_putuint16(&envbuf, set->type); isc_buffer_putuint16(&envbuf, set->rdclass); isc_buffer_putuint32(&envbuf, set->ttl); ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_usedregion(&envbuf, &r); for (i = 0; i < nrdatas; i++) { isc_uint16_t len; isc_buffer_t lenbuf; isc_region_t lenr; /* * Skip duplicates. */ if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0) continue; /* * Digest the envelope. */ ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_array; /* * Digest the length of the rdata. */ isc_buffer_init(&lenbuf, &len, sizeof(len)); INSIST(rdatas[i].length < 65536); isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length); isc_buffer_usedregion(&lenbuf, &lenr); ret = dst_context_adddata(ctx, &lenr); if (ret != ISC_R_SUCCESS) goto cleanup_array; /* * Digest the rdata. */ ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); if (ret != ISC_R_SUCCESS) goto cleanup_array; } isc_buffer_init(&sigbuf, sig.signature, sig.siglen); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_array; isc_buffer_usedregion(&sigbuf, &r); if (r.length != sig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_array; } memcpy(sig.signature, r.base, sig.siglen); ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass, sig.common.rdtype, &sig, buffer); cleanup_array: isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t)); cleanup_context: dst_context_destroy(&ctx); cleanup_databuf: isc_buffer_free(&databuf); cleanup_signature: isc_mem_put(mctx, sig.signature, sig.siglen); return (ret); }
isc_result_t dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, unsigned int digest_type, unsigned char *buffer, dns_rdata_t *rdata) { dns_fixedname_t fname; dns_name_t *name; unsigned char digest[ISC_SHA256_DIGESTLENGTH]; isc_region_t r; isc_buffer_t b; dns_rdata_ds_t ds; isc_sha1_t sha1; isc_sha256_t sha256; #ifdef HAVE_OPENSSL_GOST EVP_MD_CTX ctx; const EVP_MD *md; #endif REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey); if (!dns_ds_digest_supported(digest_type)) return (ISC_R_NOTIMPLEMENTED); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); (void)dns_name_downcase(owner, name, NULL); memset(buffer, 0, DNS_DS_BUFFERSIZE); isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE); switch (digest_type) { case DNS_DSDIGEST_SHA1: isc_sha1_init(&sha1); dns_name_toregion(name, &r); isc_sha1_update(&sha1, r.base, r.length); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); isc_sha1_update(&sha1, r.base, r.length); isc_sha1_final(&sha1, digest); break; #ifdef HAVE_OPENSSL_GOST #define CHECK(x) \ if ((x) != 1) { \ EVP_MD_CTX_cleanup(&ctx); \ return (DST_R_OPENSSLFAILURE); \ } case DNS_DSDIGEST_GOST: md = EVP_gost(); if (md == NULL) return (DST_R_OPENSSLFAILURE); EVP_MD_CTX_init(&ctx); CHECK(EVP_DigestInit(&ctx, md)); dns_name_toregion(name, &r); CHECK(EVP_DigestUpdate(&ctx, (const void *) r.base, (size_t) r.length)); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); CHECK(EVP_DigestUpdate(&ctx, (const void *) r.base, (size_t) r.length)); CHECK(EVP_DigestFinal(&ctx, digest, NULL)); break; #endif default: isc_sha256_init(&sha256); dns_name_toregion(name, &r); isc_sha256_update(&sha256, r.base, r.length); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); isc_sha256_update(&sha256, r.base, r.length); isc_sha256_final(digest, &sha256); break; } ds.mctx = NULL; ds.common.rdclass = key->rdclass; ds.common.rdtype = dns_rdatatype_ds; ds.algorithm = r.base[3]; ds.key_tag = dst_region_computeid(&r, ds.algorithm); ds.digest_type = digest_type; switch (digest_type) { case DNS_DSDIGEST_SHA1: ds.length = ISC_SHA1_DIGESTLENGTH; break; #ifdef HAVE_OPENSSL_GOST case DNS_DSDIGEST_GOST: ds.length = ISC_GOST_DIGESTLENGTH; break; #endif default: ds.length = ISC_SHA256_DIGESTLENGTH; break; } ds.digest = digest; return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds, &ds, &b)); }
isc_result_t dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, unsigned int digest_type, unsigned char *buffer, dns_rdata_t *rdata) { dns_fixedname_t fname; dns_name_t *name; unsigned char digest[ISC_SHA384_DIGESTLENGTH]; isc_region_t r; isc_buffer_t b; dns_rdata_ds_t ds; isc_sha1_t sha1; isc_sha256_t sha256; isc_sha384_t sha384; #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) isc_gost_t gost; #endif REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey); if (!dst_ds_digest_supported(digest_type)) return (ISC_R_NOTIMPLEMENTED); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); (void)dns_name_downcase(owner, name, NULL); memset(buffer, 0, DNS_DS_BUFFERSIZE); isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE); switch (digest_type) { case DNS_DSDIGEST_SHA1: isc_sha1_init(&sha1); dns_name_toregion(name, &r); isc_sha1_update(&sha1, r.base, r.length); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); isc_sha1_update(&sha1, r.base, r.length); isc_sha1_final(&sha1, digest); break; #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) #define RETERR(x) do { \ isc_result_t ret = (x); \ if (ret != ISC_R_SUCCESS) { \ isc_gost_invalidate(&gost); \ return (ret); \ } \ } while (/*CONSTCOND*/0) case DNS_DSDIGEST_GOST: RETERR(isc_gost_init(&gost)); dns_name_toregion(name, &r); RETERR(isc_gost_update(&gost, r.base, r.length)); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); RETERR(isc_gost_update(&gost, r.base, r.length)); RETERR(isc_gost_final(&gost, digest)); break; #endif case DNS_DSDIGEST_SHA384: isc_sha384_init(&sha384); dns_name_toregion(name, &r); isc_sha384_update(&sha384, r.base, r.length); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); isc_sha384_update(&sha384, r.base, r.length); isc_sha384_final(digest, &sha384); break; case DNS_DSDIGEST_SHA256: default: isc_sha256_init(&sha256); dns_name_toregion(name, &r); isc_sha256_update(&sha256, r.base, r.length); dns_rdata_toregion(key, &r); INSIST(r.length >= 4); isc_sha256_update(&sha256, r.base, r.length); isc_sha256_final(digest, &sha256); break; } ds.mctx = NULL; ds.common.rdclass = key->rdclass; ds.common.rdtype = dns_rdatatype_ds; ds.algorithm = r.base[3]; ds.key_tag = dst_region_computeid(&r, ds.algorithm); ds.digest_type = digest_type; switch (digest_type) { case DNS_DSDIGEST_SHA1: ds.length = ISC_SHA1_DIGESTLENGTH; break; #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) case DNS_DSDIGEST_GOST: ds.length = ISC_GOST_DIGESTLENGTH; break; #endif case DNS_DSDIGEST_SHA384: ds.length = ISC_SHA384_DIGESTLENGTH; break; case DNS_DSDIGEST_SHA256: default: ds.length = ISC_SHA256_DIGESTLENGTH; break; } ds.digest = digest; return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds, &ds, &b)); }
int main(int argc, char *argv[]) { char s[1000]; isc_result_t result; dns_fixedname_t wname, wname2, oname, compname, downname; isc_buffer_t source; isc_region_t r; dns_name_t *name, *origin, *comp, *down; isc_boolean_t downcase = ISC_FALSE; size_t len; isc_boolean_t quiet = ISC_FALSE; isc_boolean_t concatenate = ISC_FALSE; isc_boolean_t got_name = ISC_FALSE; isc_boolean_t check_absolute = ISC_FALSE; isc_boolean_t check_wildcard = ISC_FALSE; isc_boolean_t test_downcase = ISC_FALSE; isc_boolean_t inplace = ISC_FALSE; isc_boolean_t want_split = ISC_FALSE; unsigned int labels, split_label = 0; dns_fixedname_t fprefix, fsuffix; dns_name_t *prefix, *suffix; int ch; while ((ch = isc_commandline_parse(argc, argv, "acdiqs:w")) != -1) { switch (ch) { case 'a': check_absolute = ISC_TRUE; break; case 'c': concatenate = ISC_TRUE; break; case 'd': test_downcase = ISC_TRUE; break; case 'i': inplace = ISC_TRUE; break; case 'q': quiet = ISC_TRUE; break; case 's': want_split = ISC_TRUE; split_label = atoi(isc_commandline_argument); break; case 'w': check_wildcard = ISC_TRUE; break; } } argc -= isc_commandline_index; argv += isc_commandline_index; if (argc > 0) { if (strcasecmp("none", argv[0]) == 0) origin = NULL; else { len = strlen(argv[0]); isc_buffer_init(&source, argv[0], len); isc_buffer_add(&source, len); dns_fixedname_init(&oname); origin = &oname.name; result = dns_name_fromtext(origin, &source, dns_rootname, ISC_FALSE, NULL); if (result != 0) { fprintf(stderr, "dns_name_fromtext() failed: %d\n", result); exit(1); } } } else if (concatenate) origin = NULL; else origin = dns_rootname; if (argc >= 1) { if (strcasecmp("none", argv[1]) == 0) comp = NULL; else { len = strlen(argv[1]); isc_buffer_init(&source, argv[1], len); isc_buffer_add(&source, len); dns_fixedname_init(&compname); comp = &compname.name; result = dns_name_fromtext(comp, &source, origin, ISC_FALSE, NULL); if (result != 0) { fprintf(stderr, "dns_name_fromtext() failed: %d\n", result); exit(1); } } } else comp = NULL; dns_fixedname_init(&wname); name = dns_fixedname_name(&wname); dns_fixedname_init(&wname2); while (fgets(s, sizeof(s), stdin) != NULL) { len = strlen(s); if (len > 0U && s[len - 1] == '\n') { s[len - 1] = '\0'; len--; } isc_buffer_init(&source, s, len); isc_buffer_add(&source, len); if (len > 0U) result = dns_name_fromtext(name, &source, origin, downcase, NULL); else { if (name == dns_fixedname_name(&wname)) dns_fixedname_init(&wname); else dns_fixedname_init(&wname2); result = ISC_R_SUCCESS; } if (result != ISC_R_SUCCESS) { printf("%s\n", dns_result_totext(result)); if (name == dns_fixedname_name(&wname)) dns_fixedname_init(&wname); else dns_fixedname_init(&wname2); continue; } if (check_absolute && dns_name_countlabels(name) > 0) { if (dns_name_isabsolute(name)) printf("absolute\n"); else printf("relative\n"); } if (check_wildcard && dns_name_countlabels(name) > 0) { if (dns_name_iswildcard(name)) printf("wildcard\n"); else printf("not wildcard\n"); } dns_name_toregion(name, &r); if (!quiet) { print_wirename(&r); printf("%u labels, %u bytes.\n", dns_name_countlabels(name), r.length); } if (concatenate) { if (got_name) { printf("Concatenating.\n"); result = dns_name_concatenate(&wname.name, &wname2.name, &wname2.name, NULL); name = &wname2.name; if (result == ISC_R_SUCCESS) { if (check_absolute && dns_name_countlabels(name) > 0) { if (dns_name_isabsolute(name)) printf("absolute\n"); else printf("relative\n"); } if (check_wildcard && dns_name_countlabels(name) > 0) { if (dns_name_iswildcard(name)) printf("wildcard\n"); else printf("not " "wildcard\n"); } dns_name_toregion(name, &r); if (!quiet) { print_wirename(&r); printf("%u labels, " "%u bytes.\n", dns_name_countlabels(name), r.length); } } else printf("%s\n", dns_result_totext(result)); got_name = ISC_FALSE; } else got_name = ISC_TRUE; } isc_buffer_init(&source, s, sizeof(s)); if (dns_name_countlabels(name) > 0) result = dns_name_totext(name, ISC_FALSE, &source); else result = ISC_R_SUCCESS; if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(&source, &r); if (r.length > 0) printf("%.*s\n", (int)r.length, r.base); else printf("<empty text name>\n"); if (!quiet) { printf("%u bytes.\n", source.used); } } else printf("%s\n", dns_result_totext(result)); if (test_downcase) { if (inplace) { down = name; } else { dns_fixedname_init(&downname); down = dns_fixedname_name(&downname); } result = dns_name_downcase(name, down, NULL); INSIST(result == ISC_R_SUCCESS); if (!quiet) { dns_name_toregion(down, &r); print_wirename(&r); printf("%u labels, %u bytes.\n", dns_name_countlabels(down), r.length); } isc_buffer_init(&source, s, sizeof(s)); print_name(down); } if (comp != NULL && dns_name_countlabels(name) > 0) { int order; unsigned int nlabels; dns_namereln_t namereln; namereln = dns_name_fullcompare(name, comp, &order, &nlabels); if (!quiet) { if (order < 0) printf("<"); else if (order > 0) printf(">"); else printf("="); switch (namereln) { case dns_namereln_contains: printf(", contains"); break; case dns_namereln_subdomain: printf(", subdomain"); break; case dns_namereln_commonancestor: printf(", common ancestor"); break; default: break; } if (namereln != dns_namereln_none && namereln != dns_namereln_equal) printf(", nlabels = %u", nlabels); printf("\n"); } printf("dns_name_equal() returns %s\n", dns_name_equal(name, comp) ? "TRUE" : "FALSE"); } labels = dns_name_countlabels(name); if (want_split && split_label < labels) { dns_fixedname_init(&fprefix); prefix = dns_fixedname_name(&fprefix); dns_fixedname_init(&fsuffix); suffix = dns_fixedname_name(&fsuffix); printf("splitting at label %u: ", split_label); dns_name_split(name, split_label, prefix, suffix); printf("\n prefix = "); print_name(prefix); printf(" suffix = "); print_name(suffix); } if (concatenate) { if (got_name) name = &wname2.name; else name = &wname.name; } } return (0); }
static void nsec3hash(nsec3printer *nsec3print, const char *algostr, const char *flagstr, const char *iterstr, const char *saltstr, const char *domain) { dns_fixedname_t fixed; dns_name_t *name; isc_buffer_t buffer; isc_region_t region; isc_result_t result; unsigned char hash[NSEC3_MAX_HASH_LENGTH]; unsigned char salt[DNS_NSEC3_SALTSIZE]; unsigned char text[1024]; unsigned int hash_alg; unsigned int flags; unsigned int length; unsigned int iterations; unsigned int salt_length; const char dash[] = "-"; if (strcmp(saltstr, "-") == 0) { salt_length = 0; salt[0] = 0; } else { isc_buffer_init(&buffer, salt, sizeof(salt)); result = isc_hex_decodestring(saltstr, &buffer); check_result(result, "isc_hex_decodestring(salt)"); salt_length = isc_buffer_usedlength(&buffer); if (salt_length > DNS_NSEC3_SALTSIZE) fatal("salt too long"); if (salt_length == 0) saltstr = dash; } hash_alg = atoi(algostr); if (hash_alg > 255U) fatal("hash algorithm too large"); flags = flagstr == NULL ? 0 : atoi(flagstr); if (flags > 255U) fatal("flags too large"); iterations = atoi(iterstr); if (iterations > 0xffffU) fatal("iterations to large"); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); isc_buffer_constinit(&buffer, domain, strlen(domain)); isc_buffer_add(&buffer, strlen(domain)); result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL); check_result(result, "dns_name_fromtext() failed"); dns_name_downcase(name, name, NULL); length = isc_iterated_hash(hash, hash_alg, iterations, salt, salt_length, name->ndata, name->length); if (length == 0) fatal("isc_iterated_hash failed"); region.base = hash; region.length = length; isc_buffer_init(&buffer, text, sizeof(text)); isc_base32hexnp_totext(®ion, 1, "", &buffer); isc_buffer_putuint8(&buffer, '\0'); nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text); }