1 /* 2 * tsig.c 3 * 4 * contains the functions needed for TSIG [RFC2845] 5 * 6 * (c) 2005-2006 NLnet Labs 7 * See the file LICENSE for the license 8 */ 9 10 #include <ldns/config.h> 11 12 #include <ldns/ldns.h> 13 14 #include <strings.h> 15 16 #ifdef HAVE_SSL 17 #include <openssl/hmac.h> 18 #include <openssl/md5.h> 19 #endif /* HAVE_SSL */ 20 21 char * 22 ldns_tsig_algorithm(ldns_tsig_credentials *tc) 23 { 24 return tc->algorithm; 25 } 26 27 char * 28 ldns_tsig_keyname(ldns_tsig_credentials *tc) 29 { 30 return tc->keyname; 31 } 32 33 char * 34 ldns_tsig_keydata(ldns_tsig_credentials *tc) 35 { 36 return tc->keydata; 37 } 38 39 char * 40 ldns_tsig_keyname_clone(ldns_tsig_credentials *tc) 41 { 42 return strdup(tc->keyname); 43 } 44 45 char * 46 ldns_tsig_keydata_clone(ldns_tsig_credentials *tc) 47 { 48 return strdup(tc->keydata); 49 } 50 51 /* 52 * Makes an exact copy of the wire, but with the tsig rr removed 53 */ 54 uint8_t * 55 ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len) 56 { 57 uint8_t *wire2 = NULL; 58 uint16_t qd_count; 59 uint16_t an_count; 60 uint16_t ns_count; 61 uint16_t ar_count; 62 ldns_rr *rr; 63 64 size_t pos; 65 uint16_t i; 66 67 ldns_status status; 68 69 /* fake parse the wire */ 70 qd_count = LDNS_QDCOUNT(wire); 71 an_count = LDNS_ANCOUNT(wire); 72 ns_count = LDNS_NSCOUNT(wire); 73 ar_count = LDNS_ARCOUNT(wire); 74 75 if (ar_count > 0) { 76 ar_count--; 77 } else { 78 return NULL; 79 } 80 81 pos = LDNS_HEADER_SIZE; 82 83 for (i = 0; i < qd_count; i++) { 84 status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION); 85 if (status != LDNS_STATUS_OK) { 86 return NULL; 87 } 88 ldns_rr_free(rr); 89 } 90 91 for (i = 0; i < an_count; i++) { 92 status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER); 93 if (status != LDNS_STATUS_OK) { 94 return NULL; 95 } 96 ldns_rr_free(rr); 97 } 98 99 for (i = 0; i < ns_count; i++) { 100 status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY); 101 if (status != LDNS_STATUS_OK) { 102 return NULL; 103 } 104 ldns_rr_free(rr); 105 } 106 107 for (i = 0; i < ar_count; i++) { 108 status = ldns_wire2rr(&rr, wire, wire_len, &pos, 109 LDNS_SECTION_ADDITIONAL); 110 if (status != LDNS_STATUS_OK) { 111 return NULL; 112 } 113 ldns_rr_free(rr); 114 } 115 116 *result_len = pos; 117 wire2 = LDNS_XMALLOC(uint8_t, *result_len); 118 memcpy(wire2, wire, *result_len); 119 120 ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count); 121 122 return wire2; 123 } 124 125 #ifdef HAVE_SSL 126 static const EVP_MD * 127 ldns_digest_function(char *name) 128 { 129 /* these are the mandatory algorithms from RFC4635 */ 130 /* The optional algorithms are not yet implemented */ 131 if (strlen(name) == 12 && strncasecmp(name, "hmac-sha256.", 11) == 0) { 132 #ifdef HAVE_EVP_SHA256 133 return EVP_sha256(); 134 #else 135 return NULL; 136 #endif 137 } else if (strlen(name) == 10 && strncasecmp(name, "hmac-sha1.", 9) == 0) 138 return EVP_sha1(); 139 else if (strlen(name) == 25 && strncasecmp(name, 140 "hmac-md5.sig-alg.reg.int.", 25) == 0) 141 return EVP_md5(); 142 else 143 return NULL; 144 } 145 #endif 146 147 #ifdef HAVE_SSL 148 static ldns_status 149 ldns_tsig_mac_new(ldns_rdf **tsig_mac, uint8_t *pkt_wire, size_t pkt_wire_size, 150 const char *key_data, ldns_rdf *key_name_rdf, ldns_rdf *fudge_rdf, 151 ldns_rdf *algorithm_rdf, ldns_rdf *time_signed_rdf, ldns_rdf *error_rdf, 152 ldns_rdf *other_data_rdf, ldns_rdf *orig_mac_rdf, int tsig_timers_only) 153 { 154 char *wireformat; 155 int wiresize; 156 unsigned char *mac_bytes; 157 unsigned char *key_bytes; 158 int key_size; 159 const EVP_MD *digester; 160 char *algorithm_name; 161 unsigned int md_len = EVP_MAX_MD_SIZE; 162 ldns_rdf *result = NULL; 163 ldns_buffer *data_buffer = NULL; 164 165 /* 166 * prepare the digestable information 167 */ 168 data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 169 if(!data_buffer) { 170 return LDNS_STATUS_MEM_ERR; 171 } 172 /* if orig_mac is not NULL, add it too */ 173 if (orig_mac_rdf) { 174 (void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf); 175 } 176 ldns_buffer_write(data_buffer, pkt_wire, pkt_wire_size); 177 if (!tsig_timers_only) { 178 (void)ldns_rdf2buffer_wire(data_buffer, key_name_rdf); 179 ldns_buffer_write_u16(data_buffer, LDNS_RR_CLASS_ANY); 180 ldns_buffer_write_u32(data_buffer, 0); 181 (void)ldns_rdf2buffer_wire(data_buffer, algorithm_rdf); 182 } 183 (void)ldns_rdf2buffer_wire(data_buffer, time_signed_rdf); 184 (void)ldns_rdf2buffer_wire(data_buffer, fudge_rdf); 185 if (!tsig_timers_only) { 186 (void)ldns_rdf2buffer_wire(data_buffer, error_rdf); 187 (void)ldns_rdf2buffer_wire(data_buffer, other_data_rdf); 188 } 189 190 wireformat = (char *) data_buffer->_data; 191 wiresize = (int) ldns_buffer_position(data_buffer); 192 193 algorithm_name = ldns_rdf2str(algorithm_rdf); 194 if(!algorithm_name) { 195 ldns_buffer_free(data_buffer); 196 return LDNS_STATUS_MEM_ERR; 197 } 198 199 /* prepare the key */ 200 key_bytes = LDNS_XMALLOC(unsigned char, 201 ldns_b64_pton_calculate_size(strlen(key_data))); 202 if(!key_bytes) { 203 LDNS_FREE(algorithm_name); 204 ldns_buffer_free(data_buffer); 205 return LDNS_STATUS_MEM_ERR; 206 } 207 key_size = ldns_b64_pton(key_data, key_bytes, 208 ldns_b64_pton_calculate_size(strlen(key_data))); 209 if (key_size < 0) { 210 LDNS_FREE(algorithm_name); 211 LDNS_FREE(key_bytes); 212 ldns_buffer_free(data_buffer); 213 /* LDNS_STATUS_INVALID_B64 */ 214 return LDNS_STATUS_INVALID_B64; 215 } 216 /* hmac it */ 217 /* 2 spare bytes for the length */ 218 mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2); 219 if(!mac_bytes) { 220 LDNS_FREE(algorithm_name); 221 LDNS_FREE(key_bytes); 222 ldns_buffer_free(data_buffer); 223 return LDNS_STATUS_MEM_ERR; 224 } 225 memset(mac_bytes, 0, md_len+2); 226 227 digester = ldns_digest_function(algorithm_name); 228 229 if (digester) { 230 (void) HMAC(digester, key_bytes, key_size, (void *)wireformat, 231 (size_t) wiresize, mac_bytes + 2, &md_len); 232 233 ldns_write_uint16(mac_bytes, md_len); 234 result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2, 235 mac_bytes); 236 } else { 237 LDNS_FREE(algorithm_name); 238 LDNS_FREE(mac_bytes); 239 LDNS_FREE(key_bytes); 240 ldns_buffer_free(data_buffer); 241 return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO; 242 } 243 244 LDNS_FREE(algorithm_name); 245 LDNS_FREE(mac_bytes); 246 LDNS_FREE(key_bytes); 247 ldns_buffer_free(data_buffer); 248 249 *tsig_mac = result; 250 251 return LDNS_STATUS_OK; 252 } 253 #endif /* HAVE_SSL */ 254 255 256 #ifdef HAVE_SSL 257 bool 258 ldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char *key_name, 259 const char *key_data, ldns_rdf *orig_mac_rdf) 260 { 261 return ldns_pkt_tsig_verify_next(pkt, wire, wirelen, key_name, key_data, orig_mac_rdf, 0); 262 } 263 264 bool 265 ldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char* key_name, 266 const char *key_data, ldns_rdf *orig_mac_rdf, int tsig_timers_only) 267 { 268 ldns_rdf *fudge_rdf; 269 ldns_rdf *algorithm_rdf; 270 ldns_rdf *time_signed_rdf; 271 ldns_rdf *orig_id_rdf; 272 ldns_rdf *error_rdf; 273 ldns_rdf *other_data_rdf; 274 ldns_rdf *pkt_mac_rdf; 275 ldns_rdf *my_mac_rdf; 276 ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); 277 uint16_t pkt_id, orig_pkt_id; 278 ldns_status status; 279 280 uint8_t *prepared_wire = NULL; 281 size_t prepared_wire_size = 0; 282 283 ldns_rr *orig_tsig = ldns_pkt_tsig(pkt); 284 285 if (!orig_tsig) { 286 ldns_rdf_deep_free(key_name_rdf); 287 return false; 288 } 289 algorithm_rdf = ldns_rr_rdf(orig_tsig, 0); 290 time_signed_rdf = ldns_rr_rdf(orig_tsig, 1); 291 fudge_rdf = ldns_rr_rdf(orig_tsig, 2); 292 pkt_mac_rdf = ldns_rr_rdf(orig_tsig, 3); 293 orig_id_rdf = ldns_rr_rdf(orig_tsig, 4); 294 error_rdf = ldns_rr_rdf(orig_tsig, 5); 295 other_data_rdf = ldns_rr_rdf(orig_tsig, 6); 296 297 /* remove temporarily */ 298 ldns_pkt_set_tsig(pkt, NULL); 299 /* temporarily change the id to the original id */ 300 pkt_id = ldns_pkt_id(pkt); 301 orig_pkt_id = ldns_rdf2native_int16(orig_id_rdf); 302 ldns_pkt_set_id(pkt, orig_pkt_id); 303 304 prepared_wire = ldns_tsig_prepare_pkt_wire(wire, wirelen, &prepared_wire_size); 305 306 status = ldns_tsig_mac_new(&my_mac_rdf, prepared_wire, prepared_wire_size, 307 key_data, key_name_rdf, fudge_rdf, algorithm_rdf, 308 time_signed_rdf, error_rdf, other_data_rdf, orig_mac_rdf, tsig_timers_only); 309 310 LDNS_FREE(prepared_wire); 311 312 if (status != LDNS_STATUS_OK) { 313 ldns_rdf_deep_free(key_name_rdf); 314 return false; 315 } 316 /* Put back the values */ 317 ldns_pkt_set_tsig(pkt, orig_tsig); 318 ldns_pkt_set_id(pkt, pkt_id); 319 320 ldns_rdf_deep_free(key_name_rdf); 321 322 if (ldns_rdf_compare(pkt_mac_rdf, my_mac_rdf) == 0) { 323 ldns_rdf_deep_free(my_mac_rdf); 324 return true; 325 } else { 326 ldns_rdf_deep_free(my_mac_rdf); 327 return false; 328 } 329 } 330 #endif /* HAVE_SSL */ 331 332 #ifdef HAVE_SSL 333 /* TODO: memory :p */ 334 ldns_status 335 ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, 336 uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac) 337 { 338 return ldns_pkt_tsig_sign_next(pkt, key_name, key_data, fudge, algorithm_name, query_mac, 0); 339 } 340 341 ldns_status 342 ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, 343 uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only) 344 { 345 ldns_rr *tsig_rr; 346 ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); 347 ldns_rdf *fudge_rdf = NULL; 348 ldns_rdf *orig_id_rdf = NULL; 349 ldns_rdf *algorithm_rdf; 350 ldns_rdf *error_rdf = NULL; 351 ldns_rdf *mac_rdf = NULL; 352 ldns_rdf *other_data_rdf = NULL; 353 354 ldns_status status = LDNS_STATUS_OK; 355 356 uint8_t *pkt_wire = NULL; 357 size_t pkt_wire_len; 358 359 struct timeval tv_time_signed; 360 uint8_t *time_signed = NULL; 361 ldns_rdf *time_signed_rdf = NULL; 362 363 algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name); 364 365 /* eww don't have create tsigtime rdf yet :( */ 366 /* bleh :p */ 367 if (gettimeofday(&tv_time_signed, NULL) == 0) { 368 time_signed = LDNS_XMALLOC(uint8_t, 6); 369 ldns_write_uint64_as_uint48(time_signed, 370 (uint64_t)tv_time_signed.tv_sec); 371 } else { 372 status = LDNS_STATUS_INTERNAL_ERR; 373 goto clean; 374 } 375 376 time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed); 377 378 fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge); 379 380 orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt)); 381 382 error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0); 383 384 other_data_rdf = ldns_native2rdf_int16_data(0, NULL); 385 386 if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) { 387 status = LDNS_STATUS_ERR; 388 goto clean; 389 } 390 391 status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len, 392 key_data, key_name_rdf, fudge_rdf, algorithm_rdf, 393 time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only); 394 395 if (!mac_rdf) { 396 goto clean; 397 } 398 399 LDNS_FREE(pkt_wire); 400 401 /* Create the TSIG RR */ 402 tsig_rr = ldns_rr_new(); 403 ldns_rr_set_owner(tsig_rr, key_name_rdf); 404 ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY); 405 ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG); 406 ldns_rr_set_ttl(tsig_rr, 0); 407 408 ldns_rr_push_rdf(tsig_rr, algorithm_rdf); 409 ldns_rr_push_rdf(tsig_rr, time_signed_rdf); 410 ldns_rr_push_rdf(tsig_rr, fudge_rdf); 411 ldns_rr_push_rdf(tsig_rr, mac_rdf); 412 ldns_rr_push_rdf(tsig_rr, orig_id_rdf); 413 ldns_rr_push_rdf(tsig_rr, error_rdf); 414 ldns_rr_push_rdf(tsig_rr, other_data_rdf); 415 416 ldns_pkt_set_tsig(pkt, tsig_rr); 417 418 return status; 419 420 clean: 421 ldns_rdf_free(key_name_rdf); 422 ldns_rdf_free(algorithm_rdf); 423 ldns_rdf_free(time_signed_rdf); 424 ldns_rdf_free(fudge_rdf); 425 ldns_rdf_free(orig_id_rdf); 426 ldns_rdf_free(error_rdf); 427 ldns_rdf_free(other_data_rdf); 428 return status; 429 } 430 #endif /* HAVE_SSL */ 431