1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2018 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/file.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <inttypes.h> 32 #include <stddef.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 #include "config.h" 39 #include "auth.h" 40 #include "dhcp.h" 41 #include "dhcp6.h" 42 #include "dhcpcd.h" 43 44 #ifdef HAVE_HMAC_H 45 #include <hmac.h> 46 #endif 47 48 #ifdef __sun 49 #define htonll 50 #define ntohll 51 #endif 52 53 #ifndef htonll 54 #if (BYTE_ORDER == LITTLE_ENDIAN) 55 #define htonll(x) ((uint64_t)htonl((uint32_t)((x) >> 32)) | \ 56 (uint64_t)htonl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32) 57 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */ 58 #define htonll(x) (x) 59 #endif 60 #endif /* htonll */ 61 62 #ifndef ntohll 63 #if (BYTE_ORDER == LITTLE_ENDIAN) 64 #define ntohll(x) ((uint64_t)ntohl((uint32_t)((x) >> 32)) | \ 65 (uint64_t)ntohl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32) 66 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */ 67 #define ntohll(x) (x) 68 #endif 69 #endif /* ntohll */ 70 71 #define HMAC_LENGTH 16 72 73 void 74 dhcp_auth_reset(struct authstate *state) 75 { 76 77 state->replay = 0; 78 if (state->token) { 79 free(state->token->key); 80 free(state->token->realm); 81 free(state->token); 82 state->token = NULL; 83 } 84 if (state->reconf) { 85 free(state->reconf->key); 86 free(state->reconf->realm); 87 free(state->reconf); 88 state->reconf = NULL; 89 } 90 } 91 92 /* 93 * Authenticate a DHCP message. 94 * m and mlen refer to the whole message. 95 * t is the DHCP type, pass it 4 or 6. 96 * data and dlen refer to the authentication option within the message. 97 */ 98 const struct token * 99 dhcp_auth_validate(struct authstate *state, const struct auth *auth, 100 const void *vm, size_t mlen, int mp, int mt, 101 const void *vdata, size_t dlen) 102 { 103 const uint8_t *m, *data; 104 uint8_t protocol, algorithm, rdm, *mm, type; 105 uint64_t replay; 106 uint32_t secretid; 107 const uint8_t *d, *realm; 108 size_t realm_len; 109 const struct token *t; 110 time_t now; 111 uint8_t hmac_code[HMAC_LENGTH]; 112 113 if (dlen < 3 + sizeof(replay)) { 114 errno = EINVAL; 115 return NULL; 116 } 117 118 m = vm; 119 data = vdata; 120 /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ 121 if (data < m || data > m + mlen || data + dlen > m + mlen) { 122 errno = ERANGE; 123 return NULL; 124 } 125 126 d = data; 127 protocol = *d++; 128 algorithm = *d++; 129 rdm = *d++; 130 if (!(auth->options & DHCPCD_AUTH_SEND)) { 131 /* If we didn't send any authorisation, it can only be a 132 * reconfigure key */ 133 if (protocol != AUTH_PROTO_RECONFKEY) { 134 errno = EINVAL; 135 return NULL; 136 } 137 } else if (protocol != auth->protocol || 138 algorithm != auth->algorithm || 139 rdm != auth->rdm) 140 { 141 /* As we don't require authentication, we should still 142 * accept a reconfigure key */ 143 if (protocol != AUTH_PROTO_RECONFKEY || 144 auth->options & DHCPCD_AUTH_REQUIRE) 145 { 146 errno = EPERM; 147 return NULL; 148 } 149 } 150 dlen -= 3; 151 152 memcpy(&replay, d, sizeof(replay)); 153 replay = ntohll(replay); 154 /* 155 * Test for a replay attack. 156 * 157 * NOTE: Some servers always send a replay data value of zero. 158 * This is strictly compliant with RFC 3315 and 3318 which say: 159 * "If the RDM field contains 0x00, the replay detection field MUST be 160 * set to the value of a monotonically increasing counter." 161 * An example of a monotonically increasing sequence is: 162 * 1, 2, 2, 2, 2, 2, 2 163 * Errata 3474 updates RFC 3318 to say: 164 * "If the RDM field contains 0x00, the replay detection field MUST be 165 * set to the value of a strictly increasing counter." 166 * 167 * Taking the above into account, dhcpcd will only test for 168 * strictly speaking replay attacks if it receives any non zero 169 * replay data to validate against. 170 */ 171 if (state->token && state->replay != 0) { 172 if (state->replay == (replay ^ 0x8000000000000000ULL)) { 173 /* We don't know if the singular point is increasing 174 * or decreasing. */ 175 errno = EPERM; 176 return NULL; 177 } 178 if ((uint64_t)(replay - state->replay) <= 0) { 179 /* Replay attack detected */ 180 errno = EPERM; 181 return NULL; 182 } 183 } 184 d+= sizeof(replay); 185 dlen -= sizeof(replay); 186 187 realm = NULL; 188 realm_len = 0; 189 190 /* Extract realm and secret. 191 * Rest of data is MAC. */ 192 switch (protocol) { 193 case AUTH_PROTO_TOKEN: 194 secretid = auth->token_rcv_secretid; 195 break; 196 case AUTH_PROTO_DELAYED: 197 if (dlen < sizeof(secretid) + sizeof(hmac_code)) { 198 errno = EINVAL; 199 return NULL; 200 } 201 memcpy(&secretid, d, sizeof(secretid)); 202 secretid = ntohl(secretid); 203 d += sizeof(secretid); 204 dlen -= sizeof(secretid); 205 break; 206 case AUTH_PROTO_DELAYEDREALM: 207 if (dlen < sizeof(secretid) + sizeof(hmac_code)) { 208 errno = EINVAL; 209 return NULL; 210 } 211 realm_len = dlen - (sizeof(secretid) + sizeof(hmac_code)); 212 if (realm_len) { 213 realm = d; 214 d += realm_len; 215 dlen -= realm_len; 216 } 217 memcpy(&secretid, d, sizeof(secretid)); 218 secretid = ntohl(secretid); 219 d += sizeof(secretid); 220 dlen -= sizeof(secretid); 221 break; 222 case AUTH_PROTO_RECONFKEY: 223 if (dlen != 1 + 16) { 224 errno = EINVAL; 225 return NULL; 226 } 227 type = *d++; 228 dlen--; 229 switch (type) { 230 case 1: 231 if ((mp == 4 && mt == DHCP_ACK) || 232 (mp == 6 && mt == DHCP6_REPLY)) 233 { 234 if (state->reconf == NULL) { 235 state->reconf = 236 malloc(sizeof(*state->reconf)); 237 if (state->reconf == NULL) 238 return NULL; 239 state->reconf->key = malloc(16); 240 if (state->reconf->key == NULL) { 241 free(state->reconf); 242 state->reconf = NULL; 243 return NULL; 244 } 245 state->reconf->secretid = 0; 246 state->reconf->expire = 0; 247 state->reconf->realm = NULL; 248 state->reconf->realm_len = 0; 249 state->reconf->key_len = 16; 250 } 251 memcpy(state->reconf->key, d, 16); 252 } else { 253 errno = EINVAL; 254 return NULL; 255 } 256 if (state->reconf == NULL) 257 errno = ENOENT; 258 /* Free the old token so we log acceptance */ 259 if (state->token) { 260 free(state->token); 261 state->token = NULL; 262 } 263 /* Nothing to validate, just accepting the key */ 264 return state->reconf; 265 case 2: 266 if (!((mp == 4 && mt == DHCP_FORCERENEW) || 267 (mp == 6 && mt == DHCP6_RECONFIGURE))) 268 { 269 errno = EINVAL; 270 return NULL; 271 } 272 if (state->reconf == NULL) { 273 errno = ENOENT; 274 return NULL; 275 } 276 t = state->reconf; 277 goto gottoken; 278 default: 279 errno = EINVAL; 280 return NULL; 281 } 282 default: 283 errno = ENOTSUP; 284 return NULL; 285 } 286 287 /* Find a token for the realm and secret */ 288 TAILQ_FOREACH(t, &auth->tokens, next) { 289 if (t->secretid == secretid && 290 t->realm_len == realm_len && 291 (t->realm_len == 0 || 292 memcmp(t->realm, realm, t->realm_len) == 0)) 293 break; 294 } 295 if (t == NULL) { 296 errno = ESRCH; 297 return NULL; 298 } 299 if (t->expire) { 300 if (time(&now) == -1) 301 return NULL; 302 if (t->expire < now) { 303 errno = EFAULT; 304 return NULL; 305 } 306 } 307 308 gottoken: 309 /* First message from the server */ 310 if (state->token && 311 (state->token->secretid != t->secretid || 312 state->token->realm_len != t->realm_len || 313 memcmp(state->token->realm, t->realm, t->realm_len))) 314 { 315 errno = EPERM; 316 return NULL; 317 } 318 319 /* Special case as no hashing needs to be done. */ 320 if (protocol == AUTH_PROTO_TOKEN) { 321 if (dlen != t->key_len || memcmp(d, t->key, dlen)) { 322 errno = EPERM; 323 return NULL; 324 } 325 goto finish; 326 } 327 328 /* Make a duplicate of the message, but zero out the MAC part */ 329 mm = malloc(mlen); 330 if (mm == NULL) 331 return NULL; 332 memcpy(mm, m, mlen); 333 memset(mm + (d - m), 0, dlen); 334 335 /* RFC3318, section 5.2 - zero giaddr and hops */ 336 if (mp == 4) { 337 /* Assert the bootp structure is correct size. */ 338 __CTASSERT(sizeof(struct bootp) == 300); 339 340 *(mm + offsetof(struct bootp, hops)) = '\0'; 341 memset(mm + offsetof(struct bootp, giaddr), 0, 4); 342 } 343 344 memset(hmac_code, 0, sizeof(hmac_code)); 345 switch (algorithm) { 346 case AUTH_ALG_HMAC_MD5: 347 hmac("md5", t->key, t->key_len, mm, mlen, 348 hmac_code, sizeof(hmac_code)); 349 break; 350 default: 351 errno = ENOSYS; 352 free(mm); 353 return NULL; 354 } 355 356 free(mm); 357 if (memcmp(d, &hmac_code, dlen)) { 358 errno = EPERM; 359 return NULL; 360 } 361 362 finish: 363 /* If we got here then authentication passed */ 364 state->replay = replay; 365 if (state->token == NULL) { 366 /* We cannot just save a pointer because a reconfigure will 367 * recreate the token list. So we duplicate it. */ 368 state->token = malloc(sizeof(*state->token)); 369 if (state->token) { 370 state->token->secretid = t->secretid; 371 state->token->key = malloc(t->key_len); 372 if (state->token->key) { 373 state->token->key_len = t->key_len; 374 memcpy(state->token->key, t->key, t->key_len); 375 } else { 376 free(state->token); 377 state->token = NULL; 378 return NULL; 379 } 380 if (t->realm_len) { 381 state->token->realm = malloc(t->realm_len); 382 if (state->token->realm) { 383 state->token->realm_len = t->realm_len; 384 memcpy(state->token->realm, t->realm, 385 t->realm_len); 386 } else { 387 free(state->token->key); 388 free(state->token); 389 state->token = NULL; 390 return NULL; 391 } 392 } else { 393 state->token->realm = NULL; 394 state->token->realm_len = 0; 395 } 396 } 397 /* If we cannot save the token, we must invalidate */ 398 if (state->token == NULL) 399 return NULL; 400 } 401 402 return t; 403 } 404 405 static uint64_t 406 get_next_rdm_monotonic_counter(struct auth *auth) 407 { 408 FILE *fp; 409 uint64_t rdm; 410 #ifdef LOCK_EX 411 int flocked; 412 #endif 413 414 fp = fopen(RDM_MONOFILE, "r+"); 415 if (fp == NULL) { 416 if (errno != ENOENT) 417 return ++auth->last_replay; /* report error? */ 418 fp = fopen(RDM_MONOFILE, "w"); 419 if (fp == NULL) 420 return ++auth->last_replay; /* report error? */ 421 #ifdef LOCK_EX 422 flocked = flock(fileno(fp), LOCK_EX); 423 #endif 424 rdm = 0; 425 } else { 426 #ifdef LOCK_EX 427 flocked = flock(fileno(fp), LOCK_EX); 428 #endif 429 if (fscanf(fp, "0x%016" PRIu64, &rdm) != 1) 430 rdm = 0; /* truncated? report error? */ 431 } 432 433 rdm++; 434 if (fseek(fp, 0, SEEK_SET) == -1 || 435 ftruncate(fileno(fp), 0) == -1 || 436 fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19 || 437 fflush(fp) == EOF) 438 { 439 if (!auth->last_replay_set) { 440 auth->last_replay = rdm; 441 auth->last_replay_set = 1; 442 } else 443 rdm = ++auth->last_replay; 444 /* report error? */ 445 } 446 #ifdef LOCK_EX 447 if (flocked == 0) 448 flock(fileno(fp), LOCK_UN); 449 #endif 450 fclose(fp); 451 return rdm; 452 } 453 454 #define NTP_EPOCH 2208988800U /* 1970 - 1900 in seconds */ 455 #define NTP_SCALE_FRAC 4294967295.0 /* max value of the fractional part */ 456 static uint64_t 457 get_next_rdm_monotonic_clock(struct auth *auth) 458 { 459 struct timespec ts; 460 uint64_t secs, rdm; 461 double frac; 462 463 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) 464 return ++auth->last_replay; /* report error? */ 465 466 secs = (uint64_t)ts.tv_sec + NTP_EPOCH; 467 frac = ((double)ts.tv_nsec / 1e9 * NTP_SCALE_FRAC); 468 rdm = (secs << 32) | (uint64_t)frac; 469 return rdm; 470 } 471 472 static uint64_t 473 get_next_rdm_monotonic(struct auth *auth) 474 { 475 476 if (auth->options & DHCPCD_AUTH_RDM_COUNTER) 477 return get_next_rdm_monotonic_counter(auth); 478 return get_next_rdm_monotonic_clock(auth); 479 } 480 481 /* 482 * Encode a DHCP message. 483 * Either we know which token to use from the server response 484 * or we are using a basic configuration token. 485 * token is the token to encrypt with. 486 * m and mlen refer to the whole message. 487 * mp is the DHCP type, pass it 4 or 6. 488 * mt is the DHCP message type. 489 * data and dlen refer to the authentication option within the message. 490 */ 491 ssize_t 492 dhcp_auth_encode(struct auth *auth, const struct token *t, 493 void *vm, size_t mlen, int mp, int mt, 494 void *vdata, size_t dlen) 495 { 496 uint64_t rdm; 497 uint8_t hmac_code[HMAC_LENGTH]; 498 time_t now; 499 uint8_t hops, *p, *m, *data; 500 uint32_t giaddr, secretid; 501 bool auth_info; 502 503 /* Ignore the token argument given to us - always send using the 504 * configured token. */ 505 if (auth->protocol == AUTH_PROTO_TOKEN) { 506 TAILQ_FOREACH(t, &auth->tokens, next) { 507 if (t->secretid == auth->token_snd_secretid) 508 break; 509 } 510 if (t == NULL) { 511 errno = EINVAL; 512 return -1; 513 } 514 if (t->expire) { 515 if (time(&now) == -1) 516 return -1; 517 if (t->expire < now) { 518 errno = EPERM; 519 return -1; 520 } 521 } 522 } 523 524 switch(auth->protocol) { 525 case AUTH_PROTO_TOKEN: 526 case AUTH_PROTO_DELAYED: 527 case AUTH_PROTO_DELAYEDREALM: 528 /* We don't ever send a reconf key */ 529 break; 530 default: 531 errno = ENOTSUP; 532 return -1; 533 } 534 535 switch(auth->algorithm) { 536 case AUTH_ALG_NONE: 537 case AUTH_ALG_HMAC_MD5: 538 break; 539 default: 540 errno = ENOTSUP; 541 return -1; 542 } 543 544 switch(auth->rdm) { 545 case AUTH_RDM_MONOTONIC: 546 break; 547 default: 548 errno = ENOTSUP; 549 return -1; 550 } 551 552 /* DISCOVER or INFORM messages don't write auth info */ 553 if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) || 554 (mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ))) 555 auth_info = false; 556 else 557 auth_info = true; 558 559 /* Work out the auth area size. 560 * We only need to do this for DISCOVER messages */ 561 if (vdata == NULL) { 562 dlen = 1 + 1 + 1 + 8; 563 switch(auth->protocol) { 564 case AUTH_PROTO_TOKEN: 565 dlen += t->key_len; 566 break; 567 case AUTH_PROTO_DELAYEDREALM: 568 if (auth_info && t) 569 dlen += t->realm_len; 570 /* FALLTHROUGH */ 571 case AUTH_PROTO_DELAYED: 572 if (auth_info && t) 573 dlen += sizeof(t->secretid) + sizeof(hmac_code); 574 break; 575 } 576 return (ssize_t)dlen; 577 } 578 579 if (dlen < 1 + 1 + 1 + 8) { 580 errno = ENOBUFS; 581 return -1; 582 } 583 584 /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ 585 m = vm; 586 data = vdata; 587 if (data < m || data > m + mlen || data + dlen > m + mlen) { 588 errno = ERANGE; 589 return -1; 590 } 591 592 /* Write out our option */ 593 *data++ = auth->protocol; 594 *data++ = auth->algorithm; 595 /* 596 * RFC 3315 21.4.4.1 says that SOLICIT in DELAYED authentication 597 * should not set RDM or it's data. 598 * An expired draft draft-ietf-dhc-dhcpv6-clarify-auth-01 suggets 599 * this should not be set for INFORMATION REQ messages as well, 600 * which is probably a good idea because both states start from zero. 601 */ 602 if (auth_info || 603 !(auth->protocol & (AUTH_PROTO_DELAYED | AUTH_PROTO_DELAYEDREALM))) 604 { 605 *data++ = auth->rdm; 606 switch (auth->rdm) { 607 case AUTH_RDM_MONOTONIC: 608 rdm = get_next_rdm_monotonic(auth); 609 break; 610 default: 611 /* This block appeases gcc, clang doesn't need it */ 612 rdm = get_next_rdm_monotonic(auth); 613 break; 614 } 615 rdm = htonll(rdm); 616 memcpy(data, &rdm, 8); 617 } else { 618 *data++ = 0; /* rdm */ 619 memset(data, 0, 8); /* replay detection data */ 620 } 621 data += 8; 622 dlen -= 1 + 1 + 1 + 8; 623 624 /* Special case as no hashing needs to be done. */ 625 if (auth->protocol == AUTH_PROTO_TOKEN) { 626 /* Should be impossible, but still */ 627 if (t == NULL) { 628 errno = EINVAL; 629 return -1; 630 } 631 if (dlen < t->key_len) { 632 errno = ENOBUFS; 633 return -1; 634 } 635 memcpy(data, t->key, t->key_len); 636 return (ssize_t)(dlen - t->key_len); 637 } 638 639 /* DISCOVER or INFORM messages don't write auth info */ 640 if (!auth_info) 641 return (ssize_t)dlen; 642 643 /* Loading a saved lease without an authentication option */ 644 if (t == NULL) 645 return 0; 646 647 /* Write out the Realm */ 648 if (auth->protocol == AUTH_PROTO_DELAYEDREALM) { 649 if (dlen < t->realm_len) { 650 errno = ENOBUFS; 651 return -1; 652 } 653 memcpy(data, t->realm, t->realm_len); 654 data += t->realm_len; 655 dlen -= t->realm_len; 656 } 657 658 /* Write out the SecretID */ 659 if (auth->protocol == AUTH_PROTO_DELAYED || 660 auth->protocol == AUTH_PROTO_DELAYEDREALM) 661 { 662 if (dlen < sizeof(t->secretid)) { 663 errno = ENOBUFS; 664 return -1; 665 } 666 secretid = htonl(t->secretid); 667 memcpy(data, &secretid, sizeof(secretid)); 668 data += sizeof(secretid); 669 dlen -= sizeof(secretid); 670 } 671 672 /* Zero what's left, the MAC */ 673 memset(data, 0, dlen); 674 675 /* RFC3318, section 5.2 - zero giaddr and hops */ 676 if (mp == 4) { 677 p = m + offsetof(struct bootp, hops); 678 hops = *p; 679 *p = '\0'; 680 p = m + offsetof(struct bootp, giaddr); 681 memcpy(&giaddr, p, sizeof(giaddr)); 682 memset(p, 0, sizeof(giaddr)); 683 } else { 684 /* appease GCC again */ 685 hops = 0; 686 giaddr = 0; 687 } 688 689 /* Create our hash and write it out */ 690 switch(auth->algorithm) { 691 case AUTH_ALG_HMAC_MD5: 692 hmac("md5", t->key, t->key_len, m, mlen, 693 hmac_code, sizeof(hmac_code)); 694 memcpy(data, hmac_code, sizeof(hmac_code)); 695 break; 696 } 697 698 /* RFC3318, section 5.2 - restore giaddr and hops */ 699 if (mp == 4) { 700 p = m + offsetof(struct bootp, hops); 701 *p = hops; 702 p = m + offsetof(struct bootp, giaddr); 703 memcpy(p, &giaddr, sizeof(giaddr)); 704 } 705 706 /* Done! */ 707 return (int)(dlen - sizeof(hmac_code)); /* should be zero */ 708 } 709