1178825Sdfr/* 2233294Sstas * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "kdc_locl.h" 35178825Sdfr#include <hex.h> 36178825Sdfr 37233294Sstas#ifdef DIGEST 38178825Sdfr 39178825Sdfr#define MS_CHAP_V2 0x20 40178825Sdfr#define CHAP_MD5 0x10 41178825Sdfr#define DIGEST_MD5 0x08 42178825Sdfr#define NTLM_V2 0x04 43178825Sdfr#define NTLM_V1_SESSION 0x02 44178825Sdfr#define NTLM_V1 0x01 45178825Sdfr 46178825Sdfrconst struct units _kdc_digestunits[] = { 47233294Sstas {"ms-chap-v2", 1U << 5}, 48233294Sstas {"chap-md5", 1U << 4}, 49233294Sstas {"digest-md5", 1U << 3}, 50233294Sstas {"ntlm-v2", 1U << 2}, 51233294Sstas {"ntlm-v1-session", 1U << 1}, 52233294Sstas {"ntlm-v1", 1U << 0}, 53233294Sstas {NULL, 0} 54178825Sdfr}; 55178825Sdfr 56178825Sdfr 57178825Sdfrstatic krb5_error_code 58178825Sdfrget_digest_key(krb5_context context, 59178825Sdfr krb5_kdc_configuration *config, 60178825Sdfr hdb_entry_ex *server, 61178825Sdfr krb5_crypto *crypto) 62178825Sdfr{ 63178825Sdfr krb5_error_code ret; 64178825Sdfr krb5_enctype enctype; 65178825Sdfr Key *key; 66233294Sstas 67178825Sdfr ret = _kdc_get_preferred_key(context, 68178825Sdfr config, 69178825Sdfr server, 70178825Sdfr "digest-service", 71178825Sdfr &enctype, 72178825Sdfr &key); 73178825Sdfr if (ret) 74178825Sdfr return ret; 75178825Sdfr return krb5_crypto_init(context, &key->key, 0, crypto); 76178825Sdfr} 77178825Sdfr 78178825Sdfr/* 79178825Sdfr * 80178825Sdfr */ 81178825Sdfr 82178825Sdfrstatic char * 83178825Sdfrget_ntlm_targetname(krb5_context context, 84178825Sdfr hdb_entry_ex *client) 85178825Sdfr{ 86178825Sdfr char *targetname, *p; 87178825Sdfr 88178825Sdfr targetname = strdup(krb5_principal_get_realm(context, 89178825Sdfr client->entry.principal)); 90178825Sdfr if (targetname == NULL) 91178825Sdfr return NULL; 92178825Sdfr 93178825Sdfr p = strchr(targetname, '.'); 94178825Sdfr if (p) 95178825Sdfr *p = '\0'; 96178825Sdfr 97178825Sdfr strupr(targetname); 98178825Sdfr return targetname; 99178825Sdfr} 100178825Sdfr 101178825Sdfrstatic krb5_error_code 102178825Sdfrfill_targetinfo(krb5_context context, 103178825Sdfr char *targetname, 104178825Sdfr hdb_entry_ex *client, 105178825Sdfr krb5_data *data) 106178825Sdfr{ 107178825Sdfr struct ntlm_targetinfo ti; 108178825Sdfr krb5_error_code ret; 109178825Sdfr struct ntlm_buf d; 110178825Sdfr krb5_principal p; 111178825Sdfr const char *str; 112178825Sdfr 113178825Sdfr memset(&ti, 0, sizeof(ti)); 114178825Sdfr 115178825Sdfr ti.domainname = targetname; 116178825Sdfr p = client->entry.principal; 117178825Sdfr str = krb5_principal_get_comp_string(context, p, 0); 118233294Sstas if (str != NULL && 119233294Sstas (strcmp("host", str) == 0 || 120178825Sdfr strcmp("ftp", str) == 0 || 121178825Sdfr strcmp("imap", str) == 0 || 122178825Sdfr strcmp("pop", str) == 0 || 123178825Sdfr strcmp("smtp", str))) 124233294Sstas { 125233294Sstas str = krb5_principal_get_comp_string(context, p, 1); 126233294Sstas ti.dnsservername = rk_UNCONST(str); 127233294Sstas } 128233294Sstas 129178825Sdfr ret = heim_ntlm_encode_targetinfo(&ti, 1, &d); 130178825Sdfr if (ret) 131178825Sdfr return ret; 132178825Sdfr 133178825Sdfr data->data = d.data; 134178825Sdfr data->length = d.length; 135178825Sdfr 136178825Sdfr return 0; 137178825Sdfr} 138178825Sdfr 139178825Sdfr 140178825Sdfrstatic const unsigned char ms_chap_v2_magic1[39] = { 141178825Sdfr 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 142178825Sdfr 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 143178825Sdfr 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 144178825Sdfr 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 145178825Sdfr}; 146178825Sdfrstatic const unsigned char ms_chap_v2_magic2[41] = { 147178825Sdfr 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 148178825Sdfr 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 149178825Sdfr 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 150178825Sdfr 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 151178825Sdfr 0x6E 152178825Sdfr}; 153178825Sdfrstatic const unsigned char ms_rfc3079_magic1[27] = { 154178825Sdfr 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 155178825Sdfr 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 156178825Sdfr 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 157178825Sdfr}; 158178825Sdfr 159178825Sdfr/* 160178825Sdfr * 161178825Sdfr */ 162178825Sdfr 163178825Sdfrstatic krb5_error_code 164178825Sdfrget_password_entry(krb5_context context, 165178825Sdfr krb5_kdc_configuration *config, 166178825Sdfr const char *username, 167178825Sdfr char **password) 168178825Sdfr{ 169178825Sdfr krb5_principal clientprincipal; 170178825Sdfr krb5_error_code ret; 171178825Sdfr hdb_entry_ex *user; 172178825Sdfr HDB *db; 173178825Sdfr 174178825Sdfr /* get username */ 175178825Sdfr ret = krb5_parse_name(context, username, &clientprincipal); 176178825Sdfr if (ret) 177178825Sdfr return ret; 178178825Sdfr 179178825Sdfr ret = _kdc_db_fetch(context, config, clientprincipal, 180233294Sstas HDB_F_GET_CLIENT, NULL, &db, &user); 181178825Sdfr krb5_free_principal(context, clientprincipal); 182178825Sdfr if (ret) 183178825Sdfr return ret; 184178825Sdfr 185178825Sdfr ret = hdb_entry_get_password(context, db, &user->entry, password); 186178825Sdfr if (ret || password == NULL) { 187178825Sdfr if (ret == 0) { 188178825Sdfr ret = EINVAL; 189233294Sstas krb5_set_error_message(context, ret, "password missing"); 190178825Sdfr } 191178825Sdfr memset(user, 0, sizeof(*user)); 192178825Sdfr } 193178825Sdfr _kdc_free_ent (context, user); 194178825Sdfr return ret; 195178825Sdfr} 196178825Sdfr 197178825Sdfr/* 198178825Sdfr * 199178825Sdfr */ 200178825Sdfr 201178825Sdfrkrb5_error_code 202233294Sstas_kdc_do_digest(krb5_context context, 203178825Sdfr krb5_kdc_configuration *config, 204233294Sstas const struct DigestREQ *req, krb5_data *reply, 205178825Sdfr const char *from, struct sockaddr *addr) 206178825Sdfr{ 207178825Sdfr krb5_error_code ret = 0; 208178825Sdfr krb5_ticket *ticket = NULL; 209178825Sdfr krb5_auth_context ac = NULL; 210178825Sdfr krb5_keytab id = NULL; 211178825Sdfr krb5_crypto crypto = NULL; 212178825Sdfr DigestReqInner ireq; 213178825Sdfr DigestRepInner r; 214178825Sdfr DigestREP rep; 215178825Sdfr krb5_flags ap_req_options; 216178825Sdfr krb5_data buf; 217178825Sdfr size_t size; 218178825Sdfr krb5_storage *sp = NULL; 219178825Sdfr Checksum res; 220178825Sdfr hdb_entry_ex *server = NULL, *user = NULL; 221178825Sdfr hdb_entry_ex *client = NULL; 222178825Sdfr char *client_name = NULL, *password = NULL; 223178825Sdfr krb5_data serverNonce; 224178825Sdfr 225178825Sdfr if(!config->enable_digest) { 226233294Sstas kdc_log(context, config, 0, 227178825Sdfr "Rejected digest request (disabled) from %s", from); 228178825Sdfr return KRB5KDC_ERR_POLICY; 229178825Sdfr } 230178825Sdfr 231178825Sdfr krb5_data_zero(&buf); 232178825Sdfr krb5_data_zero(reply); 233178825Sdfr krb5_data_zero(&serverNonce); 234178825Sdfr memset(&ireq, 0, sizeof(ireq)); 235178825Sdfr memset(&r, 0, sizeof(r)); 236178825Sdfr memset(&rep, 0, sizeof(rep)); 237233294Sstas memset(&res, 0, sizeof(res)); 238178825Sdfr 239178825Sdfr kdc_log(context, config, 0, "Digest request from %s", from); 240178825Sdfr 241178825Sdfr ret = krb5_kt_resolve(context, "HDB:", &id); 242178825Sdfr if (ret) { 243178825Sdfr kdc_log(context, config, 0, "Can't open database for digest"); 244178825Sdfr goto out; 245178825Sdfr } 246178825Sdfr 247233294Sstas ret = krb5_rd_req(context, 248178825Sdfr &ac, 249178825Sdfr &req->apReq, 250178825Sdfr NULL, 251178825Sdfr id, 252178825Sdfr &ap_req_options, 253178825Sdfr &ticket); 254178825Sdfr if (ret) 255178825Sdfr goto out; 256178825Sdfr 257178825Sdfr /* check the server principal in the ticket matches digest/R@R */ 258178825Sdfr { 259178825Sdfr krb5_principal principal = NULL; 260233294Sstas const char *p, *rr; 261178825Sdfr 262178825Sdfr ret = krb5_ticket_get_server(context, ticket, &principal); 263178825Sdfr if (ret) 264178825Sdfr goto out; 265178825Sdfr 266178825Sdfr ret = EINVAL; 267233294Sstas krb5_set_error_message(context, ret, "Wrong digest server principal used"); 268178825Sdfr p = krb5_principal_get_comp_string(context, principal, 0); 269178825Sdfr if (p == NULL) { 270178825Sdfr krb5_free_principal(context, principal); 271178825Sdfr goto out; 272178825Sdfr } 273178825Sdfr if (strcmp(p, KRB5_DIGEST_NAME) != 0) { 274178825Sdfr krb5_free_principal(context, principal); 275178825Sdfr goto out; 276178825Sdfr } 277178825Sdfr 278178825Sdfr p = krb5_principal_get_comp_string(context, principal, 1); 279178825Sdfr if (p == NULL) { 280178825Sdfr krb5_free_principal(context, principal); 281178825Sdfr goto out; 282178825Sdfr } 283233294Sstas rr = krb5_principal_get_realm(context, principal); 284233294Sstas if (rr == NULL) { 285178825Sdfr krb5_free_principal(context, principal); 286178825Sdfr goto out; 287178825Sdfr } 288233294Sstas if (strcmp(p, rr) != 0) { 289178825Sdfr krb5_free_principal(context, principal); 290178825Sdfr goto out; 291178825Sdfr } 292233294Sstas krb5_clear_error_message(context); 293178825Sdfr 294178825Sdfr ret = _kdc_db_fetch(context, config, principal, 295233294Sstas HDB_F_GET_SERVER, NULL, NULL, &server); 296178825Sdfr if (ret) 297178825Sdfr goto out; 298178825Sdfr 299178825Sdfr krb5_free_principal(context, principal); 300178825Sdfr } 301178825Sdfr 302178825Sdfr /* check the client is allowed to do digest auth */ 303178825Sdfr { 304178825Sdfr krb5_principal principal = NULL; 305178825Sdfr 306178825Sdfr ret = krb5_ticket_get_client(context, ticket, &principal); 307178825Sdfr if (ret) 308178825Sdfr goto out; 309178825Sdfr 310178825Sdfr ret = krb5_unparse_name(context, principal, &client_name); 311178825Sdfr if (ret) { 312178825Sdfr krb5_free_principal(context, principal); 313178825Sdfr goto out; 314178825Sdfr } 315178825Sdfr 316178825Sdfr ret = _kdc_db_fetch(context, config, principal, 317233294Sstas HDB_F_GET_CLIENT, NULL, NULL, &client); 318178825Sdfr krb5_free_principal(context, principal); 319178825Sdfr if (ret) 320178825Sdfr goto out; 321178825Sdfr 322178825Sdfr if (client->entry.flags.allow_digest == 0) { 323233294Sstas kdc_log(context, config, 0, 324178825Sdfr "Client %s tried to use digest " 325233294Sstas "but is not allowed to", 326178825Sdfr client_name); 327178825Sdfr ret = KRB5KDC_ERR_POLICY; 328233294Sstas krb5_set_error_message(context, ret, 329233294Sstas "Client is not permitted to use digest"); 330178825Sdfr goto out; 331178825Sdfr } 332178825Sdfr } 333178825Sdfr 334178825Sdfr /* unpack request */ 335178825Sdfr { 336178825Sdfr krb5_keyblock *key; 337178825Sdfr 338178825Sdfr ret = krb5_auth_con_getremotesubkey(context, ac, &key); 339178825Sdfr if (ret) 340178825Sdfr goto out; 341178825Sdfr if (key == NULL) { 342178825Sdfr ret = EINVAL; 343233294Sstas krb5_set_error_message(context, ret, "digest: remote subkey not found"); 344178825Sdfr goto out; 345178825Sdfr } 346178825Sdfr 347178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 348178825Sdfr krb5_free_keyblock (context, key); 349178825Sdfr if (ret) 350178825Sdfr goto out; 351178825Sdfr } 352178825Sdfr 353178825Sdfr ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, 354178825Sdfr &req->innerReq, &buf); 355178825Sdfr krb5_crypto_destroy(context, crypto); 356178825Sdfr crypto = NULL; 357178825Sdfr if (ret) 358178825Sdfr goto out; 359233294Sstas 360178825Sdfr ret = decode_DigestReqInner(buf.data, buf.length, &ireq, NULL); 361178825Sdfr krb5_data_free(&buf); 362178825Sdfr if (ret) { 363233294Sstas krb5_set_error_message(context, ret, "Failed to decode digest inner request"); 364178825Sdfr goto out; 365178825Sdfr } 366178825Sdfr 367233294Sstas kdc_log(context, config, 0, "Valid digest request from %s (%s)", 368178825Sdfr client_name, from); 369178825Sdfr 370178825Sdfr /* 371178825Sdfr * Process the inner request 372178825Sdfr */ 373178825Sdfr 374178825Sdfr switch (ireq.element) { 375178825Sdfr case choice_DigestReqInner_init: { 376178825Sdfr unsigned char server_nonce[16], identifier; 377178825Sdfr 378178825Sdfr RAND_pseudo_bytes(&identifier, sizeof(identifier)); 379178825Sdfr RAND_pseudo_bytes(server_nonce, sizeof(server_nonce)); 380178825Sdfr 381178825Sdfr server_nonce[0] = kdc_time & 0xff; 382178825Sdfr server_nonce[1] = (kdc_time >> 8) & 0xff; 383178825Sdfr server_nonce[2] = (kdc_time >> 16) & 0xff; 384178825Sdfr server_nonce[3] = (kdc_time >> 24) & 0xff; 385178825Sdfr 386178825Sdfr r.element = choice_DigestRepInner_initReply; 387178825Sdfr 388178825Sdfr hex_encode(server_nonce, sizeof(server_nonce), &r.u.initReply.nonce); 389178825Sdfr if (r.u.initReply.nonce == NULL) { 390178825Sdfr ret = ENOMEM; 391233294Sstas krb5_set_error_message(context, ret, "Failed to decode server nonce"); 392178825Sdfr goto out; 393178825Sdfr } 394178825Sdfr 395178825Sdfr sp = krb5_storage_emem(); 396178825Sdfr if (sp == NULL) { 397178825Sdfr ret = ENOMEM; 398233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 399178825Sdfr goto out; 400178825Sdfr } 401178825Sdfr ret = krb5_store_stringz(sp, ireq.u.init.type); 402178825Sdfr if (ret) { 403233294Sstas krb5_clear_error_message(context); 404178825Sdfr goto out; 405178825Sdfr } 406178825Sdfr 407178825Sdfr if (ireq.u.init.channel) { 408178825Sdfr char *s; 409178825Sdfr 410178825Sdfr asprintf(&s, "%s-%s:%s", r.u.initReply.nonce, 411178825Sdfr ireq.u.init.channel->cb_type, 412178825Sdfr ireq.u.init.channel->cb_binding); 413178825Sdfr if (s == NULL) { 414178825Sdfr ret = ENOMEM; 415233294Sstas krb5_set_error_message(context, ret, 416233294Sstas "Failed to allocate channel binding"); 417178825Sdfr goto out; 418178825Sdfr } 419178825Sdfr free(r.u.initReply.nonce); 420178825Sdfr r.u.initReply.nonce = s; 421178825Sdfr } 422233294Sstas 423178825Sdfr ret = krb5_store_stringz(sp, r.u.initReply.nonce); 424178825Sdfr if (ret) { 425233294Sstas krb5_clear_error_message(context); 426178825Sdfr goto out; 427178825Sdfr } 428178825Sdfr 429178825Sdfr if (strcasecmp(ireq.u.init.type, "CHAP") == 0) { 430233294Sstas r.u.initReply.identifier = 431178825Sdfr malloc(sizeof(*r.u.initReply.identifier)); 432178825Sdfr if (r.u.initReply.identifier == NULL) { 433178825Sdfr ret = ENOMEM; 434233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 435178825Sdfr goto out; 436178825Sdfr } 437178825Sdfr 438178825Sdfr asprintf(r.u.initReply.identifier, "%02X", identifier & 0xff); 439178825Sdfr if (*r.u.initReply.identifier == NULL) { 440178825Sdfr ret = ENOMEM; 441233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 442178825Sdfr goto out; 443178825Sdfr } 444178825Sdfr 445178825Sdfr } else 446178825Sdfr r.u.initReply.identifier = NULL; 447178825Sdfr 448178825Sdfr if (ireq.u.init.hostname) { 449178825Sdfr ret = krb5_store_stringz(sp, *ireq.u.init.hostname); 450178825Sdfr if (ret) { 451233294Sstas krb5_clear_error_message(context); 452178825Sdfr goto out; 453178825Sdfr } 454178825Sdfr } 455178825Sdfr 456178825Sdfr ret = krb5_storage_to_data(sp, &buf); 457178825Sdfr if (ret) { 458233294Sstas krb5_clear_error_message(context); 459178825Sdfr goto out; 460178825Sdfr } 461178825Sdfr 462178825Sdfr ret = get_digest_key(context, config, server, &crypto); 463178825Sdfr if (ret) 464178825Sdfr goto out; 465178825Sdfr 466178825Sdfr ret = krb5_create_checksum(context, 467178825Sdfr crypto, 468178825Sdfr KRB5_KU_DIGEST_OPAQUE, 469178825Sdfr 0, 470178825Sdfr buf.data, 471178825Sdfr buf.length, 472178825Sdfr &res); 473178825Sdfr krb5_crypto_destroy(context, crypto); 474178825Sdfr crypto = NULL; 475178825Sdfr krb5_data_free(&buf); 476178825Sdfr if (ret) 477178825Sdfr goto out; 478233294Sstas 479178825Sdfr ASN1_MALLOC_ENCODE(Checksum, buf.data, buf.length, &res, &size, ret); 480178825Sdfr free_Checksum(&res); 481178825Sdfr if (ret) { 482233294Sstas krb5_set_error_message(context, ret, "Failed to encode " 483233294Sstas "checksum in digest request"); 484178825Sdfr goto out; 485178825Sdfr } 486178825Sdfr if (size != buf.length) 487178825Sdfr krb5_abortx(context, "ASN1 internal error"); 488178825Sdfr 489178825Sdfr hex_encode(buf.data, buf.length, &r.u.initReply.opaque); 490178825Sdfr free(buf.data); 491233294Sstas krb5_data_zero(&buf); 492178825Sdfr if (r.u.initReply.opaque == NULL) { 493233294Sstas krb5_clear_error_message(context); 494178825Sdfr ret = ENOMEM; 495178825Sdfr goto out; 496178825Sdfr } 497178825Sdfr 498178825Sdfr kdc_log(context, config, 0, "Digest %s init request successful from %s", 499178825Sdfr ireq.u.init.type, from); 500178825Sdfr 501178825Sdfr break; 502178825Sdfr } 503178825Sdfr case choice_DigestReqInner_digestRequest: { 504178825Sdfr sp = krb5_storage_emem(); 505178825Sdfr if (sp == NULL) { 506178825Sdfr ret = ENOMEM; 507233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 508178825Sdfr goto out; 509178825Sdfr } 510178825Sdfr ret = krb5_store_stringz(sp, ireq.u.digestRequest.type); 511178825Sdfr if (ret) { 512233294Sstas krb5_clear_error_message(context); 513178825Sdfr goto out; 514178825Sdfr } 515178825Sdfr 516178825Sdfr krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce); 517178825Sdfr 518178825Sdfr if (ireq.u.digestRequest.hostname) { 519178825Sdfr ret = krb5_store_stringz(sp, *ireq.u.digestRequest.hostname); 520178825Sdfr if (ret) { 521233294Sstas krb5_clear_error_message(context); 522178825Sdfr goto out; 523178825Sdfr } 524178825Sdfr } 525178825Sdfr 526178825Sdfr buf.length = strlen(ireq.u.digestRequest.opaque); 527178825Sdfr buf.data = malloc(buf.length); 528178825Sdfr if (buf.data == NULL) { 529178825Sdfr ret = ENOMEM; 530233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 531178825Sdfr goto out; 532178825Sdfr } 533178825Sdfr 534178825Sdfr ret = hex_decode(ireq.u.digestRequest.opaque, buf.data, buf.length); 535178825Sdfr if (ret <= 0) { 536178825Sdfr ret = ENOMEM; 537233294Sstas krb5_set_error_message(context, ret, "Failed to decode opaque"); 538178825Sdfr goto out; 539178825Sdfr } 540178825Sdfr buf.length = ret; 541178825Sdfr 542178825Sdfr ret = decode_Checksum(buf.data, buf.length, &res, NULL); 543178825Sdfr free(buf.data); 544233294Sstas krb5_data_zero(&buf); 545178825Sdfr if (ret) { 546233294Sstas krb5_set_error_message(context, ret, 547233294Sstas "Failed to decode digest Checksum"); 548178825Sdfr goto out; 549178825Sdfr } 550233294Sstas 551178825Sdfr ret = krb5_storage_to_data(sp, &buf); 552178825Sdfr if (ret) { 553233294Sstas krb5_clear_error_message(context); 554178825Sdfr goto out; 555178825Sdfr } 556178825Sdfr 557178825Sdfr serverNonce.length = strlen(ireq.u.digestRequest.serverNonce); 558178825Sdfr serverNonce.data = malloc(serverNonce.length); 559178825Sdfr if (serverNonce.data == NULL) { 560178825Sdfr ret = ENOMEM; 561233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 562178825Sdfr goto out; 563178825Sdfr } 564233294Sstas 565178825Sdfr /* 566178825Sdfr * CHAP does the checksum of the raw nonce, but do it for all 567178825Sdfr * types, since we need to check the timestamp. 568178825Sdfr */ 569178825Sdfr { 570178825Sdfr ssize_t ssize; 571233294Sstas 572233294Sstas ssize = hex_decode(ireq.u.digestRequest.serverNonce, 573178825Sdfr serverNonce.data, serverNonce.length); 574178825Sdfr if (ssize <= 0) { 575178825Sdfr ret = ENOMEM; 576233294Sstas krb5_set_error_message(context, ret, "Failed to decode serverNonce"); 577178825Sdfr goto out; 578178825Sdfr } 579178825Sdfr serverNonce.length = ssize; 580178825Sdfr } 581178825Sdfr 582178825Sdfr ret = get_digest_key(context, config, server, &crypto); 583178825Sdfr if (ret) 584178825Sdfr goto out; 585178825Sdfr 586233294Sstas ret = krb5_verify_checksum(context, crypto, 587178825Sdfr KRB5_KU_DIGEST_OPAQUE, 588178825Sdfr buf.data, buf.length, &res); 589233294Sstas free_Checksum(&res); 590233294Sstas krb5_data_free(&buf); 591178825Sdfr krb5_crypto_destroy(context, crypto); 592178825Sdfr crypto = NULL; 593178825Sdfr if (ret) 594178825Sdfr goto out; 595178825Sdfr 596178825Sdfr /* verify time */ 597178825Sdfr { 598178825Sdfr unsigned char *p = serverNonce.data; 599178825Sdfr uint32_t t; 600233294Sstas 601178825Sdfr if (serverNonce.length < 4) { 602178825Sdfr ret = EINVAL; 603233294Sstas krb5_set_error_message(context, ret, "server nonce too short"); 604178825Sdfr goto out; 605178825Sdfr } 606178825Sdfr t = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 607178825Sdfr 608178825Sdfr if (abs((kdc_time & 0xffffffff) - t) > context->max_skew) { 609178825Sdfr ret = EINVAL; 610233294Sstas krb5_set_error_message(context, ret, "time screw in server nonce "); 611178825Sdfr goto out; 612178825Sdfr } 613178825Sdfr } 614178825Sdfr 615178825Sdfr if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) { 616233294Sstas EVP_MD_CTX *ctx; 617178825Sdfr unsigned char md[MD5_DIGEST_LENGTH]; 618178825Sdfr char *mdx; 619233294Sstas char idx; 620178825Sdfr 621178825Sdfr if ((config->digests_allowed & CHAP_MD5) == 0) { 622178825Sdfr kdc_log(context, config, 0, "Digest CHAP MD5 not allowed"); 623178825Sdfr goto out; 624178825Sdfr } 625178825Sdfr 626178825Sdfr if (ireq.u.digestRequest.identifier == NULL) { 627178825Sdfr ret = EINVAL; 628233294Sstas krb5_set_error_message(context, ret, "Identifier missing " 629233294Sstas "from CHAP request"); 630178825Sdfr goto out; 631178825Sdfr } 632233294Sstas 633233294Sstas if (hex_decode(*ireq.u.digestRequest.identifier, &idx, 1) != 1) { 634178825Sdfr ret = EINVAL; 635233294Sstas krb5_set_error_message(context, ret, "failed to decode identifier"); 636178825Sdfr goto out; 637178825Sdfr } 638233294Sstas 639233294Sstas ret = get_password_entry(context, config, 640178825Sdfr ireq.u.digestRequest.username, 641178825Sdfr &password); 642178825Sdfr if (ret) 643178825Sdfr goto out; 644178825Sdfr 645233294Sstas ctx = EVP_MD_CTX_create(); 646178825Sdfr 647233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 648233294Sstas EVP_DigestUpdate(ctx, &idx, 1); 649233294Sstas EVP_DigestUpdate(ctx, password, strlen(password)); 650233294Sstas EVP_DigestUpdate(ctx, serverNonce.data, serverNonce.length); 651233294Sstas EVP_DigestFinal_ex(ctx, md, NULL); 652233294Sstas 653233294Sstas EVP_MD_CTX_destroy(ctx); 654233294Sstas 655178825Sdfr hex_encode(md, sizeof(md), &mdx); 656178825Sdfr if (mdx == NULL) { 657233294Sstas krb5_clear_error_message(context); 658178825Sdfr ret = ENOMEM; 659178825Sdfr goto out; 660178825Sdfr } 661178825Sdfr 662178825Sdfr r.element = choice_DigestRepInner_response; 663178825Sdfr 664178825Sdfr ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 665178825Sdfr free(mdx); 666178825Sdfr if (ret == 0) { 667178825Sdfr r.u.response.success = TRUE; 668178825Sdfr } else { 669233294Sstas kdc_log(context, config, 0, 670178825Sdfr "CHAP reply mismatch for %s", 671178825Sdfr ireq.u.digestRequest.username); 672178825Sdfr r.u.response.success = FALSE; 673178825Sdfr } 674178825Sdfr 675178825Sdfr } else if (strcasecmp(ireq.u.digestRequest.type, "SASL-DIGEST-MD5") == 0) { 676233294Sstas EVP_MD_CTX *ctx; 677178825Sdfr unsigned char md[MD5_DIGEST_LENGTH]; 678178825Sdfr char *mdx; 679178825Sdfr char *A1, *A2; 680178825Sdfr 681178825Sdfr if ((config->digests_allowed & DIGEST_MD5) == 0) { 682178825Sdfr kdc_log(context, config, 0, "Digest SASL MD5 not allowed"); 683178825Sdfr goto out; 684178825Sdfr } 685178825Sdfr 686233294Sstas if (ireq.u.digestRequest.nonceCount == NULL) 687178825Sdfr goto out; 688233294Sstas if (ireq.u.digestRequest.clientNonce == NULL) 689178825Sdfr goto out; 690233294Sstas if (ireq.u.digestRequest.qop == NULL) 691178825Sdfr goto out; 692233294Sstas if (ireq.u.digestRequest.realm == NULL) 693178825Sdfr goto out; 694233294Sstas 695233294Sstas ret = get_password_entry(context, config, 696178825Sdfr ireq.u.digestRequest.username, 697178825Sdfr &password); 698178825Sdfr if (ret) 699178825Sdfr goto failed; 700178825Sdfr 701233294Sstas ctx = EVP_MD_CTX_create(); 702233294Sstas 703233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 704233294Sstas EVP_DigestUpdate(ctx, ireq.u.digestRequest.username, 705178825Sdfr strlen(ireq.u.digestRequest.username)); 706233294Sstas EVP_DigestUpdate(ctx, ":", 1); 707233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.realm, 708178825Sdfr strlen(*ireq.u.digestRequest.realm)); 709233294Sstas EVP_DigestUpdate(ctx, ":", 1); 710233294Sstas EVP_DigestUpdate(ctx, password, strlen(password)); 711233294Sstas EVP_DigestFinal_ex(ctx, md, NULL); 712233294Sstas 713233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 714233294Sstas EVP_DigestUpdate(ctx, md, sizeof(md)); 715233294Sstas EVP_DigestUpdate(ctx, ":", 1); 716233294Sstas EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce, 717178825Sdfr strlen(ireq.u.digestRequest.serverNonce)); 718233294Sstas EVP_DigestUpdate(ctx, ":", 1); 719233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount, 720178825Sdfr strlen(*ireq.u.digestRequest.nonceCount)); 721178825Sdfr if (ireq.u.digestRequest.authid) { 722233294Sstas EVP_DigestUpdate(ctx, ":", 1); 723233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.authid, 724178825Sdfr strlen(*ireq.u.digestRequest.authid)); 725178825Sdfr } 726233294Sstas EVP_DigestFinal_ex(ctx, md, NULL); 727178825Sdfr hex_encode(md, sizeof(md), &A1); 728178825Sdfr if (A1 == NULL) { 729178825Sdfr ret = ENOMEM; 730233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 731233294Sstas EVP_MD_CTX_destroy(ctx); 732178825Sdfr goto failed; 733178825Sdfr } 734233294Sstas 735233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 736233294Sstas EVP_DigestUpdate(ctx, 737233294Sstas "AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1); 738233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.uri, 739178825Sdfr strlen(*ireq.u.digestRequest.uri)); 740233294Sstas 741178825Sdfr /* conf|int */ 742178825Sdfr if (strcmp(ireq.u.digestRequest.digest, "clear") != 0) { 743178825Sdfr static char conf_zeros[] = ":00000000000000000000000000000000"; 744233294Sstas EVP_DigestUpdate(ctx, conf_zeros, sizeof(conf_zeros) - 1); 745178825Sdfr } 746233294Sstas 747233294Sstas EVP_DigestFinal_ex(ctx, md, NULL); 748233294Sstas 749178825Sdfr hex_encode(md, sizeof(md), &A2); 750178825Sdfr if (A2 == NULL) { 751178825Sdfr ret = ENOMEM; 752233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 753178825Sdfr free(A1); 754178825Sdfr goto failed; 755178825Sdfr } 756178825Sdfr 757233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 758233294Sstas EVP_DigestUpdate(ctx, A1, strlen(A2)); 759233294Sstas EVP_DigestUpdate(ctx, ":", 1); 760233294Sstas EVP_DigestUpdate(ctx, ireq.u.digestRequest.serverNonce, 761178825Sdfr strlen(ireq.u.digestRequest.serverNonce)); 762233294Sstas EVP_DigestUpdate(ctx, ":", 1); 763233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.nonceCount, 764178825Sdfr strlen(*ireq.u.digestRequest.nonceCount)); 765233294Sstas EVP_DigestUpdate(ctx, ":", 1); 766233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.clientNonce, 767178825Sdfr strlen(*ireq.u.digestRequest.clientNonce)); 768233294Sstas EVP_DigestUpdate(ctx, ":", 1); 769233294Sstas EVP_DigestUpdate(ctx, *ireq.u.digestRequest.qop, 770178825Sdfr strlen(*ireq.u.digestRequest.qop)); 771233294Sstas EVP_DigestUpdate(ctx, ":", 1); 772233294Sstas EVP_DigestUpdate(ctx, A2, strlen(A2)); 773178825Sdfr 774233294Sstas EVP_DigestFinal_ex(ctx, md, NULL); 775178825Sdfr 776233294Sstas EVP_MD_CTX_destroy(ctx); 777233294Sstas 778178825Sdfr free(A1); 779178825Sdfr free(A2); 780178825Sdfr 781178825Sdfr hex_encode(md, sizeof(md), &mdx); 782178825Sdfr if (mdx == NULL) { 783233294Sstas krb5_clear_error_message(context); 784178825Sdfr ret = ENOMEM; 785178825Sdfr goto out; 786178825Sdfr } 787178825Sdfr 788178825Sdfr r.element = choice_DigestRepInner_response; 789178825Sdfr ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 790178825Sdfr free(mdx); 791178825Sdfr if (ret == 0) { 792178825Sdfr r.u.response.success = TRUE; 793178825Sdfr } else { 794233294Sstas kdc_log(context, config, 0, 795178825Sdfr "DIGEST-MD5 reply mismatch for %s", 796178825Sdfr ireq.u.digestRequest.username); 797178825Sdfr r.u.response.success = FALSE; 798178825Sdfr } 799178825Sdfr 800178825Sdfr } else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) { 801178825Sdfr unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH]; 802178825Sdfr krb5_principal clientprincipal = NULL; 803178825Sdfr char *mdx; 804178825Sdfr const char *username; 805178825Sdfr struct ntlm_buf answer; 806178825Sdfr Key *key = NULL; 807233294Sstas EVP_MD_CTX *ctp; 808178825Sdfr 809178825Sdfr if ((config->digests_allowed & MS_CHAP_V2) == 0) { 810178825Sdfr kdc_log(context, config, 0, "MS-CHAP-V2 not allowed"); 811178825Sdfr goto failed; 812178825Sdfr } 813178825Sdfr 814178825Sdfr if (ireq.u.digestRequest.clientNonce == NULL) { 815178825Sdfr ret = EINVAL; 816233294Sstas krb5_set_error_message(context, ret, 817233294Sstas "MS-CHAP-V2 clientNonce missing"); 818178825Sdfr goto failed; 819233294Sstas } 820178825Sdfr if (serverNonce.length != 16) { 821178825Sdfr ret = EINVAL; 822233294Sstas krb5_set_error_message(context, ret, 823233294Sstas "MS-CHAP-V2 serverNonce wrong length"); 824178825Sdfr goto failed; 825178825Sdfr } 826178825Sdfr 827178825Sdfr /* strip of the domain component */ 828178825Sdfr username = strchr(ireq.u.digestRequest.username, '\\'); 829178825Sdfr if (username == NULL) 830178825Sdfr username = ireq.u.digestRequest.username; 831178825Sdfr else 832178825Sdfr username++; 833178825Sdfr 834233294Sstas ctp = EVP_MD_CTX_create(); 835233294Sstas 836178825Sdfr /* ChallangeHash */ 837233294Sstas EVP_DigestInit_ex(ctp, EVP_sha1(), NULL); 838178825Sdfr { 839178825Sdfr ssize_t ssize; 840178825Sdfr krb5_data clientNonce; 841233294Sstas 842178825Sdfr clientNonce.length = strlen(*ireq.u.digestRequest.clientNonce); 843178825Sdfr clientNonce.data = malloc(clientNonce.length); 844178825Sdfr if (clientNonce.data == NULL) { 845178825Sdfr ret = ENOMEM; 846233294Sstas krb5_set_error_message(context, ret, 847233294Sstas "malloc: out of memory"); 848233294Sstas EVP_MD_CTX_destroy(ctp); 849178825Sdfr goto out; 850178825Sdfr } 851178825Sdfr 852233294Sstas ssize = hex_decode(*ireq.u.digestRequest.clientNonce, 853178825Sdfr clientNonce.data, clientNonce.length); 854178825Sdfr if (ssize != 16) { 855178825Sdfr ret = ENOMEM; 856233294Sstas krb5_set_error_message(context, ret, 857233294Sstas "Failed to decode clientNonce"); 858233294Sstas EVP_MD_CTX_destroy(ctp); 859178825Sdfr goto out; 860178825Sdfr } 861233294Sstas EVP_DigestUpdate(ctp, clientNonce.data, ssize); 862178825Sdfr free(clientNonce.data); 863178825Sdfr } 864233294Sstas EVP_DigestUpdate(ctp, serverNonce.data, serverNonce.length); 865233294Sstas EVP_DigestUpdate(ctp, username, strlen(username)); 866178825Sdfr 867233294Sstas EVP_DigestFinal_ex(ctp, challange, NULL); 868233294Sstas 869233294Sstas EVP_MD_CTX_destroy(ctp); 870233294Sstas 871178825Sdfr /* NtPasswordHash */ 872178825Sdfr ret = krb5_parse_name(context, username, &clientprincipal); 873178825Sdfr if (ret) 874178825Sdfr goto failed; 875233294Sstas 876178825Sdfr ret = _kdc_db_fetch(context, config, clientprincipal, 877233294Sstas HDB_F_GET_CLIENT, NULL, NULL, &user); 878178825Sdfr krb5_free_principal(context, clientprincipal); 879178825Sdfr if (ret) { 880233294Sstas krb5_set_error_message(context, ret, 881233294Sstas "MS-CHAP-V2 user %s not in database", 882233294Sstas username); 883178825Sdfr goto failed; 884178825Sdfr } 885178825Sdfr 886233294Sstas ret = hdb_enctype2key(context, &user->entry, 887178825Sdfr ETYPE_ARCFOUR_HMAC_MD5, &key); 888178825Sdfr if (ret) { 889233294Sstas krb5_set_error_message(context, ret, 890233294Sstas "MS-CHAP-V2 missing arcfour key %s", 891233294Sstas username); 892178825Sdfr goto failed; 893178825Sdfr } 894178825Sdfr 895178825Sdfr /* ChallengeResponse */ 896178825Sdfr ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 897178825Sdfr key->key.keyvalue.length, 898178825Sdfr challange, &answer); 899178825Sdfr if (ret) { 900233294Sstas krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 901178825Sdfr goto failed; 902178825Sdfr } 903233294Sstas 904178825Sdfr hex_encode(answer.data, answer.length, &mdx); 905178825Sdfr if (mdx == NULL) { 906178825Sdfr free(answer.data); 907233294Sstas krb5_clear_error_message(context); 908178825Sdfr ret = ENOMEM; 909178825Sdfr goto out; 910178825Sdfr } 911178825Sdfr 912178825Sdfr r.element = choice_DigestRepInner_response; 913178825Sdfr ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); 914178825Sdfr if (ret == 0) { 915178825Sdfr r.u.response.success = TRUE; 916178825Sdfr } else { 917233294Sstas kdc_log(context, config, 0, 918178825Sdfr "MS-CHAP-V2 hash mismatch for %s", 919178825Sdfr ireq.u.digestRequest.username); 920178825Sdfr r.u.response.success = FALSE; 921178825Sdfr } 922178825Sdfr free(mdx); 923178825Sdfr 924178825Sdfr if (r.u.response.success) { 925178825Sdfr unsigned char hashhash[MD4_DIGEST_LENGTH]; 926233294Sstas EVP_MD_CTX *ctxp; 927178825Sdfr 928233294Sstas ctxp = EVP_MD_CTX_create(); 929233294Sstas 930178825Sdfr /* hashhash */ 931178825Sdfr { 932233294Sstas EVP_DigestInit_ex(ctxp, EVP_md4(), NULL); 933233294Sstas EVP_DigestUpdate(ctxp, 934233294Sstas key->key.keyvalue.data, 935233294Sstas key->key.keyvalue.length); 936233294Sstas EVP_DigestFinal_ex(ctxp, hashhash, NULL); 937178825Sdfr } 938178825Sdfr 939178825Sdfr /* GenerateAuthenticatorResponse */ 940233294Sstas EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 941233294Sstas EVP_DigestUpdate(ctxp, hashhash, sizeof(hashhash)); 942233294Sstas EVP_DigestUpdate(ctxp, answer.data, answer.length); 943233294Sstas EVP_DigestUpdate(ctxp, ms_chap_v2_magic1, 944233294Sstas sizeof(ms_chap_v2_magic1)); 945233294Sstas EVP_DigestFinal_ex(ctxp, md, NULL); 946178825Sdfr 947233294Sstas EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 948233294Sstas EVP_DigestUpdate(ctxp, md, sizeof(md)); 949233294Sstas EVP_DigestUpdate(ctxp, challange, 8); 950233294Sstas EVP_DigestUpdate(ctxp, ms_chap_v2_magic2, 951233294Sstas sizeof(ms_chap_v2_magic2)); 952233294Sstas EVP_DigestFinal_ex(ctxp, md, NULL); 953178825Sdfr 954178825Sdfr r.u.response.rsp = calloc(1, sizeof(*r.u.response.rsp)); 955178825Sdfr if (r.u.response.rsp == NULL) { 956178825Sdfr free(answer.data); 957233294Sstas krb5_clear_error_message(context); 958233294Sstas EVP_MD_CTX_destroy(ctxp); 959178825Sdfr ret = ENOMEM; 960178825Sdfr goto out; 961178825Sdfr } 962178825Sdfr 963178825Sdfr hex_encode(md, sizeof(md), r.u.response.rsp); 964178825Sdfr if (r.u.response.rsp == NULL) { 965178825Sdfr free(answer.data); 966233294Sstas krb5_clear_error_message(context); 967233294Sstas EVP_MD_CTX_destroy(ctxp); 968178825Sdfr ret = ENOMEM; 969178825Sdfr goto out; 970178825Sdfr } 971178825Sdfr 972178825Sdfr /* get_master, rfc 3079 3.4 */ 973233294Sstas EVP_DigestInit_ex(ctxp, EVP_sha1(), NULL); 974233294Sstas EVP_DigestUpdate(ctxp, hashhash, 16); 975233294Sstas EVP_DigestUpdate(ctxp, answer.data, answer.length); 976233294Sstas EVP_DigestUpdate(ctxp, ms_rfc3079_magic1, 977233294Sstas sizeof(ms_rfc3079_magic1)); 978233294Sstas EVP_DigestFinal_ex(ctxp, md, NULL); 979178825Sdfr 980178825Sdfr free(answer.data); 981178825Sdfr 982233294Sstas EVP_MD_CTX_destroy(ctxp); 983233294Sstas 984233294Sstas r.u.response.session_key = 985178825Sdfr calloc(1, sizeof(*r.u.response.session_key)); 986178825Sdfr if (r.u.response.session_key == NULL) { 987233294Sstas krb5_clear_error_message(context); 988178825Sdfr ret = ENOMEM; 989178825Sdfr goto out; 990178825Sdfr } 991178825Sdfr 992178825Sdfr ret = krb5_data_copy(r.u.response.session_key, md, 16); 993178825Sdfr if (ret) { 994233294Sstas krb5_clear_error_message(context); 995178825Sdfr goto out; 996178825Sdfr } 997178825Sdfr } 998178825Sdfr 999178825Sdfr } else { 1000178825Sdfr r.element = choice_DigestRepInner_error; 1001233294Sstas asprintf(&r.u.error.reason, "Unsupported digest type %s", 1002178825Sdfr ireq.u.digestRequest.type); 1003178825Sdfr if (r.u.error.reason == NULL) { 1004178825Sdfr ret = ENOMEM; 1005233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1006178825Sdfr goto out; 1007178825Sdfr } 1008178825Sdfr r.u.error.code = EINVAL; 1009178825Sdfr } 1010178825Sdfr 1011178825Sdfr kdc_log(context, config, 0, "Digest %s request successful %s", 1012178825Sdfr ireq.u.digestRequest.type, ireq.u.digestRequest.username); 1013178825Sdfr 1014178825Sdfr break; 1015178825Sdfr } 1016178825Sdfr case choice_DigestReqInner_ntlmInit: 1017178825Sdfr 1018178825Sdfr if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) { 1019178825Sdfr kdc_log(context, config, 0, "NTLM not allowed"); 1020178825Sdfr goto failed; 1021178825Sdfr } 1022178825Sdfr 1023178825Sdfr r.element = choice_DigestRepInner_ntlmInitReply; 1024178825Sdfr 1025178825Sdfr r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE; 1026178825Sdfr 1027178825Sdfr if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) { 1028178825Sdfr kdc_log(context, config, 0, "NTLM client have no unicode"); 1029178825Sdfr goto failed; 1030178825Sdfr } 1031178825Sdfr 1032178825Sdfr if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM) 1033178825Sdfr r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM; 1034178825Sdfr else { 1035178825Sdfr kdc_log(context, config, 0, "NTLM client doesn't support NTLM"); 1036178825Sdfr goto failed; 1037178825Sdfr } 1038178825Sdfr 1039233294Sstas r.u.ntlmInitReply.flags |= 1040178825Sdfr NTLM_NEG_TARGET | 1041178825Sdfr NTLM_TARGET_DOMAIN | 1042178825Sdfr NTLM_ENC_128; 1043178825Sdfr 1044178825Sdfr#define ALL \ 1045178825Sdfr NTLM_NEG_SIGN| \ 1046178825Sdfr NTLM_NEG_SEAL| \ 1047178825Sdfr NTLM_NEG_ALWAYS_SIGN| \ 1048178825Sdfr NTLM_NEG_NTLM2_SESSION| \ 1049178825Sdfr NTLM_NEG_KEYEX 1050178825Sdfr 1051178825Sdfr r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL)); 1052178825Sdfr 1053178825Sdfr#undef ALL 1054178825Sdfr 1055233294Sstas r.u.ntlmInitReply.targetname = 1056178825Sdfr get_ntlm_targetname(context, client); 1057178825Sdfr if (r.u.ntlmInitReply.targetname == NULL) { 1058178825Sdfr ret = ENOMEM; 1059233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1060178825Sdfr goto out; 1061178825Sdfr } 1062178825Sdfr r.u.ntlmInitReply.challange.data = malloc(8); 1063178825Sdfr if (r.u.ntlmInitReply.challange.data == NULL) { 1064178825Sdfr ret = ENOMEM; 1065233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1066178825Sdfr goto out; 1067178825Sdfr } 1068178825Sdfr r.u.ntlmInitReply.challange.length = 8; 1069178825Sdfr if (RAND_bytes(r.u.ntlmInitReply.challange.data, 1070233294Sstas r.u.ntlmInitReply.challange.length) != 1) 1071233294Sstas { 1072233294Sstas ret = ENOMEM; 1073233294Sstas krb5_set_error_message(context, ret, "out of random error"); 1074233294Sstas goto out; 1075233294Sstas } 1076178825Sdfr /* XXX fix targetinfo */ 1077178825Sdfr ALLOC(r.u.ntlmInitReply.targetinfo); 1078178825Sdfr if (r.u.ntlmInitReply.targetinfo == NULL) { 1079178825Sdfr ret = ENOMEM; 1080233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1081178825Sdfr goto out; 1082178825Sdfr } 1083178825Sdfr 1084178825Sdfr ret = fill_targetinfo(context, 1085178825Sdfr r.u.ntlmInitReply.targetname, 1086178825Sdfr client, 1087178825Sdfr r.u.ntlmInitReply.targetinfo); 1088178825Sdfr if (ret) { 1089178825Sdfr ret = ENOMEM; 1090233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1091178825Sdfr goto out; 1092178825Sdfr } 1093178825Sdfr 1094233294Sstas /* 1095178825Sdfr * Save data encryted in opaque for the second part of the 1096178825Sdfr * ntlm authentication 1097178825Sdfr */ 1098178825Sdfr sp = krb5_storage_emem(); 1099178825Sdfr if (sp == NULL) { 1100178825Sdfr ret = ENOMEM; 1101233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1102178825Sdfr goto out; 1103178825Sdfr } 1104233294Sstas 1105178825Sdfr ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8); 1106178825Sdfr if (ret != 8) { 1107178825Sdfr ret = ENOMEM; 1108233294Sstas krb5_set_error_message(context, ret, "storage write challange"); 1109178825Sdfr goto out; 1110178825Sdfr } 1111178825Sdfr ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags); 1112178825Sdfr if (ret) { 1113233294Sstas krb5_clear_error_message(context); 1114178825Sdfr goto out; 1115178825Sdfr } 1116178825Sdfr 1117178825Sdfr ret = krb5_storage_to_data(sp, &buf); 1118178825Sdfr if (ret) { 1119233294Sstas krb5_clear_error_message(context); 1120178825Sdfr goto out; 1121178825Sdfr } 1122178825Sdfr 1123178825Sdfr ret = get_digest_key(context, config, server, &crypto); 1124178825Sdfr if (ret) 1125178825Sdfr goto out; 1126178825Sdfr 1127178825Sdfr ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, 1128178825Sdfr buf.data, buf.length, &r.u.ntlmInitReply.opaque); 1129178825Sdfr krb5_data_free(&buf); 1130178825Sdfr krb5_crypto_destroy(context, crypto); 1131178825Sdfr crypto = NULL; 1132178825Sdfr if (ret) 1133178825Sdfr goto out; 1134178825Sdfr 1135178825Sdfr kdc_log(context, config, 0, "NTLM init from %s", from); 1136178825Sdfr 1137178825Sdfr break; 1138178825Sdfr 1139178825Sdfr case choice_DigestReqInner_ntlmRequest: { 1140178825Sdfr krb5_principal clientprincipal; 1141178825Sdfr unsigned char sessionkey[16]; 1142178825Sdfr unsigned char challange[8]; 1143178825Sdfr uint32_t flags; 1144178825Sdfr Key *key = NULL; 1145178825Sdfr int version; 1146233294Sstas 1147178825Sdfr r.element = choice_DigestRepInner_ntlmResponse; 1148178825Sdfr r.u.ntlmResponse.success = 0; 1149178825Sdfr r.u.ntlmResponse.flags = 0; 1150178825Sdfr r.u.ntlmResponse.sessionkey = NULL; 1151178825Sdfr r.u.ntlmResponse.tickets = NULL; 1152178825Sdfr 1153178825Sdfr /* get username */ 1154178825Sdfr ret = krb5_parse_name(context, 1155178825Sdfr ireq.u.ntlmRequest.username, 1156178825Sdfr &clientprincipal); 1157178825Sdfr if (ret) 1158178825Sdfr goto failed; 1159178825Sdfr 1160178825Sdfr ret = _kdc_db_fetch(context, config, clientprincipal, 1161233294Sstas HDB_F_GET_CLIENT, NULL, NULL, &user); 1162178825Sdfr krb5_free_principal(context, clientprincipal); 1163178825Sdfr if (ret) { 1164233294Sstas krb5_set_error_message(context, ret, "NTLM user %s not in database", 1165233294Sstas ireq.u.ntlmRequest.username); 1166178825Sdfr goto failed; 1167178825Sdfr } 1168178825Sdfr 1169178825Sdfr ret = get_digest_key(context, config, server, &crypto); 1170178825Sdfr if (ret) 1171178825Sdfr goto failed; 1172178825Sdfr 1173178825Sdfr ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, 1174178825Sdfr ireq.u.ntlmRequest.opaque.data, 1175178825Sdfr ireq.u.ntlmRequest.opaque.length, &buf); 1176178825Sdfr krb5_crypto_destroy(context, crypto); 1177178825Sdfr crypto = NULL; 1178178825Sdfr if (ret) { 1179233294Sstas kdc_log(context, config, 0, 1180178825Sdfr "Failed to decrypt nonce from %s", from); 1181178825Sdfr goto failed; 1182178825Sdfr } 1183178825Sdfr 1184178825Sdfr sp = krb5_storage_from_data(&buf); 1185178825Sdfr if (sp == NULL) { 1186178825Sdfr ret = ENOMEM; 1187233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1188178825Sdfr goto out; 1189178825Sdfr } 1190233294Sstas 1191178825Sdfr ret = krb5_storage_read(sp, challange, sizeof(challange)); 1192178825Sdfr if (ret != sizeof(challange)) { 1193178825Sdfr ret = ENOMEM; 1194233294Sstas krb5_set_error_message(context, ret, "NTLM storage read challange"); 1195178825Sdfr goto out; 1196178825Sdfr } 1197178825Sdfr ret = krb5_ret_uint32(sp, &flags); 1198178825Sdfr if (ret) { 1199233294Sstas krb5_set_error_message(context, ret, "NTLM storage read flags"); 1200178825Sdfr goto out; 1201178825Sdfr } 1202233294Sstas krb5_storage_free(sp); 1203233294Sstas sp = NULL; 1204178825Sdfr krb5_data_free(&buf); 1205178825Sdfr 1206178825Sdfr if ((flags & NTLM_NEG_NTLM) == 0) { 1207178825Sdfr ret = EINVAL; 1208233294Sstas krb5_set_error_message(context, ret, "NTLM not negotiated"); 1209178825Sdfr goto out; 1210178825Sdfr } 1211178825Sdfr 1212233294Sstas ret = hdb_enctype2key(context, &user->entry, 1213178825Sdfr ETYPE_ARCFOUR_HMAC_MD5, &key); 1214178825Sdfr if (ret) { 1215233294Sstas krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 1216178825Sdfr goto out; 1217178825Sdfr } 1218178825Sdfr 1219178825Sdfr /* check if this is NTLMv2 */ 1220178825Sdfr if (ireq.u.ntlmRequest.ntlm.length != 24) { 1221178825Sdfr struct ntlm_buf infotarget, answer; 1222178825Sdfr char *targetname; 1223178825Sdfr 1224178825Sdfr if ((config->digests_allowed & NTLM_V2) == 0) { 1225178825Sdfr kdc_log(context, config, 0, "NTLM v2 not allowed"); 1226178825Sdfr goto out; 1227178825Sdfr } 1228178825Sdfr 1229178825Sdfr version = 2; 1230178825Sdfr 1231178825Sdfr targetname = get_ntlm_targetname(context, client); 1232178825Sdfr if (targetname == NULL) { 1233178825Sdfr ret = ENOMEM; 1234233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1235178825Sdfr goto out; 1236178825Sdfr } 1237178825Sdfr 1238178825Sdfr answer.length = ireq.u.ntlmRequest.ntlm.length; 1239178825Sdfr answer.data = ireq.u.ntlmRequest.ntlm.data; 1240178825Sdfr 1241178825Sdfr ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, 1242178825Sdfr key->key.keyvalue.length, 1243178825Sdfr ireq.u.ntlmRequest.username, 1244178825Sdfr targetname, 1245178825Sdfr 0, 1246178825Sdfr challange, 1247178825Sdfr &answer, 1248178825Sdfr &infotarget, 1249178825Sdfr sessionkey); 1250178825Sdfr free(targetname); 1251178825Sdfr if (ret) { 1252233294Sstas krb5_set_error_message(context, ret, "NTLM v2 verify failed"); 1253178825Sdfr goto failed; 1254178825Sdfr } 1255178825Sdfr 1256178825Sdfr /* XXX verify infotarget matches client (checksum ?) */ 1257178825Sdfr 1258178825Sdfr free(infotarget.data); 1259178825Sdfr /* */ 1260178825Sdfr 1261178825Sdfr } else { 1262178825Sdfr struct ntlm_buf answer; 1263178825Sdfr 1264178825Sdfr version = 1; 1265178825Sdfr 1266178825Sdfr if (flags & NTLM_NEG_NTLM2_SESSION) { 1267178825Sdfr unsigned char sessionhash[MD5_DIGEST_LENGTH]; 1268233294Sstas EVP_MD_CTX *ctx; 1269233294Sstas 1270178825Sdfr if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { 1271178825Sdfr kdc_log(context, config, 0, "NTLM v1-session not allowed"); 1272178825Sdfr ret = EINVAL; 1273178825Sdfr goto failed; 1274178825Sdfr } 1275178825Sdfr 1276178825Sdfr if (ireq.u.ntlmRequest.lm.length != 24) { 1277178825Sdfr ret = EINVAL; 1278233294Sstas krb5_set_error_message(context, ret, "LM hash have wrong length " 1279233294Sstas "for NTLM session key"); 1280178825Sdfr goto failed; 1281178825Sdfr } 1282233294Sstas 1283233294Sstas ctx = EVP_MD_CTX_create(); 1284233294Sstas 1285233294Sstas EVP_DigestInit_ex(ctx, EVP_md5(), NULL); 1286233294Sstas 1287233294Sstas EVP_DigestUpdate(ctx, challange, sizeof(challange)); 1288233294Sstas EVP_DigestUpdate(ctx, ireq.u.ntlmRequest.lm.data, 8); 1289233294Sstas EVP_DigestFinal_ex(ctx, sessionhash, NULL); 1290178825Sdfr memcpy(challange, sessionhash, sizeof(challange)); 1291233294Sstas 1292233294Sstas EVP_MD_CTX_destroy(ctx); 1293233294Sstas 1294178825Sdfr } else { 1295178825Sdfr if ((config->digests_allowed & NTLM_V1) == 0) { 1296178825Sdfr kdc_log(context, config, 0, "NTLM v1 not allowed"); 1297178825Sdfr goto failed; 1298178825Sdfr } 1299178825Sdfr } 1300233294Sstas 1301178825Sdfr ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 1302178825Sdfr key->key.keyvalue.length, 1303178825Sdfr challange, &answer); 1304178825Sdfr if (ret) { 1305233294Sstas krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 1306178825Sdfr goto failed; 1307178825Sdfr } 1308233294Sstas 1309178825Sdfr if (ireq.u.ntlmRequest.ntlm.length != answer.length || 1310178825Sdfr memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0) 1311233294Sstas { 1312233294Sstas free(answer.data); 1313233294Sstas ret = EINVAL; 1314233294Sstas krb5_set_error_message(context, ret, "NTLM hash mismatch"); 1315233294Sstas goto failed; 1316233294Sstas } 1317178825Sdfr free(answer.data); 1318178825Sdfr 1319178825Sdfr { 1320233294Sstas EVP_MD_CTX *ctx; 1321178825Sdfr 1322233294Sstas ctx = EVP_MD_CTX_create(); 1323233294Sstas 1324233294Sstas EVP_DigestInit_ex(ctx, EVP_md4(), NULL); 1325233294Sstas EVP_DigestUpdate(ctx, 1326233294Sstas key->key.keyvalue.data, 1327233294Sstas key->key.keyvalue.length); 1328233294Sstas EVP_DigestFinal_ex(ctx, sessionkey, NULL); 1329233294Sstas 1330233294Sstas EVP_MD_CTX_destroy(ctx); 1331178825Sdfr } 1332178825Sdfr } 1333178825Sdfr 1334178825Sdfr if (ireq.u.ntlmRequest.sessionkey) { 1335178825Sdfr unsigned char masterkey[MD4_DIGEST_LENGTH]; 1336233294Sstas EVP_CIPHER_CTX rc4; 1337178825Sdfr size_t len; 1338233294Sstas 1339178825Sdfr if ((flags & NTLM_NEG_KEYEX) == 0) { 1340178825Sdfr ret = EINVAL; 1341233294Sstas krb5_set_error_message(context, ret, 1342233294Sstas "NTLM client failed to neg key " 1343233294Sstas "exchange but still sent key"); 1344178825Sdfr goto failed; 1345178825Sdfr } 1346233294Sstas 1347178825Sdfr len = ireq.u.ntlmRequest.sessionkey->length; 1348178825Sdfr if (len != sizeof(masterkey)){ 1349233294Sstas ret = EINVAL; 1350233294Sstas krb5_set_error_message(context, ret, 1351233294Sstas "NTLM master key wrong length: %lu", 1352233294Sstas (unsigned long)len); 1353178825Sdfr goto failed; 1354178825Sdfr } 1355233294Sstas 1356233294Sstas 1357233294Sstas EVP_CIPHER_CTX_init(&rc4); 1358233294Sstas EVP_CipherInit_ex(&rc4, EVP_rc4(), NULL, sessionkey, NULL, 1); 1359233294Sstas EVP_Cipher(&rc4, 1360233294Sstas masterkey, ireq.u.ntlmRequest.sessionkey->data, 1361233294Sstas sizeof(masterkey)); 1362233294Sstas EVP_CIPHER_CTX_cleanup(&rc4); 1363233294Sstas 1364233294Sstas r.u.ntlmResponse.sessionkey = 1365178825Sdfr malloc(sizeof(*r.u.ntlmResponse.sessionkey)); 1366178825Sdfr if (r.u.ntlmResponse.sessionkey == NULL) { 1367233294Sstas ret = EINVAL; 1368233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1369178825Sdfr goto out; 1370178825Sdfr } 1371233294Sstas 1372178825Sdfr ret = krb5_data_copy(r.u.ntlmResponse.sessionkey, 1373178825Sdfr masterkey, sizeof(masterkey)); 1374178825Sdfr if (ret) { 1375233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1376178825Sdfr goto out; 1377178825Sdfr } 1378178825Sdfr } 1379178825Sdfr 1380178825Sdfr r.u.ntlmResponse.success = 1; 1381178825Sdfr kdc_log(context, config, 0, "NTLM version %d successful for %s", 1382178825Sdfr version, ireq.u.ntlmRequest.username); 1383178825Sdfr break; 1384178825Sdfr } 1385178825Sdfr case choice_DigestReqInner_supportedMechs: 1386178825Sdfr 1387178825Sdfr kdc_log(context, config, 0, "digest supportedMechs from %s", from); 1388178825Sdfr 1389178825Sdfr r.element = choice_DigestRepInner_supportedMechs; 1390178825Sdfr memset(&r.u.supportedMechs, 0, sizeof(r.u.supportedMechs)); 1391178825Sdfr 1392178825Sdfr if (config->digests_allowed & NTLM_V1) 1393178825Sdfr r.u.supportedMechs.ntlm_v1 = 1; 1394178825Sdfr if (config->digests_allowed & NTLM_V1_SESSION) 1395178825Sdfr r.u.supportedMechs.ntlm_v1_session = 1; 1396178825Sdfr if (config->digests_allowed & NTLM_V2) 1397178825Sdfr r.u.supportedMechs.ntlm_v2 = 1; 1398178825Sdfr if (config->digests_allowed & DIGEST_MD5) 1399178825Sdfr r.u.supportedMechs.digest_md5 = 1; 1400178825Sdfr if (config->digests_allowed & CHAP_MD5) 1401178825Sdfr r.u.supportedMechs.chap_md5 = 1; 1402178825Sdfr if (config->digests_allowed & MS_CHAP_V2) 1403178825Sdfr r.u.supportedMechs.ms_chap_v2 = 1; 1404178825Sdfr break; 1405178825Sdfr 1406178825Sdfr default: { 1407233294Sstas const char *s; 1408178825Sdfr ret = EINVAL; 1409233294Sstas krb5_set_error_message(context, ret, "unknown operation to digest"); 1410178825Sdfr 1411233294Sstas failed: 1412178825Sdfr 1413178825Sdfr s = krb5_get_error_message(context, ret); 1414178825Sdfr if (s == NULL) { 1415233294Sstas krb5_clear_error_message(context); 1416178825Sdfr goto out; 1417178825Sdfr } 1418233294Sstas 1419178825Sdfr kdc_log(context, config, 0, "Digest failed with: %s", s); 1420178825Sdfr 1421178825Sdfr r.element = choice_DigestRepInner_error; 1422178825Sdfr r.u.error.reason = strdup("unknown error"); 1423233294Sstas krb5_free_error_message(context, s); 1424178825Sdfr if (r.u.error.reason == NULL) { 1425178825Sdfr ret = ENOMEM; 1426233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 1427178825Sdfr goto out; 1428178825Sdfr } 1429178825Sdfr r.u.error.code = EINVAL; 1430178825Sdfr break; 1431178825Sdfr } 1432178825Sdfr } 1433178825Sdfr 1434178825Sdfr ASN1_MALLOC_ENCODE(DigestRepInner, buf.data, buf.length, &r, &size, ret); 1435178825Sdfr if (ret) { 1436233294Sstas krb5_set_error_message(context, ret, "Failed to encode inner digest reply"); 1437178825Sdfr goto out; 1438178825Sdfr } 1439178825Sdfr if (size != buf.length) 1440178825Sdfr krb5_abortx(context, "ASN1 internal error"); 1441178825Sdfr 1442178825Sdfr krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL); 1443178825Sdfr 1444178825Sdfr ret = krb5_mk_rep (context, ac, &rep.apRep); 1445178825Sdfr if (ret) 1446178825Sdfr goto out; 1447178825Sdfr 1448178825Sdfr { 1449178825Sdfr krb5_keyblock *key; 1450178825Sdfr 1451178825Sdfr ret = krb5_auth_con_getlocalsubkey(context, ac, &key); 1452178825Sdfr if (ret) 1453178825Sdfr goto out; 1454178825Sdfr 1455178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 1456178825Sdfr krb5_free_keyblock (context, key); 1457178825Sdfr if (ret) 1458178825Sdfr goto out; 1459178825Sdfr } 1460178825Sdfr 1461233294Sstas ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, 1462178825Sdfr buf.data, buf.length, 0, 1463178825Sdfr &rep.innerRep); 1464233294Sstas 1465178825Sdfr ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret); 1466178825Sdfr if (ret) { 1467233294Sstas krb5_set_error_message(context, ret, "Failed to encode digest reply"); 1468178825Sdfr goto out; 1469178825Sdfr } 1470178825Sdfr if (size != reply->length) 1471178825Sdfr krb5_abortx(context, "ASN1 internal error"); 1472178825Sdfr 1473233294Sstas 1474233294Sstas out: 1475178825Sdfr if (ac) 1476178825Sdfr krb5_auth_con_free(context, ac); 1477178825Sdfr if (ret) 1478178825Sdfr krb5_warn(context, ret, "Digest request from %s failed", from); 1479178825Sdfr if (ticket) 1480178825Sdfr krb5_free_ticket(context, ticket); 1481178825Sdfr if (id) 1482178825Sdfr krb5_kt_close(context, id); 1483178825Sdfr if (crypto) 1484178825Sdfr krb5_crypto_destroy(context, crypto); 1485178825Sdfr if (sp) 1486178825Sdfr krb5_storage_free(sp); 1487178825Sdfr if (user) 1488178825Sdfr _kdc_free_ent (context, user); 1489178825Sdfr if (server) 1490178825Sdfr _kdc_free_ent (context, server); 1491178825Sdfr if (client) 1492178825Sdfr _kdc_free_ent (context, client); 1493178825Sdfr if (password) { 1494178825Sdfr memset(password, 0, strlen(password)); 1495178825Sdfr free (password); 1496178825Sdfr } 1497178825Sdfr if (client_name) 1498178825Sdfr free (client_name); 1499178825Sdfr krb5_data_free(&buf); 1500178825Sdfr krb5_data_free(&serverNonce); 1501233294Sstas free_Checksum(&res); 1502178825Sdfr free_DigestREP(&rep); 1503178825Sdfr free_DigestRepInner(&r); 1504178825Sdfr free_DigestReqInner(&ireq); 1505178825Sdfr 1506178825Sdfr return ret; 1507178825Sdfr} 1508233294Sstas 1509233294Sstas#endif /* DIGEST */ 1510