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