/* * Check if any clock skew policy matches */ static void get_clock_skew(val_context_t *ctx, u_char *name_n, int *skew, u_int32_t *ttl_x) { policy_entry_t *cs_pol, *cs_cur; u_char *p; size_t name_len; if (ctx == NULL || name_n == NULL || skew == NULL || ttl_x == NULL) { val_log(ctx, LOG_DEBUG, "get_clock_skew(): Cannot check for clock skew policy, bad args"); return; } RETRIEVE_POLICY(ctx, P_CLOCK_SKEW, cs_pol); if (cs_pol) { name_len = wire_name_length(name_n); for (cs_cur = cs_pol; cs_cur && (wire_name_length(cs_cur->zone_n) > name_len); cs_cur = cs_cur->next); /* * for all zones which are shorter or as long, do a strstr */ /* * Because of the ordering, the longest match is found first */ for (; cs_cur; cs_cur = cs_cur->next) { int root_zone = 0; if (!namecmp(cs_cur->zone_n, (const u_char *) "")) root_zone = 1; else { /* * Find the last occurrence of cs_cur->zone_n in name_n */ p = name_n; while (p && (*p != '\0')) { if (!namecmp(p, cs_cur->zone_n)) break; p = p + *p + 1; } } if (root_zone || (!namecmp(p, cs_cur->zone_n))) { val_log(ctx, LOG_DEBUG, "get_clock_skew(): Found clock skew policy"); if (cs_cur->pol) { *skew = ((struct clock_skew_policy *)(cs_cur->pol))->clock_skew; if (cs_cur->exp_ttl > 0) *ttl_x = cs_cur->exp_ttl; return; } } } } val_log(ctx, LOG_DEBUG, "get_clock_skew(): No clock skew policy found"); *skew = 0; }
int ds_sha384_hash_is_equal(u_char * name_n, u_char * rrdata, size_t rrdatalen, u_char * ds_hash, size_t ds_hash_len) { u_char ds_digest[SHA384_DIGEST_LENGTH]; size_t namelen; SHA512_CTX c; size_t l_index; u_char qc_name_n[NS_MAXCDNAME]; if (rrdata == NULL || ds_hash_len != SHA384_DIGEST_LENGTH) return 0; namelen = wire_name_length(name_n); memcpy(qc_name_n, name_n, namelen); l_index = 0; lower_name(qc_name_n, &l_index); memset(ds_digest, 0, SHA384_DIGEST_LENGTH); SHA384_Init(&c); SHA384_Update(&c, qc_name_n, namelen); SHA384_Update(&c, rrdata, rrdatalen); SHA384_Final(ds_digest, &c); if (!memcmp(ds_digest, ds_hash, SHA384_DIGEST_LENGTH)) return 1; return 0; }
u_char * nsec3_sha_hash_compute(u_char * name_n, u_char * salt, size_t saltlen, size_t iter, u_char ** hash, size_t * hashlen) { /* * Assume that the caller has already performed all sanity checks */ SHA_CTX c; size_t i; size_t l_index; int len = wire_name_length(name_n); u_char qc_name_n[NS_MAXCDNAME]; memcpy(qc_name_n, name_n, len); l_index = 0; lower_name(qc_name_n, &l_index); *hash = (u_char *) MALLOC(SHA_DIGEST_LENGTH * sizeof(u_char)); if (*hash == NULL) return NULL; *hashlen = SHA_DIGEST_LENGTH; memset(*hash, 0, SHA_DIGEST_LENGTH); /* * IH(salt, x, 0) = H( x || salt) */ SHA1_Init(&c); SHA1_Update(&c, qc_name_n, wire_name_length(qc_name_n)); SHA1_Update(&c, salt, saltlen); SHA1_Final(*hash, &c); /* * IH(salt, x, k) = H(IH(salt, x, k-1) || salt) */ for (i = 0; i < iter; i++) { SHA1_Init(&c); SHA1_Update(&c, *hash, *hashlen); SHA1_Update(&c, salt, saltlen); SHA1_Final(*hash, &c); } return *hash; }
/* * Calculate the size of the field over which the verification * is done. This is the sum of * the number of bytes through the signer name in the SIG RDATA * the length of the signer name (uncompressed) * the sum of the fully uncompressed lengths of the RRs in the set * *field_length is the field length * *signer_length is the length of the signer's name (used externally) */ static int predict_sigbuflength(struct rrset_rec *rr_set, size_t * field_length, size_t *signer_length) { struct rrset_rr *rr; int owner_length; /** Input has already been NULL-checked **/ owner_length = wire_name_length(rr_set->rrs_name_n); *signer_length = wire_name_length(&rr_set->rrs_sig->rr_rdata[SIGNBY]); if (*signer_length == 0) return VAL_BAD_ARGUMENT; *field_length = SIGNBY + (*signer_length); for (rr = rr_set->rrs_data; rr; rr = rr->rr_next) *field_length += owner_length + ENVELOPE + rr->rr_rdata_length; return VAL_NO_ERROR; }
/* * Create the buffer over which the signature is to be verified */ static int make_sigfield(u_char ** field, size_t * field_length, struct rrset_rec *rr_set, struct rrset_rr *rr_sig, int is_a_wildcard) { struct rrset_rr *curr_rr; size_t index; size_t signer_length; size_t owner_length; u_int16_t type_n; u_int16_t class_n; u_int32_t ttl_n; u_int16_t rdata_length_n; u_char lowered_owner_n[NS_MAXCDNAME]; size_t l_index; int retval; if ((field == NULL) || (field_length == NULL) || (rr_set == NULL) || (rr_sig == NULL) || (rr_set->rrs_name_n == NULL) || (rr_set->rrs_sig == NULL) || (rr_set->rrs_sig->rr_rdata == NULL)) return VAL_BAD_ARGUMENT; if ((retval = predict_sigbuflength(rr_set, field_length, &signer_length)) != VAL_NO_ERROR) return retval; *field = (u_char *) MALLOC(*field_length * sizeof(u_char)); if (*field == NULL) return VAL_OUT_OF_MEMORY; /* * Make sure we are using the correct TTL */ memcpy(&ttl_n, &rr_sig->rr_rdata[TTL], sizeof(u_int32_t)); rr_set->rrs_ttl_h = ntohl(ttl_n); /* * While we're at it, we'll gather other common info, specifically * network ordered numbers (type, class) and name length. */ owner_length = wire_name_length(rr_set->rrs_name_n); if (owner_length == 0) goto err; memcpy(lowered_owner_n, rr_set->rrs_name_n, owner_length); l_index = 0; lower_name(lowered_owner_n, &l_index); type_n = htons(rr_set->rrs_type_h); class_n = htons(rr_set->rrs_class_h); /* * Copy in the SIG RDATA (up to the signature */ index = 0; if ((index + SIGNBY + signer_length) > *field_length) goto err; memcpy(&(*field)[index], rr_sig->rr_rdata, SIGNBY + signer_length); l_index = 0; lower_name(&(*field)[index+SIGNBY], &l_index); index += SIGNBY + signer_length; /* * For each record of data, copy in the envelope & the lower cased rdata */ for (curr_rr = rr_set->rrs_data; curr_rr; curr_rr = curr_rr->rr_next) { if (curr_rr->rr_rdata == NULL) goto err; /* * Copy in the envelope information */ if (is_a_wildcard) { /* * Construct the original name */ u_char wcard_n[NS_MAXCDNAME]; u_char *np = lowered_owner_n; int i; size_t outer_len; for (i = 0; i < is_a_wildcard; i++) np += np[0] + 1; outer_len = wire_name_length(np); wcard_n[0] = (u_char) 1; wcard_n[1] = '*'; if ((outer_len + 2) > sizeof(wcard_n)) goto err; memcpy(&wcard_n[2], np, outer_len); if ((index + outer_len + 2) > *field_length) goto err; memcpy(&(*field)[index], wcard_n, outer_len + 2); index += outer_len + 2; } else { if ((index + owner_length) > *field_length) goto err; memcpy(&(*field)[index], lowered_owner_n, owner_length); index += owner_length; } if ((index + sizeof(u_int16_t) + sizeof(u_int16_t) + sizeof(u_int32_t)) > *field_length) goto err; memcpy(&(*field)[index], &type_n, sizeof(u_int16_t)); index += sizeof(u_int16_t); memcpy(&(*field)[index], &class_n, sizeof(u_int16_t)); index += sizeof(u_int16_t); memcpy(&(*field)[index], &ttl_n, sizeof(u_int32_t)); index += sizeof(u_int32_t); /* * Now the RR-specific info, the length and the data */ rdata_length_n = htons(curr_rr->rr_rdata_length); if ((index + sizeof(u_int16_t) + curr_rr->rr_rdata_length) > *field_length) goto err; memcpy(&(*field)[index], &rdata_length_n, sizeof(u_int16_t)); index += sizeof(u_int16_t); memcpy(&(*field)[index], curr_rr->rr_rdata, curr_rr->rr_rdata_length); index += curr_rr->rr_rdata_length; } *field_length = index; return VAL_NO_ERROR; err: FREE(*field); *field = NULL; *field_length = 0; return VAL_BAD_ARGUMENT; }
static int process_packet(val_context_t *context) { HEADER *query_header, *response_header; u_char *pos; int q_name_len, rc; u_int16_t type_h, class_h; struct sockaddr from; socklen_t from_len; u_char query[4096], response[4096]; int query_size, response_size; /* * get a packet */ from_len = sizeof(from); memset(&from, 0x0, sizeof(from)); do { rc = recvfrom(listen_fd, query, sizeof(query), 0, &from, &from_len); if (rc < 0 && errno != EINTR) { // xxx-rks: log err msg break; } } while (rc < 0); if (rc < 0) return rc; query_size = rc; if (query_size < (sizeof(HEADER) + 1)) return -1; query_header = (HEADER *) query; /* * get query name */ pos = &query[sizeof(HEADER)]; q_name_len = wire_name_length(pos); pos += q_name_len; /* * get class and type */ VAL_GET16(type_h, pos); VAL_GET16(class_h, pos); response_size = sizeof(response); get_results(context, "test", (char *)&query[sizeof(HEADER)], (int)class_h, (int)type_h, response, &response_size, 0); /* * check to see if we need a dummy response */ val_log(NULL, LOG_DEBUG, "XXX-RKS: handle no response"); if (0 == response_size) { // no response; generate dummy/nxdomain response? return 1; } response_header = (HEADER*)response; response_header->id = query_header->id; /* * send response */ do { rc = sendto(listen_fd, response, response_size, 0, &from, sizeof(from)); if (rc < 0 && errno != EINTR) { // xxx-rks: log err msg break; } } while (rc < 0); if (rc > 0) { val_log(NULL, LOG_DEBUG, "sent %d bytes", rc); } return 0; /* no error */ }
/* * Set the TSIG params for this name server * Format is: * name:alg:fudge:key */ int res_set_ns_tsig(struct name_server *ns, char *tsigstr) { struct ns_tsig *tsig = NULL; int rr_hlen, rr_rdatalen; char *name_s; char *fudge_s; char *key_s; const char *alg_s; int i; char *buf, *c, *n; if (ns == NULL || tsigstr == NULL) return SR_TS_CALL_ERROR; tsig = (struct ns_tsig *) MALLOC (sizeof(struct ns_tsig)); if (tsig == NULL) return SR_TS_FAIL; buf = strdup(tsigstr); if (buf == NULL) { FREE(tsig); return SR_TS_FAIL; } c = buf; /* Parse the tsig string */ name_s = c; if (!(n = strchr(c,':'))) { goto err; } *n = '\0'; c = n+1; alg_s = c; if (!(n = strchr(c,':'))) { goto err; } *n = '\0'; c = n+1; fudge_s = c; if (!(n = strchr(c,':'))) { goto err; } *n = '\0'; c = n+1; key_s = c; for(i = 0; name_s[i]; i++){ if (isupper(name_s[i])) name_s[i] = tolower(name_s[i]); } if (ns_name_pton(name_s, tsig->name_n, sizeof(tsig->name_n)) == -1) { goto err; } /* check for alg sanity */ if (!strcmp(alg_s, "")) { alg_s = TSIG_ALG_HMAC_MD5_STR; tsig->alg = TSIG_ALG_HMAC_MD5; tsig->mac_size = MD5_DIGEST_LENGTH; } else if (!strcmp(alg_s, TSIG_ALG_HMAC_MD5_STR)) { tsig->alg = TSIG_ALG_HMAC_MD5; tsig->mac_size = MD5_DIGEST_LENGTH; } else if (!strcmp(alg_s, TSIG_ALG_HMAC_SHA1_STR)) { tsig->alg = TSIG_ALG_HMAC_SHA1; tsig->mac_size = SHA_DIGEST_LENGTH; } else if (!strcmp(alg_s, TSIG_ALG_HMAC_SHA256_STR)) { tsig->alg = TSIG_ALG_HMAC_SHA256; tsig->mac_size = SHA256_DIGEST_LENGTH; } else { goto err; } for(i = 0; alg_s[i]; i++){ if (isupper(alg_s[i])) name_s[i] = tolower(alg_s[i]); } if (ns_name_pton(alg_s, tsig->alg_n, sizeof(tsig->alg_n)) == -1) { goto err; } /* check for fudge sanity */ if (0 == (tsig->fudge = (u_int16_t)atoi(fudge_s))) { tsig->fudge = TSIG_FUDGE_DEFAULT; } /* Decode the base64 key */ tsig->key = (u_char *) MALLOC (strlen(key_s)+1); if (tsig->key == NULL) { goto err; } if ((tsig->keylen = decode_tsig_key(key_s, tsig->key, strlen(key_s))) <= 0) { FREE(tsig->key); goto err; } rr_hlen = wire_name_length(tsig->name_n) + /*Name*/ sizeof(u_int16_t) + /*type*/ sizeof(u_int16_t) + /*class*/ sizeof(u_int32_t); /*ttl*/ rr_rdatalen = wire_name_length(tsig->alg_n) + /*alg*/ sizeof(u_int32_t) + sizeof(u_int16_t) + /*time signed is u_int48_t*/ sizeof(u_int16_t) + /*fudge*/ sizeof(u_int16_t) + /*mac size*/ tsig->mac_size + /*mac*/ sizeof(u_int16_t) + /*original ID*/ sizeof(u_int16_t) + /*error*/ sizeof(u_int16_t) ; /*other len*/ tsig->rdatalen = rr_rdatalen; tsig->buf_size = rr_hlen + sizeof(u_int16_t) + rr_rdatalen; ns->ns_tsig = tsig; ns->ns_security_options |= ZONE_USE_TSIG; free(buf); return SR_TS_OK; err: free(buf); FREE(tsig); return SR_TS_FAIL; }
int res_tsig_sign(u_char * query, size_t query_length, struct name_server *ns, u_char ** signed_query, size_t *signed_length) { int buflen; u_char *cp, *p; u_char *hp; HEADER *header; struct timeval now; HMAC_CTX *ctx; const EVP_MD *md; u_char hash[MAX_DIGEST_LENGTH]; unsigned int len; u_int16_t arcount; if (!signed_query || !signed_length) return SR_TS_FAIL; *signed_query = NULL; *signed_length = 0; if (query && query_length && query_length > sizeof(HEADER)) { if (!(ns->ns_security_options & ZONE_USE_TSIG)) { *signed_query = (u_char *) MALLOC(query_length * sizeof(u_char)); if (*signed_query == NULL) return SR_TS_FAIL; memcpy(*signed_query, query, query_length * sizeof(u_char)); *signed_length = query_length; return SR_TS_OK; } else if (!ns->ns_tsig) { return SR_TS_FAIL; } switch(ns->ns_tsig->alg) { case TSIG_ALG_HMAC_MD5: md = EVP_md5(); break; case TSIG_ALG_HMAC_SHA1: md = EVP_sha1(); break; case TSIG_ALG_HMAC_SHA256: md = EVP_sha256(); break; default: return SR_TS_FAIL; } ctx = HMAC_CTX_new(); HMAC_Init_ex(ctx, ns->ns_tsig->key, ns->ns_tsig->keylen, md, NULL); /* Create a TSIG RR and add it to the additional section */ buflen = query_length + ns->ns_tsig->buf_size; *signed_query = (u_char *) MALLOC(buflen * sizeof(u_char)); if (*signed_query == NULL) return SR_TS_FAIL; *signed_length = buflen; cp = *signed_query; p = cp; memcpy(cp, query, query_length * sizeof(u_char)); cp += query_length; HMAC_Update(ctx, p, cp-p); /* Bump up the additional section count */ header = (HEADER *) p; arcount = ntohs(header->arcount); arcount++; header->arcount = htons(arcount);; p = cp; memcpy(cp, ns->ns_tsig->name_n, wire_name_length(ns->ns_tsig->name_n)); cp += wire_name_length(ns->ns_tsig->name_n); HMAC_Update(ctx, p, cp-p); /* don't digest type */ RES_PUT16(ns_t_tsig, cp); p = cp; RES_PUT16(ns_t_any, cp); RES_PUT32(0, cp); HMAC_Update(ctx, p, cp-p); /* don't digest rdatalen */ RES_PUT16(ns->ns_tsig->rdatalen, cp); p = cp; memcpy(cp, ns->ns_tsig->alg_n, wire_name_length(ns->ns_tsig->alg_n)); cp += wire_name_length(ns->ns_tsig->alg_n); HMAC_Update(ctx, p, cp-p); gettimeofday(&now, NULL); p = cp; RES_PUT48((u_int64_t)now.tv_sec, cp); RES_PUT16(ns->ns_tsig->fudge, cp); HMAC_Update(ctx, p, cp-p); /* don't digest the mac_size */ RES_PUT16(ns->ns_tsig->mac_size, cp); /* save the location for the hmac */ hp = cp; cp += ns->ns_tsig->mac_size; /* don't digest the header ID */ RES_PUT16(ntohs(header->id), cp); p = cp; RES_PUT16(0, cp); RES_PUT16(0, cp); HMAC_Update(ctx, p, cp-p); HMAC_Final(ctx, hash, &len); if (len != ns->ns_tsig->mac_size) { FREE(*signed_query); *signed_query = NULL; return SR_TS_FAIL; } memcpy(hp, hash, len); HMAC_CTX_free(ctx); return SR_TS_OK; } else return SR_TS_CALL_ERROR; }