1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2015 Roy Marples <roy (at) 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 "crypt/crypt.h" 41 #include "dhcp.h" 42 #include "dhcp6.h" 43 #include "dhcpcd.h" 44 45 #ifdef __sun 46 #define htonll 47 #define ntohll 48 #endif 49 50 #ifndef htonll 51 #if (BYTE_ORDER == LITTLE_ENDIAN) 52 static inline uint64_t 53 htonll(uint64_t x) 54 { 55 56 return (uint64_t)htonl((uint32_t)(x >> 32)) | 57 (uint64_t)htonl((uint32_t)(x & 0xffffffff)) << 32; 58 } 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 static inline uint64_t 67 ntohll(uint64_t x) 68 { 69 70 return (uint64_t)ntohl((uint32_t)(x >> 32)) | 71 (uint64_t)ntohl((uint32_t)(x & 0xffffffff)) << 32; 72 } 73 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */ 74 #define ntohll(x) (x) 75 #endif 76 #endif /* ntohll */ 77 78 #define HMAC_LENGTH 16 79 80 void 81 dhcp_auth_reset(struct authstate *state) 82 { 83 84 state->replay = 0; 85 if (state->token) { 86 free(state->token->key); 87 free(state->token->realm); 88 free(state->token); 89 state->token = NULL; 90 } 91 if (state->reconf) { 92 free(state->reconf->key); 93 free(state->reconf->realm); 94 free(state->reconf); 95 state->reconf = NULL; 96 } 97 } 98 99 /* 100 * Authenticate a DHCP message. 101 * m and mlen refer to the whole message. 102 * t is the DHCP type, pass it 4 or 6. 103 * data and dlen refer to the authentication option within the message. 104 */ 105 const struct token * 106 dhcp_auth_validate(struct authstate *state, const struct auth *auth, 107 const uint8_t *m, size_t mlen, int mp, int mt, 108 const uint8_t *data, size_t dlen) 109 { 110 uint8_t protocol, algorithm, rdm, *mm, type; 111 uint64_t replay; 112 uint32_t secretid; 113 const uint8_t *d, *realm; 114 size_t realm_len; 115 const struct token *t; 116 time_t now; 117 uint8_t hmac[HMAC_LENGTH]; 118 119 if (dlen < 3 + sizeof(replay)) { 120 errno = EINVAL; 121 return NULL; 122 } 123 124 /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ 125 if (data < m || data > m + mlen || data + dlen > m + mlen) { 126 errno = ERANGE; 127 return NULL; 128 } 129 130 d = data; 131 protocol = *d++; 132 algorithm = *d++; 133 rdm = *d++; 134 if (!(auth->options & DHCPCD_AUTH_SEND)) { 135 /* If we didn't send any authorisation, it can only be a 136 * reconfigure key */ 137 if (protocol != AUTH_PROTO_RECONFKEY) { 138 errno = EINVAL; 139 return NULL; 140 } 141 } else if (protocol != auth->protocol || 142 algorithm != auth->algorithm || 143 rdm != auth->rdm) 144 { 145 /* As we don't require authentication, we should still 146 * accept a reconfigure key */ 147 if (protocol != AUTH_PROTO_RECONFKEY || 148 auth->options & DHCPCD_AUTH_REQUIRE) 149 { 150 errno = EPERM; 151 return NULL; 152 } 153 } 154 dlen -= 3; 155 156 memcpy(&replay, d, sizeof(replay)); 157 replay = ntohll(replay); 158 if (state->token) { 159 if (state->replay == (replay ^ 0x8000000000000000ULL)) { 160 /* We don't know if the singular point is increasing 161 * or decreasing. */ 162 errno = EPERM; 163 return NULL; 164 } 165 if ((uint64_t)(replay - state->replay) <= 0) { 166 /* Replay attack detected */ 167 errno = EPERM; 168 return NULL; 169 } 170 } 171 d+= sizeof(replay); 172 dlen -= sizeof(replay); 173 174 realm = NULL; 175 realm_len = 0; 176 177 /* Extract realm and secret. 178 * Rest of data is MAC. */ 179 switch (protocol) { 180 case AUTH_PROTO_TOKEN: 181 secretid = 0; 182 break; 183 case AUTH_PROTO_DELAYED: 184 if (dlen < sizeof(secretid) + sizeof(hmac)) { 185 errno = EINVAL; 186 return NULL; 187 } 188 memcpy(&secretid, d, sizeof(secretid)); 189 d += sizeof(secretid); 190 dlen -= sizeof(secretid); 191 break; 192 case AUTH_PROTO_DELAYEDREALM: 193 if (dlen < sizeof(secretid) + sizeof(hmac)) { 194 errno = EINVAL; 195 return NULL; 196 } 197 realm_len = dlen - (sizeof(secretid) + sizeof(hmac)); 198 if (realm_len) { 199 realm = d; 200 d += realm_len; 201 dlen -= realm_len; 202 } 203 memcpy(&secretid, d, sizeof(secretid)); 204 d += sizeof(secretid); 205 dlen -= sizeof(secretid); 206 break; 207 case AUTH_PROTO_RECONFKEY: 208 if (dlen != 1 + 16) { 209 errno = EINVAL; 210 return NULL; 211 } 212 type = *d++; 213 dlen--; 214 switch (type) { 215 case 1: 216 if ((mp == 4 && mt == DHCP_ACK) || 217 (mp == 6 && mt == DHCP6_REPLY)) 218 { 219 if (state->reconf == NULL) { 220 state->reconf = 221 malloc(sizeof(*state->reconf)); 222 if (state->reconf == NULL) 223 return NULL; 224 state->reconf->key = malloc(16); 225 if (state->reconf->key == NULL) { 226 free(state->reconf); 227 state->reconf = NULL; 228 return NULL; 229 } 230 state->reconf->secretid = 0; 231 state->reconf->expire = 0; 232 state->reconf->realm = NULL; 233 state->reconf->realm_len = 0; 234 state->reconf->key_len = 16; 235 } 236 memcpy(state->reconf->key, d, 16); 237 } else { 238 errno = EINVAL; 239 return NULL; 240 } 241 if (state->reconf == NULL) 242 errno = ENOENT; 243 /* Free the old token so we log acceptance */ 244 if (state->token) { 245 free(state->token); 246 state->token = NULL; 247 } 248 /* Nothing to validate, just accepting the key */ 249 return state->reconf; 250 case 2: 251 if (!((mp == 4 && mt == DHCP_FORCERENEW) || 252 (mp == 6 && mt == DHCP6_RECONFIGURE))) 253 { 254 errno = EINVAL; 255 return NULL; 256 } 257 if (state->reconf == NULL) { 258 errno = ENOENT; 259 return NULL; 260 } 261 t = state->reconf; 262 goto gottoken; 263 default: 264 errno = EINVAL; 265 return NULL; 266 } 267 default: 268 errno = ENOTSUP; 269 return NULL; 270 } 271 272 /* Find a token for the realm and secret */ 273 secretid = ntohl(secretid); 274 TAILQ_FOREACH(t, &auth->tokens, next) { 275 if (t->secretid == secretid && 276 t->realm_len == realm_len && 277 (t->realm_len == 0 || 278 memcmp(t->realm, realm, t->realm_len) == 0)) 279 break; 280 } 281 if (t == NULL) { 282 errno = ESRCH; 283 return NULL; 284 } 285 if (t->expire) { 286 if (time(&now) == -1) 287 return NULL; 288 if (t->expire < now) { 289 errno = EFAULT; 290 return NULL; 291 } 292 } 293 294 gottoken: 295 /* First message from the server */ 296 if (state->token && 297 (state->token->secretid != t->secretid || 298 state->token->realm_len != t->realm_len || 299 memcmp(state->token->realm, t->realm, t->realm_len))) 300 { 301 errno = EPERM; 302 return NULL; 303 } 304 305 /* Special case as no hashing needs to be done. */ 306 if (protocol == AUTH_PROTO_TOKEN) { 307 if (dlen != t->key_len || memcmp(d, t->key, dlen)) { 308 errno = EPERM; 309 return NULL; 310 } 311 goto finish; 312 } 313 314 /* Make a duplicate of the message, but zero out the MAC part */ 315 mm = malloc(mlen); 316 if (mm == NULL) 317 return NULL; 318 memcpy(mm, m, mlen); 319 memset(mm + (d - m), 0, dlen); 320 321 /* RFC3318, section 5.2 - zero giaddr and hops */ 322 if (mp == 4) { 323 *(mm + offsetof(struct dhcp_message, hwopcount)) = '\0'; 324 memset(mm + offsetof(struct dhcp_message, giaddr), 0, 4); 325 } 326 327 memset(hmac, 0, sizeof(hmac)); 328 switch (algorithm) { 329 case AUTH_ALG_HMAC_MD5: 330 hmac_md5(mm, mlen, t->key, t->key_len, hmac); 331 break; 332 default: 333 errno = ENOSYS; 334 free(mm); 335 return NULL; 336 } 337 338 free(mm); 339 if (memcmp(d, &hmac, dlen)) { 340 errno = EPERM; 341 return NULL; 342 } 343 344 finish: 345 /* If we got here then authentication passed */ 346 state->replay = replay; 347 if (state->token == NULL) { 348 /* We cannot just save a pointer because a reconfigure will 349 * recreate the token list. So we duplicate it. */ 350 state->token = malloc(sizeof(*state->token)); 351 if (state->token) { 352 state->token->secretid = t->secretid; 353 state->token->key = malloc(t->key_len); 354 if (state->token->key) { 355 state->token->key_len = t->key_len; 356 memcpy(state->token->key, t->key, t->key_len); 357 } else { 358 free(state->token); 359 state->token = NULL; 360 return NULL; 361 } 362 if (t->realm_len) { 363 state->token->realm = malloc(t->realm_len); 364 if (state->token->realm) { 365 state->token->realm_len = t->realm_len; 366 memcpy(state->token->realm, t->realm, 367 t->realm_len); 368 } else { 369 free(state->token->key); 370 free(state->token); 371 state->token = NULL; 372 return NULL; 373 } 374 } else { 375 state->token->realm = NULL; 376 state->token->realm_len = 0; 377 } 378 } 379 /* If we cannot save the token, we must invalidate */ 380 if (state->token == NULL) 381 return NULL; 382 } 383 384 return t; 385 } 386 387 static uint64_t 388 get_next_rdm_monotonic_counter(struct auth *auth) 389 { 390 FILE *fp; 391 uint64_t rdm; 392 #ifdef LOCK_EX 393 int flocked; 394 #endif 395 396 fp = fopen(RDM_MONOFILE, "r+"); 397 if (fp == NULL) { 398 if (errno != ENOENT) 399 return ++auth->last_replay; /* report error? */ 400 fp = fopen(RDM_MONOFILE, "w"); 401 if (fp == NULL) 402 return ++auth->last_replay; /* report error? */ 403 #ifdef LOCK_EX 404 flocked = flock(fileno(fp), LOCK_EX); 405 #endif 406 rdm = 0; 407 } else { 408 #ifdef LOCK_EX 409 flocked = flock(fileno(fp), LOCK_EX); 410 #endif 411 if (fscanf(fp, "0x%016" PRIu64, &rdm) != 1) 412 rdm = 0; /* truncated? report error? */ 413 } 414 415 rdm++; 416 if (fseek(fp, 0, SEEK_SET) == -1 || 417 ftruncate(fileno(fp), 0) == -1 || 418 fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19) 419 { 420 if (!auth->last_replay_set) { 421 auth->last_replay = rdm; 422 auth->last_replay_set = 1; 423 } else 424 rdm = ++auth->last_replay; 425 /* report error? */ 426 } 427 fflush(fp); 428 #ifdef LOCK_EX 429 if (flocked == 0) 430 flock(fileno(fp), LOCK_UN); 431 #endif 432 fclose(fp); 433 return rdm; 434 } 435 436 #define JAN_1970 2208988800U /* 1970 - 1900 in seconds */ 437 static uint64_t 438 get_next_rdm_monotonic_clock(struct auth *auth) 439 { 440 struct timespec ts; 441 uint32_t pack[2]; 442 double frac; 443 uint64_t rdm; 444 445 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) 446 return ++auth->last_replay; /* report error? */ 447 pack[0] = htonl((uint32_t)ts.tv_sec + JAN_1970); 448 frac = ((double)ts.tv_nsec / 1e9 * 0x100000000ULL); 449 pack[1] = htonl((uint32_t)frac); 450 451 memcpy(&rdm, &pack, sizeof(rdm)); 452 return rdm; 453 } 454 455 static uint64_t 456 get_next_rdm_monotonic(struct auth *auth) 457 { 458 459 if (auth->options & DHCPCD_AUTH_RDM_COUNTER) 460 return get_next_rdm_monotonic_counter(auth); 461 return get_next_rdm_monotonic_clock(auth); 462 } 463 464 /* 465 * Encode a DHCP message. 466 * Either we know which token to use from the server response 467 * or we are using a basic configuration token. 468 * token is the token to encrypt with. 469 * m and mlen refer to the whole message. 470 * mp is the DHCP type, pass it 4 or 6. 471 * mt is the DHCP message type. 472 * data and dlen refer to the authentication option within the message. 473 */ 474 ssize_t 475 dhcp_auth_encode(struct auth *auth, const struct token *t, 476 uint8_t *m, size_t mlen, int mp, int mt, 477 uint8_t *data, size_t dlen) 478 { 479 uint64_t rdm; 480 uint8_t hmac[HMAC_LENGTH]; 481 time_t now; 482 uint8_t hops, *p, info; 483 uint32_t giaddr, secretid; 484 485 if (auth->protocol == 0 && t == NULL) { 486 TAILQ_FOREACH(t, &auth->tokens, next) { 487 if (t->secretid == 0 && 488 t->realm_len == 0) 489 break; 490 } 491 if (t == NULL) { 492 errno = EINVAL; 493 return -1; 494 } 495 if (t->expire) { 496 if (time(&now) == -1) 497 return -1; 498 if (t->expire < now) { 499 errno = EPERM; 500 return -1; 501 } 502 } 503 } 504 505 switch(auth->protocol) { 506 case AUTH_PROTO_TOKEN: 507 case AUTH_PROTO_DELAYED: 508 case AUTH_PROTO_DELAYEDREALM: 509 /* We don't ever send a reconf key */ 510 break; 511 default: 512 errno = ENOTSUP; 513 return -1; 514 } 515 516 switch(auth->algorithm) { 517 case AUTH_ALG_HMAC_MD5: 518 break; 519 default: 520 errno = ENOTSUP; 521 return -1; 522 } 523 524 switch(auth->rdm) { 525 case AUTH_RDM_MONOTONIC: 526 break; 527 default: 528 errno = ENOTSUP; 529 return -1; 530 } 531 532 /* DISCOVER or INFORM messages don't write auth info */ 533 if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) || 534 (mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ))) 535 info = 0; 536 else 537 info = 1; 538 539 /* Work out the auth area size. 540 * We only need to do this for DISCOVER messages */ 541 if (data == NULL) { 542 dlen = 1 + 1 + 1 + 8; 543 switch(auth->protocol) { 544 case AUTH_PROTO_TOKEN: 545 dlen += t->key_len; 546 break; 547 case AUTH_PROTO_DELAYEDREALM: 548 if (info && t) 549 dlen += t->realm_len; 550 /* FALLTHROUGH */ 551 case AUTH_PROTO_DELAYED: 552 if (info && t) 553 dlen += sizeof(t->secretid) + sizeof(hmac); 554 break; 555 } 556 return (ssize_t)dlen; 557 } 558 559 if (dlen < 1 + 1 + 1 + 8) { 560 errno = ENOBUFS; 561 return -1; 562 } 563 564 /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ 565 if (data < m || data > m + mlen || data + dlen > m + mlen) { 566 errno = ERANGE; 567 return -1; 568 } 569 570 /* Write out our option */ 571 *data++ = auth->protocol; 572 *data++ = auth->algorithm; 573 *data++ = auth->rdm; 574 switch (auth->rdm) { 575 case AUTH_RDM_MONOTONIC: 576 rdm = get_next_rdm_monotonic(auth); 577 break; 578 default: 579 /* This block appeases gcc, clang doesn't need it */ 580 rdm = get_next_rdm_monotonic(auth); 581 break; 582 } 583 rdm = htonll(rdm); 584 memcpy(data, &rdm, 8); 585 data += 8; 586 dlen -= 1 + 1 + 1 + 8; 587 588 /* Special case as no hashing needs to be done. */ 589 if (auth->protocol == AUTH_PROTO_TOKEN) { 590 /* Should be impossible, but still */ 591 if (t == NULL) { 592 errno = EINVAL; 593 return -1; 594 } 595 if (dlen < t->key_len) { 596 errno = ENOBUFS; 597 return -1; 598 } 599 memcpy(data, t->key, t->key_len); 600 return (ssize_t)(dlen - t->key_len); 601 } 602 603 /* DISCOVER or INFORM messages don't write auth info */ 604 if (!info) 605 return (ssize_t)dlen; 606 607 /* Loading a saved lease without an authentication option */ 608 if (t == NULL) 609 return 0; 610 611 /* Write out the Realm */ 612 if (auth->protocol == AUTH_PROTO_DELAYEDREALM) { 613 if (dlen < t->realm_len) { 614 errno = ENOBUFS; 615 return -1; 616 } 617 memcpy(data, t->realm, t->realm_len); 618 data += t->realm_len; 619 dlen -= t->realm_len; 620 } 621 622 /* Write out the SecretID */ 623 if (auth->protocol == AUTH_PROTO_DELAYED || 624 auth->protocol == AUTH_PROTO_DELAYEDREALM) 625 { 626 if (dlen < sizeof(t->secretid)) { 627 errno = ENOBUFS; 628 return -1; 629 } 630 secretid = htonl(t->secretid); 631 memcpy(data, &secretid, sizeof(secretid)); 632 data += sizeof(secretid); 633 dlen -= sizeof(secretid); 634 } 635 636 /* Zero what's left, the MAC */ 637 memset(data, 0, dlen); 638 639 /* RFC3318, section 5.2 - zero giaddr and hops */ 640 if (mp == 4) { 641 p = m + offsetof(struct dhcp_message, hwopcount); 642 hops = *p; 643 *p = '\0'; 644 p = m + offsetof(struct dhcp_message, giaddr); 645 memcpy(&giaddr, p, sizeof(giaddr)); 646 memset(p, 0, sizeof(giaddr)); 647 } else { 648 /* appease GCC again */ 649 hops = 0; 650 giaddr = 0; 651 } 652 653 /* Create our hash and write it out */ 654 switch(auth->algorithm) { 655 case AUTH_ALG_HMAC_MD5: 656 hmac_md5(m, mlen, t->key, t->key_len, hmac); 657 memcpy(data, hmac, sizeof(hmac)); 658 break; 659 } 660 661 /* RFC3318, section 5.2 - restore giaddr and hops */ 662 if (mp == 4) { 663 p = m + offsetof(struct dhcp_message, hwopcount); 664 *p = hops; 665 p = m + offsetof(struct dhcp_message, giaddr); 666 memcpy(p, &giaddr, sizeof(giaddr)); 667 } 668 669 /* Done! */ 670 return (int)(dlen - sizeof(hmac)); /* should be zero */ 671 } 672