1 /* $NetBSD: digest.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kdc_locl.h" 37 #include <krb5/hex.h> 38 39 #ifdef DIGEST 40 41 #define MS_CHAP_V2 0x20 42 #define CHAP_MD5 0x10 43 #define DIGEST_MD5 0x08 44 #define NTLM_V2 0x04 45 #define NTLM_V1_SESSION 0x02 46 #define NTLM_V1 0x01 47 48 const struct units _kdc_digestunits[] = { 49 {"ms-chap-v2", 1U << 5}, 50 {"chap-md5", 1U << 4}, 51 {"digest-md5", 1U << 3}, 52 {"ntlm-v2", 1U << 2}, 53 {"ntlm-v1-session", 1U << 1}, 54 {"ntlm-v1", 1U << 0}, 55 {NULL, 0} 56 }; 57 58 59 static krb5_error_code 60 get_digest_key(krb5_context context, 61 krb5_kdc_configuration *config, 62 hdb_entry_ex *server, 63 krb5_crypto *crypto) 64 { 65 krb5_error_code ret; 66 krb5_enctype enctype; 67 Key *key; 68 69 ret = _kdc_get_preferred_key(context, 70 config, 71 server, 72 "digest-service", 73 &enctype, 74 &key); 75 if (ret) 76 return ret; 77 return krb5_crypto_init(context, &key->key, 0, crypto); 78 } 79 80 /* 81 * 82 */ 83 84 static char * 85 get_ntlm_targetname(krb5_context context, 86 hdb_entry_ex *client) 87 { 88 char *targetname, *p; 89 90 targetname = strdup(krb5_principal_get_realm(context, 91 client->entry.principal)); 92 if (targetname == NULL) 93 return NULL; 94 95 p = strchr(targetname, '.'); 96 if (p) 97 *p = '\0'; 98 99 strupr(targetname); 100 return targetname; 101 } 102 103 static krb5_error_code 104 fill_targetinfo(krb5_context context, 105 char *targetname, 106 hdb_entry_ex *client, 107 krb5_data *data) 108 { 109 struct ntlm_targetinfo ti; 110 krb5_error_code ret; 111 struct ntlm_buf d; 112 krb5_principal p; 113 const char *str; 114 115 memset(&ti, 0, sizeof(ti)); 116 117 ti.domainname = targetname; 118 p = client->entry.principal; 119 str = krb5_principal_get_comp_string(context, p, 0); 120 if (str != NULL && 121 (strcmp("host", str) == 0 || 122 strcmp("ftp", str) == 0 || 123 strcmp("imap", str) == 0 || 124 strcmp("pop", str) == 0 || 125 strcmp("smtp", str))) 126 { 127 str = krb5_principal_get_comp_string(context, p, 1); 128 ti.dnsservername = rk_UNCONST(str); 129 } 130 131 ret = heim_ntlm_encode_targetinfo(&ti, 1, &d); 132 if (ret) 133 return ret; 134 135 data->data = d.data; 136 data->length = d.length; 137 138 return 0; 139 } 140 141 142 static const unsigned char ms_chap_v2_magic1[39] = { 143 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 144 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 145 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 146 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 147 }; 148 static const unsigned char ms_chap_v2_magic2[41] = { 149 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 150 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 151 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 152 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 153 0x6E 154 }; 155 static const unsigned char ms_rfc3079_magic1[27] = { 156 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 157 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 158 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 159 }; 160 161 /* 162 * 163 */ 164 165 static krb5_error_code 166 get_password_entry(krb5_context context, 167 krb5_kdc_configuration *config, 168 const char *username, 169 char **password) 170 { 171 krb5_principal clientprincipal; 172 krb5_error_code ret; 173 hdb_entry_ex *user; 174 HDB *db; 175 176 /* get username */ 177 ret = krb5_parse_name(context, username, &clientprincipal); 178 if (ret) 179 return ret; 180 181 ret = _kdc_db_fetch(context, config, clientprincipal, 182 HDB_F_GET_CLIENT, NULL, &db, &user); 183 krb5_free_principal(context, clientprincipal); 184 if (ret) 185 return ret; 186 187 ret = hdb_entry_get_password(context, db, &user->entry, password); 188 if (ret || password == NULL) { 189 if (ret == 0) { 190 ret = EINVAL; 191 krb5_set_error_message(context, ret, "password missing"); 192 } 193 memset(user, 0, sizeof(*user)); 194 } 195 _kdc_free_ent (context, user); 196 return ret; 197 } 198 199 /* 200 * 201 */ 202 203 krb5_error_code 204 _kdc_do_digest(krb5_context context, 205 krb5_kdc_configuration *config, 206 const struct DigestREQ *req, krb5_data *reply, 207 const char *from, struct sockaddr *addr) 208 { 209 krb5_error_code ret = 0; 210 krb5_ticket *ticket = NULL; 211 krb5_auth_context ac = NULL; 212 krb5_keytab id = NULL; 213 krb5_crypto crypto = NULL; 214 DigestReqInner ireq; 215 DigestRepInner r; 216 DigestREP rep; 217 krb5_flags ap_req_options; 218 krb5_data buf; 219 size_t size; 220 krb5_storage *sp = NULL; 221 Checksum res; 222 hdb_entry_ex *server = NULL, *user = NULL; 223 hdb_entry_ex *client = NULL; 224 char *client_name = NULL, *password = NULL; 225 krb5_data serverNonce; 226 227 if(!config->enable_digest) { 228 kdc_log(context, config, 0, 229 "Rejected digest request (disabled) from %s", from); 230 return KRB5KDC_ERR_POLICY; 231 } 232 233 krb5_data_zero(&buf); 234 krb5_data_zero(reply); 235 krb5_data_zero(&serverNonce); 236 memset(&ireq, 0, sizeof(ireq)); 237 memset(&r, 0, sizeof(r)); 238 memset(&rep, 0, sizeof(rep)); 239 memset(&res, 0, sizeof(res)); 240 241 kdc_log(context, config, 0, "Digest request from %s", from); 242 243 ret = krb5_kt_resolve(context, "HDB:", &id); 244 if (ret) { 245 kdc_log(context, config, 0, "Can't open database for digest"); 246 goto out; 247 } 248 249 ret = krb5_rd_req(context, 250 &ac, 251 &req->apReq, 252 NULL, 253 id, 254 &ap_req_options, 255 &ticket); 256 if (ret) 257 goto out; 258 259 /* check the server principal in the ticket matches digest/R@R */ 260 { 261 krb5_principal principal = NULL; 262 const char *p, *rr; 263 264 ret = krb5_ticket_get_server(context, ticket, &principal); 265 if (ret) 266 goto out; 267 268 ret = EINVAL; 269 krb5_set_error_message(context, ret, "Wrong digest server principal used"); 270 p = krb5_principal_get_comp_string(context, principal, 0); 271 if (p == NULL) { 272 krb5_free_principal(context, principal); 273 goto out; 274 } 275 if (strcmp(p, KRB5_DIGEST_NAME) != 0) { 276 krb5_free_principal(context, principal); 277 goto out; 278 } 279 280 p = krb5_principal_get_comp_string(context, principal, 1); 281 if (p == NULL) { 282 krb5_free_principal(context, principal); 283 goto out; 284 } 285 rr = krb5_principal_get_realm(context, principal); 286 if (rr == NULL) { 287 krb5_free_principal(context, principal); 288 goto out; 289 } 290 if (strcmp(p, rr) != 0) { 291 krb5_free_principal(context, principal); 292 goto out; 293 } 294 krb5_clear_error_message(context); 295 296 ret = _kdc_db_fetch(context, config, principal, 297 HDB_F_GET_SERVER, NULL, NULL, &server); 298 if (ret) 299 goto out; 300 301 krb5_free_principal(context, principal); 302 } 303 304 /* check the client is allowed to do digest auth */ 305 { 306 krb5_principal principal = NULL; 307 308 ret = krb5_ticket_get_client(context, ticket, &principal); 309 if (ret) 310 goto out; 311 312 ret = krb5_unparse_name(context, principal, &client_name); 313 if (ret) { 314 krb5_free_principal(context, principal); 315 goto out; 316 } 317 318 ret = _kdc_db_fetch(context, config, principal, 319 HDB_F_GET_CLIENT, NULL, NULL, &client); 320 krb5_free_principal(context, principal); 321 if (ret) 322 goto out; 323 324 if (client->entry.flags.allow_digest == 0) { 325 kdc_log(context, config, 0, 326 "Client %s tried to use digest " 327 "but is not allowed to", 328 client_name); 329 ret = KRB5KDC_ERR_POLICY; 330 krb5_set_error_message(context, ret, 331 "Client is not permitted to use digest"); 332 goto out; 333 } 334 } 335 336 /* unpack request */ 337 { 338 krb5_keyblock *key; 339 340 ret = krb5_auth_con_getremotesubkey(context, ac, &key); 341 if (ret) 342 goto out; 343 if (key == NULL) { 344 ret = EINVAL; 345 krb5_set_error_message(context, ret, "digest: remote subkey not found"); 346 goto out; 347 } 348 349 ret = krb5_crypto_init(context, key, 0, &crypto); 350 krb5_free_keyblock (context, key); 351 if (ret) 352 goto out; 353 } 354 355 ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, 356 &req->innerReq, &buf); 357 krb5_crypto_destroy(context, crypto); 358 crypto = NULL; 359 if (ret) 360 goto out; 361 362 ret = decode_DigestReqInner(buf.data, buf.length, &ireq, NULL); 363 krb5_data_free(&buf); 364 if (ret) { 365 krb5_set_error_message(context, ret, "Failed to decode digest inner request"); 366 goto out; 367 } 368 369 kdc_log(context, config, 0, "Valid digest request from %s (%s)", 370 client_name, from); 371 372 /* 373 * Process the inner request 374 */ 375 376 switch (ireq.element) { 377 case choice_DigestReqInner_init: { 378 unsigned char server_nonce[16], identifier; 379 380 RAND_pseudo_bytes(&identifier, sizeof(identifier)); 381 RAND_pseudo_bytes(server_nonce, sizeof(server_nonce)); 382 383 server_nonce[0] = kdc_time & 0xff; 384 server_nonce[1] = (kdc_time >> 8) & 0xff; 385 server_nonce[2] = (kdc_time >> 16) & 0xff; 386 server_nonce[3] = (kdc_time >> 24) & 0xff; 387 388 r.element = choice_DigestRepInner_initReply; 389 390 hex_encode(server_nonce, sizeof(server_nonce), &r.u.initReply.nonce); 391 if (r.u.initReply.nonce == NULL) { 392 ret = ENOMEM; 393 krb5_set_error_message(context, ret, "Failed to decode server nonce"); 394 goto out; 395 } 396 397 sp = krb5_storage_emem(); 398 if (sp == NULL) { 399 ret = ENOMEM; 400 krb5_set_error_message(context, ret, "malloc: out of memory"); 401 goto out; 402 } 403 ret = krb5_store_stringz(sp, ireq.u.init.type); 404 if (ret) { 405 krb5_clear_error_message(context); 406 goto out; 407 } 408 409 if (ireq.u.init.channel) { 410 char *s; 411 412 asprintf(&s, "%s-%s:%s", r.u.initReply.nonce, 413 ireq.u.init.channel->cb_type, 414 ireq.u.init.channel->cb_binding); 415 if (s == NULL) { 416 ret = ENOMEM; 417 krb5_set_error_message(context, ret, 418 "Failed to allocate channel binding"); 419 goto out; 420 } 421 free(r.u.initReply.nonce); 422 r.u.initReply.nonce = s; 423 } 424 425 ret = krb5_store_stringz(sp, r.u.initReply.nonce); 426 if (ret) { 427 krb5_clear_error_message(context); 428 goto out; 429 } 430 431 if (strcasecmp(ireq.u.init.type, "CHAP") == 0) { 432 r.u.initReply.identifier = 433 malloc(sizeof(*r.u.initReply.identifier)); 434 if (r.u.initReply.identifier == NULL) { 435 ret = ENOMEM; 436 krb5_set_error_message(context, ret, "malloc: out of memory"); 437 goto out; 438 } 439 440 asprintf(r.u.initReply.identifier, "%02X", identifier & 0xff); 441 if (*r.u.initReply.identifier == NULL) { 442 ret = ENOMEM; 443 krb5_set_error_message(context, ret, "malloc: out of memory"); 444 goto out; 445 } 446 447 } else 448 r.u.initReply.identifier = NULL; 449 450 if (ireq.u.init.hostname) { 451 ret = krb5_store_stringz(sp, *ireq.u.init.hostname); 452 if (ret) { 453 krb5_clear_error_message(context); 454 goto out; 455 } 456 } 457 458 ret = krb5_storage_to_data(sp, &buf); 459 if (ret) { 460 krb5_clear_error_message(context); 461 goto out; 462 } 463 464 ret = get_digest_key(context, config, server, &crypto); 465 if (ret) 466 goto out; 467 468 ret = krb5_create_checksum(context, 469 crypto, 470 KRB5_KU_DIGEST_OPAQUE, 471 0, 472 buf.data, 473 buf.length, 474 &res); 475 krb5_crypto_destroy(context, crypto); 476 crypto = NULL; 477 krb5_data_free(&buf); 478 if (ret) 479 goto out; 480 481 ASN1_MALLOC_ENCODE(Checksum, buf.data, buf.length, &res, &size, ret); 482 free_Checksum(&res); 483 if (ret) { 484 krb5_set_error_message(context, ret, "Failed to encode " 485 "checksum in digest request"); 486 goto out; 487 } 488 if (size != buf.length) 489 krb5_abortx(context, "ASN1 internal error"); 490 491 hex_encode(buf.data, buf.length, &r.u.initReply.opaque); 492 free(buf.data); 493 krb5_data_zero(&buf); 494 if (r.u.initReply.opaque == NULL) { 495 krb5_clear_error_message(context); 496 ret = ENOMEM; 497 goto out; 498 } 499 500 kdc_log(context, config, 0, "Digest %s init request successful from %s", 501 ireq.u.init.type, from); 502 503 break; 504 } 505 case choice_DigestReqInner_digestRequest: { 506 sp = krb5_storage_emem(); 507 if (sp == NULL) { 508 ret = ENOMEM; 509 krb5_set_error_message(context, ret, "malloc: out of memory"); 510 goto out; 511 } 512 ret = krb5_store_stringz(sp, ireq.u.digestRequest.type); 513 if (ret) { 514 krb5_clear_error_message(context); 515 goto out; 516 } 517 518 krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce); 519 520 if (ireq.u.digestRequest.hostname) { 521 ret = krb5_store_stringz(sp, *ireq.u.digestRequest.hostname); 522 if (ret) { 523 krb5_clear_error_message(context); 524 goto out; 525 } 526 } 527 528 buf.length = strlen(ireq.u.digestRequest.opaque); 529 buf.data = malloc(buf.length); 530 if (buf.data == NULL) { 531 ret = ENOMEM; 532 krb5_set_error_message(context, ret, "malloc: out of memory"); 533 goto out; 534 } 535 536 ret = hex_decode(ireq.u.digestRequest.opaque, buf.data, buf.length); 537 if (ret <= 0) { 538 ret = ENOMEM; 539 krb5_set_error_message(context, ret, "Failed to decode opaque"); 540 goto out; 541 } 542 buf.length = ret; 543 544 ret = decode_Checksum(buf.data, buf.length, &res, NULL); 545 free(buf.data); 546 krb5_data_zero(&buf); 547 if (ret) { 548 krb5_set_error_message(context, ret, 549 "Failed to decode digest Checksum"); 550 goto out; 551 } 552 553 ret = krb5_storage_to_data(sp, &buf); 554 if (ret) { 555 krb5_clear_error_message(context); 556 goto out; 557 } 558 559 serverNonce.length = strlen(ireq.u.digestRequest.serverNonce); 560 serverNonce.data = malloc(serverNonce.length); 561 if (serverNonce.data == NULL) { 562 ret = ENOMEM; 563 krb5_set_error_message(context, ret, "malloc: out of memory"); 564 goto out; 565 } 566 567 /* 568 * CHAP does the checksum of the raw nonce, but do it for all 569 * types, since we need to check the timestamp. 570 */ 571 { 572 ssize_t ssize; 573 574 ssize = hex_decode(ireq.u.digestRequest.serverNonce, 575 serverNonce.data, serverNonce.length); 576 if (ssize <= 0) { 577 ret = ENOMEM; 578 krb5_set_error_message(context, ret, "Failed to decode serverNonce"); 579 goto out; 580 } 581 serverNonce.length = ssize; 582 } 583 584 ret = get_digest_key(context, config, server, &crypto); 585 if (ret) 586 goto out; 587 588 ret = krb5_verify_checksum(context, crypto, 589 KRB5_KU_DIGEST_OPAQUE, 590 buf.data, buf.length, &res); 591 free_Checksum(&res); 592 krb5_data_free(&buf); 593 krb5_crypto_destroy(context, crypto); 594 crypto = NULL; 595 if (ret) 596 goto out; 597 598 /* verify time */ 599 { 600 unsigned char *p = serverNonce.data; 601 uint32_t t; 602 603 if (serverNonce.length < 4) { 604 ret = EINVAL; 605 krb5_set_error_message(context, ret, "server nonce too short"); 606 goto out; 607 } 608 t = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 609 610 if (abs((kdc_time & 0xffffffff) - t) > context->max_skew) { 611 ret = EINVAL; 612 krb5_set_error_message(context, ret, "time screw in server nonce "); 613 goto out; 614 } 615 } 616 617 if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) { 618 EVP_MD_CTX *ctx; 619 unsigned char md[MD5_DIGEST_LENGTH]; 620 char *mdx; 621 char idx; 622 623 if ((config->digests_allowed & CHAP_MD5) == 0) { 624 kdc_log(context, config, 0, "Digest CHAP MD5 not allowed"); 625 goto out; 626 } 627 628 if (ireq.u.digestRequest.identifier == NULL) { 629 ret = EINVAL; 630 krb5_set_error_message(context, ret, "Identifier missing " 631 "from CHAP request"); 632 goto out; 633 } 634 635 if (hex_decode(*ireq.u.digestRequest.identifier, &idx, 1) != 1) { 636 ret = EINVAL; 637 krb5_set_error_message(context, ret, "failed to decode identifier"); 638 goto out; 639 } 640 641 ret = get_password_entry(context, config, 642 ireq.u.digestRequest.username, 643 &password); 644 if (ret) 645 goto out; 646 647 ctx = EVP_MD_CTX_create(); 648 649 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 650 EVP_DigestUpdate(ctx, &idx, 1); 651 EVP_DigestUpdate(ctx, password, strlen(password)); 652 EVP_DigestUpdate(ctx, serverNonce.data, serverNonce.length); 653 EVP_DigestFinal_ex(ctx, md, NULL); 654 655 EVP_MD_CTX_destroy(ctx); 656 657 hex_encode(md, sizeof(md), &mdx); 658 if (mdx == NULL) { 659 krb5_clear_error_message(context); 660 ret = ENOMEM; 661 goto out; 662 } 663 664 r.element = choice_DigestRepInner_response; 665 666 ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 667 free(mdx); 668 if (ret == 0) { 669 r.u.response.success = TRUE; 670 } else { 671 kdc_log(context, config, 0, 672 "CHAP reply mismatch for %s", 673 ireq.u.digestRequest.username); 674 r.u.response.success = FALSE; 675 } 676 677 } else if (strcasecmp(ireq.u.digestRequest.type, "SASL-DIGEST-MD5") == 0) { 678 EVP_MD_CTX *ctx; 679 unsigned char md[MD5_DIGEST_LENGTH]; 680 char *mdx; 681 char *A1, *A2; 682 683 if ((config->digests_allowed & DIGEST_MD5) == 0) { 684 kdc_log(context, config, 0, "Digest SASL MD5 not allowed"); 685 goto out; 686 } 687 688 if (ireq.u.digestRequest.nonceCount == NULL) 689 goto out; 690 if (ireq.u.digestRequest.clientNonce == NULL) 691 goto out; 692 if (ireq.u.digestRequest.qop == NULL) 693 goto out; 694 if (ireq.u.digestRequest.realm == NULL) 695 goto out; 696 697 ret = get_password_entry(context, config, 698 ireq.u.digestRequest.username, 699 &password); 700 if (ret) 701 goto failed; 702 703 ctx = EVP_MD_CTX_create(); 704 705 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 706 EVP_DigestUpdate(ctx, ireq.u.digestRequest.username, 707 strlen(ireq.u.digestRequest.username)); 708 EVP_DigestUpdate(ctx, ":", 1); 709 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.realm, 710 strlen(*ireq.u.digestRequest.realm)); 711 EVP_DigestUpdate(ctx, ":", 1); 712 EVP_DigestUpdate(ctx, password, strlen(password)); 713 EVP_DigestFinal_ex(ctx, md, NULL); 714 715 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 716 EVP_DigestUpdate(ctx, md, sizeof(md)); 717 EVP_DigestUpdate(ctx, ":", 1); 718 EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce, 719 strlen(ireq.u.digestRequest.serverNonce)); 720 EVP_DigestUpdate(ctx, ":", 1); 721 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount, 722 strlen(*ireq.u.digestRequest.nonceCount)); 723 if (ireq.u.digestRequest.authid) { 724 EVP_DigestUpdate(ctx, ":", 1); 725 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.authid, 726 strlen(*ireq.u.digestRequest.authid)); 727 } 728 EVP_DigestFinal_ex(ctx, md, NULL); 729 hex_encode(md, sizeof(md), &A1); 730 if (A1 == NULL) { 731 ret = ENOMEM; 732 krb5_set_error_message(context, ret, "malloc: out of memory"); 733 EVP_MD_CTX_destroy(ctx); 734 goto failed; 735 } 736 737 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 738 EVP_DigestUpdate(ctx, 739 "AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1); 740 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.uri, 741 strlen(*ireq.u.digestRequest.uri)); 742 743 /* conf|int */ 744 if (strcmp(ireq.u.digestRequest.digest, "clear") != 0) { 745 static char conf_zeros[] = ":00000000000000000000000000000000"; 746 EVP_DigestUpdate(ctx, conf_zeros, sizeof(conf_zeros) - 1); 747 } 748 749 EVP_DigestFinal_ex(ctx, md, NULL); 750 751 hex_encode(md, sizeof(md), &A2); 752 if (A2 == NULL) { 753 ret = ENOMEM; 754 krb5_set_error_message(context, ret, "malloc: out of memory"); 755 free(A1); 756 goto failed; 757 } 758 759 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 760 EVP_DigestUpdate(ctx, A1, strlen(A2)); 761 EVP_DigestUpdate(ctx, ":", 1); 762 EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce, 763 strlen(ireq.u.digestRequest.serverNonce)); 764 EVP_DigestUpdate(ctx, ":", 1); 765 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount, 766 strlen(*ireq.u.digestRequest.nonceCount)); 767 EVP_DigestUpdate(ctx, ":", 1); 768 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.clientNonce, 769 strlen(*ireq.u.digestRequest.clientNonce)); 770 EVP_DigestUpdate(ctx, ":", 1); 771 EVP_DigestUpdate(ctx, *ireq.u.digestRequest.qop, 772 strlen(*ireq.u.digestRequest.qop)); 773 EVP_DigestUpdate(ctx, ":", 1); 774 EVP_DigestUpdate(ctx, A2, strlen(A2)); 775 776 EVP_DigestFinal_ex(ctx, md, NULL); 777 778 EVP_MD_CTX_destroy(ctx); 779 780 free(A1); 781 free(A2); 782 783 hex_encode(md, sizeof(md), &mdx); 784 if (mdx == NULL) { 785 krb5_clear_error_message(context); 786 ret = ENOMEM; 787 goto out; 788 } 789 790 r.element = choice_DigestRepInner_response; 791 ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 792 free(mdx); 793 if (ret == 0) { 794 r.u.response.success = TRUE; 795 } else { 796 kdc_log(context, config, 0, 797 "DIGEST-MD5 reply mismatch for %s", 798 ireq.u.digestRequest.username); 799 r.u.response.success = FALSE; 800 } 801 802 } else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) { 803 unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH]; 804 krb5_principal clientprincipal = NULL; 805 char *mdx; 806 const char *username; 807 struct ntlm_buf answer; 808 Key *key = NULL; 809 EVP_MD_CTX *ctp; 810 811 if ((config->digests_allowed & MS_CHAP_V2) == 0) { 812 kdc_log(context, config, 0, "MS-CHAP-V2 not allowed"); 813 goto failed; 814 } 815 816 if (ireq.u.digestRequest.clientNonce == NULL) { 817 ret = EINVAL; 818 krb5_set_error_message(context, ret, 819 "MS-CHAP-V2 clientNonce missing"); 820 goto failed; 821 } 822 if (serverNonce.length != 16) { 823 ret = EINVAL; 824 krb5_set_error_message(context, ret, 825 "MS-CHAP-V2 serverNonce wrong length"); 826 goto failed; 827 } 828 829 /* strip of the domain component */ 830 username = strchr(ireq.u.digestRequest.username, '\\'); 831 if (username == NULL) 832 username = ireq.u.digestRequest.username; 833 else 834 username++; 835 836 ctp = EVP_MD_CTX_create(); 837 838 /* ChallangeHash */ 839 EVP_DigestInit_ex(ctp, EVP_sha1(), NULL); 840 { 841 ssize_t ssize; 842 krb5_data clientNonce; 843 844 clientNonce.length = strlen(*ireq.u.digestRequest.clientNonce); 845 clientNonce.data = malloc(clientNonce.length); 846 if (clientNonce.data == NULL) { 847 ret = ENOMEM; 848 krb5_set_error_message(context, ret, 849 "malloc: out of memory"); 850 EVP_MD_CTX_destroy(ctp); 851 goto out; 852 } 853 854 ssize = hex_decode(*ireq.u.digestRequest.clientNonce, 855 clientNonce.data, clientNonce.length); 856 if (ssize != 16) { 857 ret = ENOMEM; 858 krb5_set_error_message(context, ret, 859 "Failed to decode clientNonce"); 860 EVP_MD_CTX_destroy(ctp); 861 goto out; 862 } 863 EVP_DigestUpdate(ctp, clientNonce.data, ssize); 864 free(clientNonce.data); 865 } 866 EVP_DigestUpdate(ctp, serverNonce.data, serverNonce.length); 867 EVP_DigestUpdate(ctp, username, strlen(username)); 868 869 EVP_DigestFinal_ex(ctp, challange, NULL); 870 871 EVP_MD_CTX_destroy(ctp); 872 873 /* NtPasswordHash */ 874 ret = krb5_parse_name(context, username, &clientprincipal); 875 if (ret) 876 goto failed; 877 878 ret = _kdc_db_fetch(context, config, clientprincipal, 879 HDB_F_GET_CLIENT, NULL, NULL, &user); 880 krb5_free_principal(context, clientprincipal); 881 if (ret) { 882 krb5_set_error_message(context, ret, 883 "MS-CHAP-V2 user %s not in database", 884 username); 885 goto failed; 886 } 887 888 ret = hdb_enctype2key(context, &user->entry, 889 ETYPE_ARCFOUR_HMAC_MD5, &key); 890 if (ret) { 891 krb5_set_error_message(context, ret, 892 "MS-CHAP-V2 missing arcfour key %s", 893 username); 894 goto failed; 895 } 896 897 /* ChallengeResponse */ 898 ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 899 key->key.keyvalue.length, 900 challange, &answer); 901 if (ret) { 902 krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 903 goto failed; 904 } 905 906 hex_encode(answer.data, answer.length, &mdx); 907 if (mdx == NULL) { 908 free(answer.data); 909 krb5_clear_error_message(context); 910 ret = ENOMEM; 911 goto out; 912 } 913 914 r.element = choice_DigestRepInner_response; 915 ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 916 if (ret == 0) { 917 r.u.response.success = TRUE; 918 } else { 919 kdc_log(context, config, 0, 920 "MS-CHAP-V2 hash mismatch for %s", 921 ireq.u.digestRequest.username); 922 r.u.response.success = FALSE; 923 } 924 free(mdx); 925 926 if (r.u.response.success) { 927 unsigned char hashhash[MD4_DIGEST_LENGTH]; 928 EVP_MD_CTX *ctxp; 929 930 ctxp = EVP_MD_CTX_create(); 931 932 /* hashhash */ 933 { 934 EVP_DigestInit_ex(ctxp, EVP_md4(), NULL); 935 EVP_DigestUpdate(ctxp, 936 key->key.keyvalue.data, 937 key->key.keyvalue.length); 938 EVP_DigestFinal_ex(ctxp, hashhash, NULL); 939 } 940 941 /* GenerateAuthenticatorResponse */ 942 EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 943 EVP_DigestUpdate(ctxp, hashhash, sizeof(hashhash)); 944 EVP_DigestUpdate(ctxp, answer.data, answer.length); 945 EVP_DigestUpdate(ctxp, ms_chap_v2_magic1, 946 sizeof(ms_chap_v2_magic1)); 947 EVP_DigestFinal_ex(ctxp, md, NULL); 948 949 EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 950 EVP_DigestUpdate(ctxp, md, sizeof(md)); 951 EVP_DigestUpdate(ctxp, challange, 8); 952 EVP_DigestUpdate(ctxp, ms_chap_v2_magic2, 953 sizeof(ms_chap_v2_magic2)); 954 EVP_DigestFinal_ex(ctxp, md, NULL); 955 956 r.u.response.rsp = calloc(1, sizeof(*r.u.response.rsp)); 957 if (r.u.response.rsp == NULL) { 958 free(answer.data); 959 krb5_clear_error_message(context); 960 EVP_MD_CTX_destroy(ctxp); 961 ret = ENOMEM; 962 goto out; 963 } 964 965 hex_encode(md, sizeof(md), r.u.response.rsp); 966 if (r.u.response.rsp == NULL) { 967 free(answer.data); 968 krb5_clear_error_message(context); 969 EVP_MD_CTX_destroy(ctxp); 970 ret = ENOMEM; 971 goto out; 972 } 973 974 /* get_master, rfc 3079 3.4 */ 975 EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 976 EVP_DigestUpdate(ctxp, hashhash, 16); 977 EVP_DigestUpdate(ctxp, answer.data, answer.length); 978 EVP_DigestUpdate(ctxp, ms_rfc3079_magic1, 979 sizeof(ms_rfc3079_magic1)); 980 EVP_DigestFinal_ex(ctxp, md, NULL); 981 982 free(answer.data); 983 984 EVP_MD_CTX_destroy(ctxp); 985 986 r.u.response.session_key = 987 calloc(1, sizeof(*r.u.response.session_key)); 988 if (r.u.response.session_key == NULL) { 989 krb5_clear_error_message(context); 990 ret = ENOMEM; 991 goto out; 992 } 993 994 ret = krb5_data_copy(r.u.response.session_key, md, 16); 995 if (ret) { 996 krb5_clear_error_message(context); 997 goto out; 998 } 999 } 1000 1001 } else { 1002 r.element = choice_DigestRepInner_error; 1003 asprintf(&r.u.error.reason, "Unsupported digest type %s", 1004 ireq.u.digestRequest.type); 1005 if (r.u.error.reason == NULL) { 1006 ret = ENOMEM; 1007 krb5_set_error_message(context, ret, "malloc: out of memory"); 1008 goto out; 1009 } 1010 r.u.error.code = EINVAL; 1011 } 1012 1013 kdc_log(context, config, 0, "Digest %s request successful %s", 1014 ireq.u.digestRequest.type, ireq.u.digestRequest.username); 1015 1016 break; 1017 } 1018 case choice_DigestReqInner_ntlmInit: 1019 1020 if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) { 1021 kdc_log(context, config, 0, "NTLM not allowed"); 1022 goto failed; 1023 } 1024 1025 r.element = choice_DigestRepInner_ntlmInitReply; 1026 1027 r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE; 1028 1029 if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) { 1030 kdc_log(context, config, 0, "NTLM client have no unicode"); 1031 goto failed; 1032 } 1033 1034 if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM) 1035 r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM; 1036 else { 1037 kdc_log(context, config, 0, "NTLM client doesn't support NTLM"); 1038 goto failed; 1039 } 1040 1041 r.u.ntlmInitReply.flags |= 1042 NTLM_NEG_TARGET | 1043 NTLM_TARGET_DOMAIN | 1044 NTLM_ENC_128; 1045 1046 #define ALL \ 1047 NTLM_NEG_SIGN| \ 1048 NTLM_NEG_SEAL| \ 1049 NTLM_NEG_ALWAYS_SIGN| \ 1050 NTLM_NEG_NTLM2_SESSION| \ 1051 NTLM_NEG_KEYEX 1052 1053 r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL)); 1054 1055 #undef ALL 1056 1057 r.u.ntlmInitReply.targetname = 1058 get_ntlm_targetname(context, client); 1059 if (r.u.ntlmInitReply.targetname == NULL) { 1060 ret = ENOMEM; 1061 krb5_set_error_message(context, ret, "malloc: out of memory"); 1062 goto out; 1063 } 1064 r.u.ntlmInitReply.challange.data = malloc(8); 1065 if (r.u.ntlmInitReply.challange.data == NULL) { 1066 ret = ENOMEM; 1067 krb5_set_error_message(context, ret, "malloc: out of memory"); 1068 goto out; 1069 } 1070 r.u.ntlmInitReply.challange.length = 8; 1071 if (RAND_bytes(r.u.ntlmInitReply.challange.data, 1072 r.u.ntlmInitReply.challange.length) != 1) 1073 { 1074 ret = ENOMEM; 1075 krb5_set_error_message(context, ret, "out of random error"); 1076 goto out; 1077 } 1078 /* XXX fix targetinfo */ 1079 ALLOC(r.u.ntlmInitReply.targetinfo); 1080 if (r.u.ntlmInitReply.targetinfo == NULL) { 1081 ret = ENOMEM; 1082 krb5_set_error_message(context, ret, "malloc: out of memory"); 1083 goto out; 1084 } 1085 1086 ret = fill_targetinfo(context, 1087 r.u.ntlmInitReply.targetname, 1088 client, 1089 r.u.ntlmInitReply.targetinfo); 1090 if (ret) { 1091 ret = ENOMEM; 1092 krb5_set_error_message(context, ret, "malloc: out of memory"); 1093 goto out; 1094 } 1095 1096 /* 1097 * Save data encryted in opaque for the second part of the 1098 * ntlm authentication 1099 */ 1100 sp = krb5_storage_emem(); 1101 if (sp == NULL) { 1102 ret = ENOMEM; 1103 krb5_set_error_message(context, ret, "malloc: out of memory"); 1104 goto out; 1105 } 1106 1107 ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8); 1108 if (ret != 8) { 1109 ret = ENOMEM; 1110 krb5_set_error_message(context, ret, "storage write challange"); 1111 goto out; 1112 } 1113 ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags); 1114 if (ret) { 1115 krb5_clear_error_message(context); 1116 goto out; 1117 } 1118 1119 ret = krb5_storage_to_data(sp, &buf); 1120 if (ret) { 1121 krb5_clear_error_message(context); 1122 goto out; 1123 } 1124 1125 ret = get_digest_key(context, config, server, &crypto); 1126 if (ret) 1127 goto out; 1128 1129 ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, 1130 buf.data, buf.length, &r.u.ntlmInitReply.opaque); 1131 krb5_data_free(&buf); 1132 krb5_crypto_destroy(context, crypto); 1133 crypto = NULL; 1134 if (ret) 1135 goto out; 1136 1137 kdc_log(context, config, 0, "NTLM init from %s", from); 1138 1139 break; 1140 1141 case choice_DigestReqInner_ntlmRequest: { 1142 krb5_principal clientprincipal; 1143 unsigned char sessionkey[16]; 1144 unsigned char challange[8]; 1145 uint32_t flags; 1146 Key *key = NULL; 1147 int version; 1148 1149 r.element = choice_DigestRepInner_ntlmResponse; 1150 r.u.ntlmResponse.success = 0; 1151 r.u.ntlmResponse.flags = 0; 1152 r.u.ntlmResponse.sessionkey = NULL; 1153 r.u.ntlmResponse.tickets = NULL; 1154 1155 /* get username */ 1156 ret = krb5_parse_name(context, 1157 ireq.u.ntlmRequest.username, 1158 &clientprincipal); 1159 if (ret) 1160 goto failed; 1161 1162 ret = _kdc_db_fetch(context, config, clientprincipal, 1163 HDB_F_GET_CLIENT, NULL, NULL, &user); 1164 krb5_free_principal(context, clientprincipal); 1165 if (ret) { 1166 krb5_set_error_message(context, ret, "NTLM user %s not in database", 1167 ireq.u.ntlmRequest.username); 1168 goto failed; 1169 } 1170 1171 ret = get_digest_key(context, config, server, &crypto); 1172 if (ret) 1173 goto failed; 1174 1175 ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, 1176 ireq.u.ntlmRequest.opaque.data, 1177 ireq.u.ntlmRequest.opaque.length, &buf); 1178 krb5_crypto_destroy(context, crypto); 1179 crypto = NULL; 1180 if (ret) { 1181 kdc_log(context, config, 0, 1182 "Failed to decrypt nonce from %s", from); 1183 goto failed; 1184 } 1185 1186 sp = krb5_storage_from_data(&buf); 1187 if (sp == NULL) { 1188 ret = ENOMEM; 1189 krb5_set_error_message(context, ret, "malloc: out of memory"); 1190 goto out; 1191 } 1192 1193 ret = krb5_storage_read(sp, challange, sizeof(challange)); 1194 if (ret != sizeof(challange)) { 1195 ret = ENOMEM; 1196 krb5_set_error_message(context, ret, "NTLM storage read challange"); 1197 goto out; 1198 } 1199 ret = krb5_ret_uint32(sp, &flags); 1200 if (ret) { 1201 krb5_set_error_message(context, ret, "NTLM storage read flags"); 1202 goto out; 1203 } 1204 krb5_storage_free(sp); 1205 sp = NULL; 1206 krb5_data_free(&buf); 1207 1208 if ((flags & NTLM_NEG_NTLM) == 0) { 1209 ret = EINVAL; 1210 krb5_set_error_message(context, ret, "NTLM not negotiated"); 1211 goto out; 1212 } 1213 1214 ret = hdb_enctype2key(context, &user->entry, 1215 ETYPE_ARCFOUR_HMAC_MD5, &key); 1216 if (ret) { 1217 krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 1218 goto out; 1219 } 1220 1221 /* check if this is NTLMv2 */ 1222 if (ireq.u.ntlmRequest.ntlm.length != 24) { 1223 struct ntlm_buf infotarget, answer; 1224 char *targetname; 1225 1226 if ((config->digests_allowed & NTLM_V2) == 0) { 1227 kdc_log(context, config, 0, "NTLM v2 not allowed"); 1228 goto out; 1229 } 1230 1231 version = 2; 1232 1233 targetname = get_ntlm_targetname(context, client); 1234 if (targetname == NULL) { 1235 ret = ENOMEM; 1236 krb5_set_error_message(context, ret, "malloc: out of memory"); 1237 goto out; 1238 } 1239 1240 answer.length = ireq.u.ntlmRequest.ntlm.length; 1241 answer.data = ireq.u.ntlmRequest.ntlm.data; 1242 1243 ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, 1244 key->key.keyvalue.length, 1245 ireq.u.ntlmRequest.username, 1246 targetname, 1247 0, 1248 challange, 1249 &answer, 1250 &infotarget, 1251 sessionkey); 1252 free(targetname); 1253 if (ret) { 1254 krb5_set_error_message(context, ret, "NTLM v2 verify failed"); 1255 goto failed; 1256 } 1257 1258 /* XXX verify infotarget matches client (checksum ?) */ 1259 1260 free(infotarget.data); 1261 /* */ 1262 1263 } else { 1264 struct ntlm_buf answer; 1265 1266 version = 1; 1267 1268 if (flags & NTLM_NEG_NTLM2_SESSION) { 1269 unsigned char sessionhash[MD5_DIGEST_LENGTH]; 1270 EVP_MD_CTX *ctx; 1271 1272 if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { 1273 kdc_log(context, config, 0, "NTLM v1-session not allowed"); 1274 ret = EINVAL; 1275 goto failed; 1276 } 1277 1278 if (ireq.u.ntlmRequest.lm.length != 24) { 1279 ret = EINVAL; 1280 krb5_set_error_message(context, ret, "LM hash have wrong length " 1281 "for NTLM session key"); 1282 goto failed; 1283 } 1284 1285 ctx = EVP_MD_CTX_create(); 1286 1287 EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 1288 1289 EVP_DigestUpdate(ctx, challange, sizeof(challange)); 1290 EVP_DigestUpdate(ctx, ireq.u.ntlmRequest.lm.data, 8); 1291 EVP_DigestFinal_ex(ctx, sessionhash, NULL); 1292 memcpy(challange, sessionhash, sizeof(challange)); 1293 1294 EVP_MD_CTX_destroy(ctx); 1295 1296 } else { 1297 if ((config->digests_allowed & NTLM_V1) == 0) { 1298 kdc_log(context, config, 0, "NTLM v1 not allowed"); 1299 goto failed; 1300 } 1301 } 1302 1303 ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 1304 key->key.keyvalue.length, 1305 challange, &answer); 1306 if (ret) { 1307 krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 1308 goto failed; 1309 } 1310 1311 if (ireq.u.ntlmRequest.ntlm.length != answer.length || 1312 memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0) 1313 { 1314 free(answer.data); 1315 ret = EINVAL; 1316 krb5_set_error_message(context, ret, "NTLM hash mismatch"); 1317 goto failed; 1318 } 1319 free(answer.data); 1320 1321 { 1322 EVP_MD_CTX *ctx; 1323 1324 ctx = EVP_MD_CTX_create(); 1325 1326 EVP_DigestInit_ex(ctx, EVP_md4(), NULL); 1327 EVP_DigestUpdate(ctx, 1328 key->key.keyvalue.data, 1329 key->key.keyvalue.length); 1330 EVP_DigestFinal_ex(ctx, sessionkey, NULL); 1331 1332 EVP_MD_CTX_destroy(ctx); 1333 } 1334 } 1335 1336 if (ireq.u.ntlmRequest.sessionkey) { 1337 unsigned char masterkey[MD4_DIGEST_LENGTH]; 1338 EVP_CIPHER_CTX rc4; 1339 size_t len; 1340 1341 if ((flags & NTLM_NEG_KEYEX) == 0) { 1342 ret = EINVAL; 1343 krb5_set_error_message(context, ret, 1344 "NTLM client failed to neg key " 1345 "exchange but still sent key"); 1346 goto failed; 1347 } 1348 1349 len = ireq.u.ntlmRequest.sessionkey->length; 1350 if (len != sizeof(masterkey)){ 1351 ret = EINVAL; 1352 krb5_set_error_message(context, ret, 1353 "NTLM master key wrong length: %lu", 1354 (unsigned long)len); 1355 goto failed; 1356 } 1357 1358 1359 EVP_CIPHER_CTX_init(&rc4); 1360 EVP_CipherInit_ex(&rc4, EVP_rc4(), NULL, sessionkey, NULL, 1); 1361 EVP_Cipher(&rc4, 1362 masterkey, ireq.u.ntlmRequest.sessionkey->data, 1363 sizeof(masterkey)); 1364 EVP_CIPHER_CTX_cleanup(&rc4); 1365 1366 r.u.ntlmResponse.sessionkey = 1367 malloc(sizeof(*r.u.ntlmResponse.sessionkey)); 1368 if (r.u.ntlmResponse.sessionkey == NULL) { 1369 ret = EINVAL; 1370 krb5_set_error_message(context, ret, "malloc: out of memory"); 1371 goto out; 1372 } 1373 1374 ret = krb5_data_copy(r.u.ntlmResponse.sessionkey, 1375 masterkey, sizeof(masterkey)); 1376 if (ret) { 1377 krb5_set_error_message(context, ret, "malloc: out of memory"); 1378 goto out; 1379 } 1380 } 1381 1382 r.u.ntlmResponse.success = 1; 1383 kdc_log(context, config, 0, "NTLM version %d successful for %s", 1384 version, ireq.u.ntlmRequest.username); 1385 break; 1386 } 1387 case choice_DigestReqInner_supportedMechs: 1388 1389 kdc_log(context, config, 0, "digest supportedMechs from %s", from); 1390 1391 r.element = choice_DigestRepInner_supportedMechs; 1392 memset(&r.u.supportedMechs, 0, sizeof(r.u.supportedMechs)); 1393 1394 if (config->digests_allowed & NTLM_V1) 1395 r.u.supportedMechs.ntlm_v1 = 1; 1396 if (config->digests_allowed & NTLM_V1_SESSION) 1397 r.u.supportedMechs.ntlm_v1_session = 1; 1398 if (config->digests_allowed & NTLM_V2) 1399 r.u.supportedMechs.ntlm_v2 = 1; 1400 if (config->digests_allowed & DIGEST_MD5) 1401 r.u.supportedMechs.digest_md5 = 1; 1402 if (config->digests_allowed & CHAP_MD5) 1403 r.u.supportedMechs.chap_md5 = 1; 1404 if (config->digests_allowed & MS_CHAP_V2) 1405 r.u.supportedMechs.ms_chap_v2 = 1; 1406 break; 1407 1408 default: { 1409 const char *s; 1410 ret = EINVAL; 1411 krb5_set_error_message(context, ret, "unknown operation to digest"); 1412 1413 failed: 1414 1415 s = krb5_get_error_message(context, ret); 1416 if (s == NULL) { 1417 krb5_clear_error_message(context); 1418 goto out; 1419 } 1420 1421 kdc_log(context, config, 0, "Digest failed with: %s", s); 1422 1423 r.element = choice_DigestRepInner_error; 1424 r.u.error.reason = strdup("unknown error"); 1425 krb5_free_error_message(context, s); 1426 if (r.u.error.reason == NULL) { 1427 ret = ENOMEM; 1428 krb5_set_error_message(context, ret, "malloc: out of memory"); 1429 goto out; 1430 } 1431 r.u.error.code = EINVAL; 1432 break; 1433 } 1434 } 1435 1436 ASN1_MALLOC_ENCODE(DigestRepInner, buf.data, buf.length, &r, &size, ret); 1437 if (ret) { 1438 krb5_set_error_message(context, ret, "Failed to encode inner digest reply"); 1439 goto out; 1440 } 1441 if (size != buf.length) 1442 krb5_abortx(context, "ASN1 internal error"); 1443 1444 krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL); 1445 1446 ret = krb5_mk_rep (context, ac, &rep.apRep); 1447 if (ret) 1448 goto out; 1449 1450 { 1451 krb5_keyblock *key; 1452 1453 ret = krb5_auth_con_getlocalsubkey(context, ac, &key); 1454 if (ret) 1455 goto out; 1456 1457 ret = krb5_crypto_init(context, key, 0, &crypto); 1458 krb5_free_keyblock (context, key); 1459 if (ret) 1460 goto out; 1461 } 1462 1463 ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, 1464 buf.data, buf.length, 0, 1465 &rep.innerRep); 1466 1467 ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret); 1468 if (ret) { 1469 krb5_set_error_message(context, ret, "Failed to encode digest reply"); 1470 goto out; 1471 } 1472 if (size != reply->length) 1473 krb5_abortx(context, "ASN1 internal error"); 1474 1475 1476 out: 1477 if (ac) 1478 krb5_auth_con_free(context, ac); 1479 if (ret) 1480 krb5_warn(context, ret, "Digest request from %s failed", from); 1481 if (ticket) 1482 krb5_free_ticket(context, ticket); 1483 if (id) 1484 krb5_kt_close(context, id); 1485 if (crypto) 1486 krb5_crypto_destroy(context, crypto); 1487 if (sp) 1488 krb5_storage_free(sp); 1489 if (user) 1490 _kdc_free_ent (context, user); 1491 if (server) 1492 _kdc_free_ent (context, server); 1493 if (client) 1494 _kdc_free_ent (context, client); 1495 if (password) { 1496 memset(password, 0, strlen(password)); 1497 free (password); 1498 } 1499 if (client_name) 1500 free (client_name); 1501 krb5_data_free(&buf); 1502 krb5_data_free(&serverNonce); 1503 free_Checksum(&res); 1504 free_DigestREP(&rep); 1505 free_DigestRepInner(&r); 1506 free_DigestReqInner(&ireq); 1507 1508 return ret; 1509 } 1510 1511 #endif /* DIGEST */ 1512