1 1.1 christos /* towire.c 2 1.1 christos * 3 1.1 christos * Copyright (c) 2018-2021 Apple, Inc. All rights reserved. 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License"); 6 1.1 christos * you may not use this file except in compliance with the License. 7 1.1 christos * You may obtain a copy of the License at 8 1.1 christos * 9 1.1 christos * http://www.apache.org/licenses/LICENSE-2.0 10 1.1 christos * 11 1.1 christos * Unless required by applicable law or agreed to in writing, software 12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS, 13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 1.1 christos * See the License for the specific language governing permissions and 15 1.1 christos * limitations under the License. 16 1.1 christos * 17 1.1 christos * DNS to-wire wire-format functions. 18 1.1 christos * 19 1.1 christos * These are really simple functions for constructing DNS messages in wire format. 20 1.1 christos * The flow is that there is a transaction structure which contains pointers to both 21 1.1 christos * a message output buffer and a response input buffer. The structure is initialized, 22 1.1 christos * and then the various wire format functions are called repeatedly to store data. 23 1.1 christos * If an error occurs during this process, it's okay to just keep going, because the 24 1.1 christos * error is recorded in the transaction; once all of the copy-in functions have been 25 1.1 christos * called, the error status can be checked once at the end. 26 1.1 christos */ 27 1.1 christos 28 1.1 christos #include <stdio.h> 29 1.1 christos #include <unistd.h> 30 1.1 christos #include <string.h> 31 1.1 christos #include <errno.h> 32 1.1 christos #ifndef THREAD_DEVKIT_ADK 33 1.1 christos #include <arpa/inet.h> 34 1.1 christos #endif 35 1.1 christos #include <stdlib.h> 36 1.1 christos 37 1.1 christos #include "srp.h" 38 1.1 christos #include "dns-msg.h" 39 1.1 christos #include "srp-crypto.h" 40 1.1 christos 41 1.1 christos #ifndef NO_CLOCK 42 1.1 christos #include <sys/time.h> 43 1.1 christos #endif 44 1.1 christos 45 1.1 christos static int 46 1.1 christos dns_parse_label(const char *cur, const char *NONNULL *NONNULL nextp, uint8_t *NONNULL lenp, uint8_t *NONNULL buf, 47 1.1 christos ssize_t max) 48 1.1 christos { 49 1.1 christos const char *end; 50 1.1 christos int tlen; 51 1.1 christos const char *s; 52 1.1 christos uint8_t *t; 53 1.1 christos 54 1.1 christos end = strchr(cur, '.'); 55 1.1 christos if (end == NULL) { 56 1.1 christos end = cur + strlen(cur); 57 1.1 christos if (end == cur) { 58 1.1 christos *lenp = 0; 59 1.1 christos *nextp = NULL; 60 1.1 christos return 0; 61 1.1 christos } 62 1.1 christos *nextp = NULL; 63 1.1 christos } else { 64 1.1 christos if (end == cur) { 65 1.1 christos return EINVAL; 66 1.1 christos } 67 1.1 christos *nextp = end + 1; 68 1.1 christos } 69 1.1 christos 70 1.1 christos // Figure out the length of the label after escapes have been converted. 71 1.1 christos tlen = 0; 72 1.1 christos for (s = cur; s < end; s++) { 73 1.1 christos if (*s == '\\') { 74 1.1 christos if (s + 4 <= end) { 75 1.1 christos tlen++; 76 1.1 christos s += 3; 77 1.1 christos } else { 78 1.1 christos tlen++; 79 1.1 christos } 80 1.1 christos } else { 81 1.1 christos tlen++; 82 1.1 christos } 83 1.1 christos } 84 1.1 christos 85 1.1 christos // Is there no space? 86 1.1 christos 87 1.1 christos if (tlen >= max) { 88 1.1 christos return ENOBUFS; 89 1.1 christos } 90 1.1 christos 91 1.1 christos // Is the label too long? 92 1.1 christos if (end - cur > DNS_MAX_LABEL_SIZE) { 93 1.1 christos return ENAMETOOLONG; 94 1.1 christos } 95 1.1 christos 96 1.1 christos // Store the label length 97 1.1 christos *lenp = (uint8_t)(tlen); 98 1.1 christos 99 1.1 christos // Store the label. 100 1.1 christos t = buf; 101 1.1 christos for (s = cur; s < end; s++) { 102 1.1 christos if (*s == '\\') { 103 1.1 christos if (s + 4 <= end) { 104 1.1 christos int v0 = s[1] - '0'; 105 1.1 christos int v1 = s[2] - '0'; 106 1.1 christos int v2 = s[3] - '0'; 107 1.1 christos int val = v0 * 100 + v1 * 10 + v2; 108 1.1 christos if (val < 255) { 109 1.1 christos *t++ = (uint8_t)val; 110 1.1 christos s += 3; 111 1.1 christos } else { 112 1.1 christos return EINVAL; 113 1.1 christos } 114 1.1 christos } else { 115 1.1 christos return EINVAL; 116 1.1 christos } 117 1.1 christos } else { 118 1.1 christos *t++ = (uint8_t)*s; 119 1.1 christos } 120 1.1 christos } 121 1.1 christos return 0; 122 1.1 christos } 123 1.1 christos 124 1.1 christos // Convert a name to wire format. Does not store the root label (0) at the end. Does not support binary labels. 125 1.1 christos void 126 1.1 christos dns_name_to_wire_(dns_name_pointer_t *NULLABLE r_pointer, dns_towire_state_t *NONNULL txn, 127 1.1 christos const char *NONNULL name, int line) 128 1.1 christos { 129 1.1 christos const char *next, *cur; 130 1.1 christos int status; 131 1.1 christos dns_name_pointer_t np; 132 1.1 christos 133 1.1 christos if (!txn->error) { 134 1.1 christos memset(&np, 0, sizeof np); 135 1.1 christos np.message_start = (uint8_t *)txn->message; 136 1.1 christos np.name_start = txn->p; 137 1.1 christos 138 1.1 christos cur = name; 139 1.1 christos do { 140 1.1 christos // Note that nothing is stored through txn->p until dns_name_parse has verified that 141 1.1 christos // there is space in the buffer for the label as well as the length. 142 1.1 christos status = dns_parse_label(cur, &next, txn->p, txn->p + 1, txn->lim - txn->p - 1); 143 1.1 christos if (status) { 144 1.1 christos if (status == ENOBUFS) { 145 1.1 christos txn->truncated = true; 146 1.1 christos } 147 1.1 christos txn->error = (unsigned)status; 148 1.1 christos txn->line = line; 149 1.1 christos return; 150 1.1 christos } 151 1.1 christos 152 1.1 christos // Don't use the root label if it was parsed. 153 1.1 christos if (*txn->p != 0) { 154 1.1 christos np.num_labels++; 155 1.1 christos np.length += 1 + *txn->p; 156 1.1 christos txn->p = txn->p + *txn->p + 1; 157 1.1 christos cur = next; 158 1.1 christos } 159 1.1 christos } while (next != NULL); 160 1.1 christos 161 1.1 christos if (np.length > DNS_MAX_NAME_SIZE) { 162 1.1 christos txn->error = ENAMETOOLONG; 163 1.1 christos txn->line = line; 164 1.1 christos return; 165 1.1 christos } 166 1.1 christos if (r_pointer != NULL) { 167 1.1 christos *r_pointer = np; 168 1.1 christos } 169 1.1 christos } 170 1.1 christos } 171 1.1 christos 172 1.1 christos // Like dns_name_to_wire, but includes the root label at the end. 173 1.1 christos void 174 1.1 christos dns_full_name_to_wire_(dns_name_pointer_t *NULLABLE r_pointer, dns_towire_state_t *NONNULL txn, 175 1.1 christos const char *NONNULL name, int line) 176 1.1 christos { 177 1.1 christos dns_name_pointer_t np; 178 1.1 christos if (!txn->error) { 179 1.1 christos memset(&np, 0, sizeof np); 180 1.1 christos dns_name_to_wire(&np, txn, name); 181 1.1 christos if (!txn->error) { 182 1.1 christos if (txn->p + 1 >= txn->lim) { 183 1.1 christos txn->error = ENOBUFS; 184 1.1 christos txn->truncated = true; 185 1.1 christos txn->line = line; 186 1.1 christos return; 187 1.1 christos } 188 1.1 christos *txn->p++ = 0; 189 1.1 christos np.num_labels++; 190 1.1 christos np.length += 1; 191 1.1 christos if (np.length > DNS_MAX_NAME_SIZE) { 192 1.1 christos txn->error = ENAMETOOLONG; 193 1.1 christos txn->line = line; 194 1.1 christos return; 195 1.1 christos } 196 1.1 christos if (r_pointer) { 197 1.1 christos *r_pointer = np; 198 1.1 christos } 199 1.1 christos } 200 1.1 christos } 201 1.1 christos } 202 1.1 christos 203 1.1 christos // Store a pointer to a name that's already in the message. 204 1.1 christos void 205 1.1 christos dns_pointer_to_wire_(dns_name_pointer_t *NULLABLE r_pointer, dns_towire_state_t *NONNULL txn, 206 1.1 christos dns_name_pointer_t *NONNULL pointer, int line) 207 1.1 christos { 208 1.1 christos if (!txn->error) { 209 1.1 christos uint16_t offset = (uint16_t)(pointer->name_start - pointer->message_start); 210 1.1 christos if (offset > DNS_MAX_POINTER) { 211 1.1 christos txn->error = ETOOMANYREFS; 212 1.1 christos txn->line = line; 213 1.1 christos return; 214 1.1 christos } 215 1.1 christos if (txn->p + 2 >= txn->lim) { 216 1.1 christos txn->error = ENOBUFS; 217 1.1 christos txn->truncated = true; 218 1.1 christos txn->line = line; 219 1.1 christos return; 220 1.1 christos } 221 1.1 christos *txn->p++ = 0xc0 | (offset >> 8); 222 1.1 christos *txn->p++ = offset & 0xff; 223 1.1 christos if (r_pointer) { 224 1.1 christos r_pointer->num_labels += pointer->num_labels; 225 1.1 christos r_pointer->length += pointer->length + 1; 226 1.1 christos if (r_pointer->length > DNS_MAX_NAME_SIZE) { 227 1.1 christos txn->error = ENAMETOOLONG; 228 1.1 christos txn->line = line; 229 1.1 christos return; 230 1.1 christos } 231 1.1 christos } 232 1.1 christos } 233 1.1 christos } 234 1.1 christos 235 1.1 christos void 236 1.1 christos dns_u8_to_wire_(dns_towire_state_t *NONNULL txn, uint8_t val, int line) 237 1.1 christos { 238 1.1 christos if (!txn->error) { 239 1.1 christos if (txn->p + 1 >= txn->lim) { 240 1.1 christos txn->error = ENOBUFS; 241 1.1 christos txn->truncated = true; 242 1.1 christos txn->line = line; 243 1.1 christos return; 244 1.1 christos } 245 1.1 christos *txn->p++ = val; 246 1.1 christos } 247 1.1 christos } 248 1.1 christos 249 1.1 christos // Store a 16-bit integer in network byte order 250 1.1 christos void 251 1.1 christos dns_u16_to_wire_(dns_towire_state_t *NONNULL txn, uint16_t val, int line) 252 1.1 christos { 253 1.1 christos if (!txn->error) { 254 1.1 christos if (txn->p + 2 >= txn->lim) { 255 1.1 christos txn->error = ENOBUFS; 256 1.1 christos txn->truncated = true; 257 1.1 christos txn->line = line; 258 1.1 christos return; 259 1.1 christos } 260 1.1 christos *txn->p++ = val >> 8; 261 1.1 christos *txn->p++ = val & 0xff; 262 1.1 christos } 263 1.1 christos } 264 1.1 christos 265 1.1 christos void 266 1.1 christos dns_u32_to_wire_(dns_towire_state_t *NONNULL txn, uint32_t val, int line) 267 1.1 christos { 268 1.1 christos if (!txn->error) { 269 1.1 christos if (txn->p + 4 >= txn->lim) { 270 1.1 christos txn->error = ENOBUFS; 271 1.1 christos txn->truncated = true; 272 1.1 christos txn->line = line; 273 1.1 christos return; 274 1.1 christos } 275 1.1 christos *txn->p++ = val >> 24; 276 1.1 christos *txn->p++ = (val >> 16) & 0xff; 277 1.1 christos *txn->p++ = (val >> 8) & 0xff; 278 1.1 christos *txn->p++ = val & 0xff; 279 1.1 christos } 280 1.1 christos } 281 1.1 christos 282 1.1 christos void 283 1.1 christos dns_u64_to_wire_(dns_towire_state_t *NONNULL txn, uint64_t val, int line) 284 1.1 christos { 285 1.1 christos if (!txn->error) { 286 1.1 christos if (txn->p + 8 >= txn->lim) { 287 1.1 christos txn->error = ENOBUFS; 288 1.1 christos txn->truncated = true; 289 1.1 christos txn->line = line; 290 1.1 christos return; 291 1.1 christos } 292 1.1 christos *txn->p++ = val >> 56; 293 1.1 christos *txn->p++ = (val >> 48) & 0xff; 294 1.1 christos *txn->p++ = (val >> 40) & 0xff; 295 1.1 christos *txn->p++ = (val >> 32) & 0xff; 296 1.1 christos *txn->p++ = (val >> 24) & 0xff; 297 1.1 christos *txn->p++ = (val >> 16) & 0xff; 298 1.1 christos *txn->p++ = (val >> 8) & 0xff; 299 1.1 christos *txn->p++ = val & 0xff; 300 1.1 christos } 301 1.1 christos } 302 1.1 christos 303 1.1 christos void 304 1.1 christos dns_ttl_to_wire_(dns_towire_state_t *NONNULL txn, int32_t val, int line) 305 1.1 christos { 306 1.1 christos if (!txn->error) { 307 1.1 christos dns_u32_to_wire_(txn, (uint32_t)val, line); 308 1.1 christos } 309 1.1 christos } 310 1.1 christos 311 1.1 christos void 312 1.1 christos dns_rdlength_begin_(dns_towire_state_t *NONNULL txn, int line) 313 1.1 christos { 314 1.1 christos if (!txn->error) { 315 1.1 christos if (txn->p + 2 >= txn->lim) { 316 1.1 christos txn->error = ENOBUFS; 317 1.1 christos txn->truncated = true; 318 1.1 christos txn->line = line; 319 1.1 christos return; 320 1.1 christos } 321 1.1 christos if (txn->p_rdlength != NULL) { 322 1.1 christos txn->error = EINVAL; 323 1.1 christos txn->line = line; 324 1.1 christos return; 325 1.1 christos } 326 1.1 christos txn->p_rdlength = txn->p; 327 1.1 christos txn->p += 2; 328 1.1 christos } 329 1.1 christos } 330 1.1 christos 331 1.1 christos void 332 1.1 christos dns_rdlength_end_(dns_towire_state_t *NONNULL txn, int line) 333 1.1 christos { 334 1.1 christos ssize_t rdlength; 335 1.1 christos if (!txn->error) { 336 1.1 christos if (txn->p_rdlength == NULL) { 337 1.1 christos txn->error = EINVAL; 338 1.1 christos txn->line = line; 339 1.1 christos return; 340 1.1 christos } 341 1.1 christos rdlength = txn->p - txn->p_rdlength - 2; 342 1.1 christos txn->p_rdlength[0] = (uint8_t)(rdlength >> 8); 343 1.1 christos txn->p_rdlength[1] = (uint8_t)(rdlength & 0xff); 344 1.1 christos txn->p_rdlength = NULL; 345 1.1 christos } 346 1.1 christos } 347 1.1 christos 348 1.1 christos #ifndef THREAD_DEVKIT_ADK 349 1.1 christos void 350 1.1 christos dns_rdata_a_to_wire_(dns_towire_state_t *NONNULL txn, const char *NONNULL ip_address, int line) 351 1.1 christos { 352 1.1 christos if (!txn->error) { 353 1.1 christos if (txn->p + 4 >= txn->lim) { 354 1.1 christos txn->error = ENOBUFS; 355 1.1 christos txn->truncated = true; 356 1.1 christos txn->line = line; 357 1.1 christos return; 358 1.1 christos } 359 1.1 christos if (!inet_pton(AF_INET, ip_address, txn->p)) { 360 1.1 christos txn->error = EINVAL; 361 1.1 christos txn->line = line; 362 1.1 christos return; 363 1.1 christos } 364 1.1 christos txn->p += 4; 365 1.1 christos } 366 1.1 christos } 367 1.1 christos 368 1.1 christos void 369 1.1 christos dns_rdata_aaaa_to_wire_(dns_towire_state_t *NONNULL txn, const char *NONNULL ip_address, int line) 370 1.1 christos { 371 1.1 christos if (!txn->error) { 372 1.1 christos if (txn->p + 16 >= txn->lim) { 373 1.1 christos txn->error = ENOBUFS; 374 1.1 christos txn->truncated = true; 375 1.1 christos txn->line = line; 376 1.1 christos return; 377 1.1 christos } 378 1.1 christos if (!inet_pton(AF_INET6, ip_address, txn->p)) { 379 1.1 christos txn->error = EINVAL; 380 1.1 christos txn->line = line; 381 1.1 christos return; 382 1.1 christos } 383 1.1 christos txn->p += 16; 384 1.1 christos } 385 1.1 christos } 386 1.1 christos #endif 387 1.1 christos 388 1.1 christos uint16_t 389 1.1 christos dns_rdata_key_to_wire_(dns_towire_state_t *NONNULL txn, unsigned key_type, unsigned name_type, 390 1.1 christos uint8_t signatory, srp_key_t *key, int line) 391 1.1 christos { 392 1.1 christos size_t key_len = srp_pubkey_length(key), copied_len; 393 1.1 christos uint8_t *rdata = txn->p; 394 1.1 christos uint32_t key_tag; 395 1.1 christos int i; 396 1.1 christos ssize_t rdlen; 397 1.1 christos 398 1.1 christos if (!txn->error) { 399 1.1 christos if (key_type > 3 || name_type > 3 || signatory > 15) { 400 1.1 christos txn->error = EINVAL; 401 1.1 christos txn->line = line; 402 1.1 christos return 0; 403 1.1 christos } 404 1.1 christos if (txn->p + key_len + 4 >= txn->lim) { 405 1.1 christos txn->error = ENOBUFS; 406 1.1 christos txn->truncated = true; 407 1.1 christos txn->line = line; 408 1.1 christos return 0; 409 1.1 christos } 410 1.1 christos *txn->p++ = (uint8_t)((key_type << 6) | name_type); 411 1.1 christos *txn->p++ = signatory; 412 1.1 christos *txn->p++ = 3; // protocol type is always 3 413 1.1 christos *txn->p++ = srp_key_algorithm(key); 414 1.1 christos copied_len = srp_pubkey_copy(txn->p, key_len, key); 415 1.1 christos if (copied_len == 0) { 416 1.1 christos txn->error = EINVAL; 417 1.1 christos txn->line = line; 418 1.1 christos return 0; 419 1.1 christos } 420 1.1 christos txn->p += key_len; 421 1.1 christos } 422 1.1 christos rdlen = txn->p - rdata; 423 1.1 christos 424 1.1 christos // Compute the key tag 425 1.1 christos key_tag = 0; 426 1.1 christos for (i = 0; i < rdlen; i++) { 427 1.1 christos key_tag += (i & 1) ? rdata[i] : (uint16_t)(rdata[i] << 8); 428 1.1 christos } 429 1.1 christos key_tag += (key_tag >> 16) & 0xFFFF; 430 1.1 christos return (uint16_t)(key_tag & 0xFFFF); 431 1.1 christos } 432 1.1 christos 433 1.1 christos void 434 1.1 christos dns_rdata_txt_to_wire_(dns_towire_state_t *NONNULL txn, const char *NONNULL txt_record, int line) 435 1.1 christos { 436 1.1 christos if (!txn->error) { 437 1.1 christos size_t len = strlen(txt_record); 438 1.1 christos if (txn->p + len + 1 >= txn->lim) { 439 1.1 christos txn->error = ENOBUFS; 440 1.1 christos txn->truncated = true; 441 1.1 christos txn->line = line; 442 1.1 christos return; 443 1.1 christos } 444 1.1 christos if (len > 255) { 445 1.1 christos txn->error = ENAMETOOLONG; 446 1.1 christos txn->line = line; 447 1.1 christos return; 448 1.1 christos } 449 1.1 christos *txn->p++ = (uint8_t)len; 450 1.1 christos memcpy(txn->p, txt_record, len); 451 1.1 christos txn->p += len; 452 1.1 christos } 453 1.1 christos } 454 1.1 christos 455 1.1 christos void 456 1.1 christos dns_rdata_raw_data_to_wire_(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length, int line) 457 1.1 christos { 458 1.1 christos if (!txn->error) { 459 1.1 christos if (txn->p + length > txn->lim) { 460 1.1 christos txn->error = ENOBUFS; 461 1.1 christos txn->truncated = true; 462 1.1 christos txn->line = line; 463 1.1 christos return; 464 1.1 christos } 465 1.1 christos memcpy(txn->p, raw_data, length); 466 1.1 christos txn->p += length; 467 1.1 christos } 468 1.1 christos } 469 1.1 christos 470 1.1 christos void 471 1.1 christos dns_edns0_header_to_wire_(dns_towire_state_t *NONNULL txn, uint16_t mtu, uint8_t xrcode, uint8_t version, bool DO, int line) 472 1.1 christos { 473 1.1 christos if (!txn->error) { 474 1.1 christos if (txn->p + 9 >= txn->lim) { 475 1.1 christos txn->error = ENOBUFS; 476 1.1 christos txn->truncated = true; 477 1.1 christos txn->line = line; 478 1.1 christos return; 479 1.1 christos } 480 1.1 christos *txn->p++ = 0; // root label 481 1.1 christos dns_u16_to_wire(txn, dns_rrtype_opt); 482 1.1 christos dns_u16_to_wire(txn, mtu); 483 1.1 christos *txn->p++ = xrcode; 484 1.1 christos *txn->p++ = version; 485 1.1 christos *txn->p++ = DO ? 1 << 7 : 0; // flags (usb) 486 1.1 christos *txn->p++ = 0; // flags (lsb, mbz) 487 1.1 christos } 488 1.1 christos } 489 1.1 christos 490 1.1 christos void 491 1.1 christos dns_edns0_option_begin_(dns_towire_state_t *NONNULL txn, int line) 492 1.1 christos { 493 1.1 christos if (!txn->error) { 494 1.1 christos if (txn->p + 2 >= txn->lim) { 495 1.1 christos txn->error = ENOBUFS; 496 1.1 christos txn->truncated = true; 497 1.1 christos txn->line = line; 498 1.1 christos return; 499 1.1 christos } 500 1.1 christos if (txn->p_opt != NULL) { 501 1.1 christos txn->error = EINVAL; 502 1.1 christos txn->line = line; 503 1.1 christos return; 504 1.1 christos } 505 1.1 christos txn->p_opt = txn->p; 506 1.1 christos txn->p += 2; 507 1.1 christos } 508 1.1 christos } 509 1.1 christos 510 1.1 christos void 511 1.1 christos dns_edns0_option_end_(dns_towire_state_t *NONNULL txn, int line) 512 1.1 christos { 513 1.1 christos ssize_t opt_length; 514 1.1 christos if (!txn->error) { 515 1.1 christos if (txn->p_opt == NULL) { 516 1.1 christos txn->error = EINVAL; 517 1.1 christos txn->line = line; 518 1.1 christos return; 519 1.1 christos } 520 1.1 christos opt_length = txn->p - txn->p_opt - 2; 521 1.1 christos txn->p_opt[0] = (uint8_t)(opt_length >> 8); 522 1.1 christos txn->p_opt[1] = opt_length & 0xff; 523 1.1 christos txn->p_opt = NULL; 524 1.1 christos } 525 1.1 christos } 526 1.1 christos 527 1.1 christos void 528 1.1 christos dns_sig0_signature_to_wire_(dns_towire_state_t *NONNULL txn, srp_key_t *key, uint16_t key_tag, 529 1.1 christos dns_name_pointer_t *NONNULL signer, const char *NONNULL signer_hostname, 530 1.1 christos const char *NONNULL signer_domain, uint32_t timenow, int line) 531 1.1 christos { 532 1.1 christos size_t siglen = srp_signature_length(key); 533 1.1 christos uint8_t *start, *p_signer, *p_signature, *rrstart = txn->p; 534 1.1 christos 535 1.1 christos // 1 name (root) 536 1.1 christos // 2 type (SIG) 537 1.1 christos // 2 class (255) ANY 538 1.1 christos // 4 TTL (0) 539 1.1 christos // 18 SIG RDATA up to signer name 540 1.1 christos // 2 signer name (always a pointer) 541 1.1 christos // 29 bytes so far 542 1.1 christos // signature data (depends on algorithm, e.g. 64 for ECDSASHA256) 543 1.1 christos // so e.g. 93 bytes total 544 1.1 christos 545 1.1 christos if (!txn->error) { 546 1.1 christos dns_u8_to_wire(txn, 0); // root label 547 1.1 christos dns_u16_to_wire(txn, dns_rrtype_sig); 548 1.1 christos dns_u16_to_wire(txn, dns_qclass_any); // class 549 1.1 christos dns_ttl_to_wire(txn, 0); // SIG RR TTL 550 1.1 christos dns_rdlength_begin(txn); 551 1.1 christos start = txn->p; 552 1.1 christos dns_u16_to_wire(txn, 0); // type = 0 for transaction signature 553 1.1 christos dns_u8_to_wire(txn, srp_key_algorithm(key)); 554 1.1 christos dns_u8_to_wire(txn, 0); // labels field doesn't apply for transaction signature 555 1.1 christos dns_ttl_to_wire(txn, 0); // original ttl doesn't apply 556 1.1 christos // If timenow is <300, it's either just after the epoch, or the caller doesn't know what time it is. 557 1.1 christos if (timenow < 300) { 558 1.1 christos dns_u32_to_wire(txn, 0); // Indicate that we have no clock: set expiry and inception times to zero 559 1.1 christos dns_u32_to_wire(txn, 0); 560 1.1 christos } else { 561 1.1 christos dns_u32_to_wire(txn, timenow + 300); // signature expiration time is five minutes from now 562 1.1 christos dns_u32_to_wire(txn, timenow - 300); // signature inception time, five minutes in the past 563 1.1 christos } 564 1.1 christos dns_u16_to_wire(txn, key_tag); 565 1.1 christos 566 1.1 christos p_signer = txn->p; 567 1.1 christos // We store the name in uncompressed form because that's what we have to sign 568 1.1 christos if (signer_hostname != NULL) { 569 1.1 christos dns_name_to_wire(NULL, txn, signer_hostname); 570 1.1 christos } 571 1.1 christos dns_full_name_to_wire(NULL, txn, signer_domain); 572 1.1 christos // And that means we're going to have to copy the signature back earlier in the packet. 573 1.1 christos p_signature = txn->p; 574 1.1 christos 575 1.1 christos // Sign the message, signature RRDATA (less signature) first. 576 1.1 christos if (!srp_sign(txn->p, siglen, (uint8_t *)txn->message, (size_t)(rrstart - (uint8_t *)txn->message), 577 1.1 christos start, (size_t)(txn->p - start), key)) { 578 1.1 christos txn->error = true; 579 1.1 christos txn->line = __LINE__; 580 1.1 christos } else { 581 1.1 christos // Now that it's signed, back up and store the pointer to the name, because we're trying 582 1.1 christos // to be as compact as possible. 583 1.1 christos txn->p = p_signer; 584 1.1 christos dns_pointer_to_wire(NULL, txn, signer); // Pointer to the owner name the key is attached to 585 1.1 christos // And move the signature earlier in the packet. 586 1.1 christos memmove(txn->p, p_signature, siglen); 587 1.1 christos 588 1.1 christos txn->p += siglen; 589 1.1 christos dns_rdlength_end(txn); 590 1.1 christos } 591 1.1 christos 592 1.1 christos if (txn->error) { 593 1.1 christos txn->outer_line = line; 594 1.1 christos } 595 1.1 christos } 596 1.1 christos } 597 1.1 christos 598 1.1 christos // Local Variables: 599 1.1 christos // mode: C 600 1.1 christos // tab-width: 4 601 1.1 christos // c-file-style: "bsd" 602 1.1 christos // c-basic-offset: 4 603 1.1 christos // fill-column: 108 604 1.1 christos // indent-tabs-mode: nil 605 1.1 christos // End: 606