17c478bd9Sstevel@tonic-gate /* 2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate 77c478bd9Sstevel@tonic-gate /* 87c478bd9Sstevel@tonic-gate * lib/krb5/krb/mk_req_ext.c 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Copyright 1990,1991 by the Massachusetts Institute of Technology. 117c478bd9Sstevel@tonic-gate * All Rights Reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 147c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 157c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 167c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 237c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 257c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 267c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 277c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 287c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 297c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 307c478bd9Sstevel@tonic-gate * or implied warranty. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * krb5_mk_req_extended() 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate 37*159d09a2SMark Phalan #include "k5-int.h" 38*159d09a2SMark Phalan #include "auth_con.h" 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate Formats a KRB_AP_REQ message into outbuf, with more complete options than 427c478bd9Sstevel@tonic-gate krb_mk_req. 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate outbuf, ap_req_options, checksum, and ccache are used in the 457c478bd9Sstevel@tonic-gate same fashion as for krb5_mk_req. 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate creds is used to supply the credentials (ticket and session key) needed 487c478bd9Sstevel@tonic-gate to form the request. 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate if creds->ticket has no data (length == 0), then a ticket is obtained 517c478bd9Sstevel@tonic-gate from either the cache or the TGS, passing creds to krb5_get_credentials(). 527c478bd9Sstevel@tonic-gate kdc_options specifies the options requested for the ticket to be used. 537c478bd9Sstevel@tonic-gate If a ticket with appropriate flags is not found in the cache, then these 547c478bd9Sstevel@tonic-gate options are passed on in a request to an appropriate KDC. 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate ap_req_options specifies the KRB_AP_REQ options desired. 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket 597c478bd9Sstevel@tonic-gate must contain the appropriate ENC-TKT-IN-SKEY ticket. 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate checksum specifies the checksum to be used in the authenticator. 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate The outbuf buffer storage is allocated, and should be freed by the 647c478bd9Sstevel@tonic-gate caller when finished. 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate On an error return, the credentials pointed to by creds might have been 677c478bd9Sstevel@tonic-gate augmented with additional fields from the obtained credentials; the entire 687c478bd9Sstevel@tonic-gate credentials should be released by calling krb5_free_creds(). 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate returns system errors 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate static krb5_error_code 74505d05c7Sgtb krb5_generate_authenticator (krb5_context, 757c478bd9Sstevel@tonic-gate krb5_authenticator *, krb5_principal, 76505d05c7Sgtb krb5_checksum *, krb5_keyblock *, 77505d05c7Sgtb krb5_ui_4, krb5_authdata ** ); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate krb5_error_code 807c478bd9Sstevel@tonic-gate krb5int_generate_and_save_subkey (krb5_context context, 817c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 827c478bd9Sstevel@tonic-gate krb5_keyblock *keyblock) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate #if 0 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * Solaris Kerberos: Don't bother with this PRNG stuff, 877c478bd9Sstevel@tonic-gate * we have /dev/random and PKCS#11 to handle Random Numbers. 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate /* Provide some more fodder for random number code. 907c478bd9Sstevel@tonic-gate This isn't strong cryptographically; the point here is not 917c478bd9Sstevel@tonic-gate to guarantee randomness, but to make it less likely that multiple 927c478bd9Sstevel@tonic-gate sessions could pick the same subkey. */ 937c478bd9Sstevel@tonic-gate struct { 947c478bd9Sstevel@tonic-gate krb5_int32 sec, usec; 957c478bd9Sstevel@tonic-gate } rnd_data; 967c478bd9Sstevel@tonic-gate krb5_data d; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate krb5_crypto_us_timeofday (&rnd_data.sec, &rnd_data.usec); 997c478bd9Sstevel@tonic-gate d.length = sizeof (rnd_data); 1007c478bd9Sstevel@tonic-gate d.data = (char *) &rnd_data; 1017c478bd9Sstevel@tonic-gate (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_TIMING, &d); 1027c478bd9Sstevel@tonic-gate #endif 1037c478bd9Sstevel@tonic-gate krb5_error_code retval; 1047c478bd9Sstevel@tonic-gate 105*159d09a2SMark Phalan /* Solaris Kerberos */ 1067c478bd9Sstevel@tonic-gate if (auth_context->send_subkey != NULL) { 1077c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, auth_context->send_subkey); 1087c478bd9Sstevel@tonic-gate auth_context->send_subkey = NULL; 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if ((retval = krb5_generate_subkey(context, keyblock, &auth_context->send_subkey))) 1127c478bd9Sstevel@tonic-gate return retval; 1137c478bd9Sstevel@tonic-gate 114*159d09a2SMark Phalan /* Solaris Kerberos */ 1157c478bd9Sstevel@tonic-gate if (auth_context->recv_subkey != NULL) { 1167c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, auth_context->recv_subkey); 1177c478bd9Sstevel@tonic-gate auth_context->recv_subkey = NULL; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate retval = krb5_copy_keyblock(context, auth_context->send_subkey, 1207c478bd9Sstevel@tonic-gate &auth_context->recv_subkey); 1217c478bd9Sstevel@tonic-gate if (retval) { 1227c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, auth_context->send_subkey); 1237c478bd9Sstevel@tonic-gate auth_context->send_subkey = NULL; 1247c478bd9Sstevel@tonic-gate return retval; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate return 0; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV 130*159d09a2SMark Phalan krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, 131*159d09a2SMark Phalan krb5_flags ap_req_options, krb5_data *in_data, 132*159d09a2SMark Phalan krb5_creds *in_creds, krb5_data *outbuf) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate krb5_error_code retval; 1357c478bd9Sstevel@tonic-gate krb5_checksum checksum; 1367c478bd9Sstevel@tonic-gate krb5_checksum *checksump = 0; 1377c478bd9Sstevel@tonic-gate krb5_auth_context new_auth_context; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate krb5_ap_req request; 1407c478bd9Sstevel@tonic-gate krb5_data *scratch = 0; 1417c478bd9Sstevel@tonic-gate krb5_data *toutbuf; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK; 1447c478bd9Sstevel@tonic-gate request.authenticator.ciphertext.data = 0; 1457c478bd9Sstevel@tonic-gate request.ticket = 0; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if (!in_creds->ticket.length) 1487c478bd9Sstevel@tonic-gate return(KRB5_NO_TKT_SUPPLIED); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* we need a native ticket */ 1517c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket))) 1527c478bd9Sstevel@tonic-gate return(retval); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* verify that the ticket is not expired */ 155*159d09a2SMark Phalan if ((retval = krb5_validate_times(context, &in_creds->times)) != 0) 1567c478bd9Sstevel@tonic-gate goto cleanup; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* generate auth_context if needed */ 1597c478bd9Sstevel@tonic-gate if (*auth_context == NULL) { 1607c478bd9Sstevel@tonic-gate if ((retval = krb5_auth_con_init(context, &new_auth_context))) 1617c478bd9Sstevel@tonic-gate goto cleanup; 1627c478bd9Sstevel@tonic-gate *auth_context = new_auth_context; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if ((*auth_context)->keyblock != NULL) { 1667c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, (*auth_context)->keyblock); 1677c478bd9Sstevel@tonic-gate (*auth_context)->keyblock = NULL; 1687c478bd9Sstevel@tonic-gate } 169*159d09a2SMark Phalan 170*159d09a2SMark Phalan /* set auth context keyblock */ 1717c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 1727c478bd9Sstevel@tonic-gate &((*auth_context)->keyblock)))) 1737c478bd9Sstevel@tonic-gate goto cleanup; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* generate seq number if needed */ 1767c478bd9Sstevel@tonic-gate if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) 1777c478bd9Sstevel@tonic-gate || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 1787c478bd9Sstevel@tonic-gate && ((*auth_context)->local_seq_number == 0)) 1797c478bd9Sstevel@tonic-gate if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock, 1807c478bd9Sstevel@tonic-gate &(*auth_context)->local_seq_number))) 1817c478bd9Sstevel@tonic-gate goto cleanup; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* generate subkey if needed */ 1857c478bd9Sstevel@tonic-gate if (!in_data &&(*auth_context)->checksum_func) { 1867c478bd9Sstevel@tonic-gate retval = (*auth_context)->checksum_func( context, 1877c478bd9Sstevel@tonic-gate *auth_context, 1887c478bd9Sstevel@tonic-gate (*auth_context)->checksum_func_data, 1897c478bd9Sstevel@tonic-gate &in_data); 1907c478bd9Sstevel@tonic-gate if (retval) 1917c478bd9Sstevel@tonic-gate goto cleanup; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) { 1957c478bd9Sstevel@tonic-gate retval = krb5int_generate_and_save_subkey (context, *auth_context, 1967c478bd9Sstevel@tonic-gate &in_creds->keyblock); 1977c478bd9Sstevel@tonic-gate if (retval) 1987c478bd9Sstevel@tonic-gate goto cleanup; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 201*159d09a2SMark Phalan 2027c478bd9Sstevel@tonic-gate if (in_data) { 203*159d09a2SMark Phalan 2047c478bd9Sstevel@tonic-gate if ((*auth_context)->req_cksumtype == 0x8003) { 2057c478bd9Sstevel@tonic-gate /* XXX Special hack for GSSAPI */ 2067c478bd9Sstevel@tonic-gate checksum.checksum_type = 0x8003; 2077c478bd9Sstevel@tonic-gate checksum.length = in_data->length; 2087c478bd9Sstevel@tonic-gate checksum.contents = (krb5_octet *) in_data->data; 2097c478bd9Sstevel@tonic-gate } else { 210*159d09a2SMark Phalan if ((retval = krb5_c_make_checksum(context, 2117c478bd9Sstevel@tonic-gate (*auth_context)->req_cksumtype, 2127c478bd9Sstevel@tonic-gate (*auth_context)->keyblock, 2137c478bd9Sstevel@tonic-gate KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, 214*159d09a2SMark Phalan in_data, &checksum))) 2157c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate checksump = &checksum; 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* Generate authenticator */ 2217c478bd9Sstevel@tonic-gate if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof( 2227c478bd9Sstevel@tonic-gate krb5_authenticator))) == NULL) { 2237c478bd9Sstevel@tonic-gate retval = ENOMEM; 2247c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if ((retval = krb5_generate_authenticator(context, 2287c478bd9Sstevel@tonic-gate (*auth_context)->authentp, 2297c478bd9Sstevel@tonic-gate (in_creds)->client, checksump, 2307c478bd9Sstevel@tonic-gate (*auth_context)->send_subkey, 2317c478bd9Sstevel@tonic-gate (*auth_context)->local_seq_number, 2327c478bd9Sstevel@tonic-gate (in_creds)->authdata))) 2337c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* encode the authenticator */ 2367c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_authenticator((*auth_context)->authentp, 2377c478bd9Sstevel@tonic-gate &scratch))) 2387c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* Null out these fields, to prevent pointer sharing problems; 2417c478bd9Sstevel@tonic-gate * they were supplied by the caller 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate (*auth_context)->authentp->client = NULL; 2447c478bd9Sstevel@tonic-gate (*auth_context)->authentp->checksum = NULL; 2457c478bd9Sstevel@tonic-gate (*auth_context)->authentp->authorization_data = NULL; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* call the encryption routine */ 248*159d09a2SMark Phalan if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock, 2497c478bd9Sstevel@tonic-gate KRB5_KEYUSAGE_AP_REQ_AUTH, 250*159d09a2SMark Phalan scratch, &request.authenticator))) 2517c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_ap_req(&request, &toutbuf))) 2547c478bd9Sstevel@tonic-gate goto cleanup_cksum; 2557c478bd9Sstevel@tonic-gate *outbuf = *toutbuf; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate krb5_xfree(toutbuf); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate cleanup_cksum: 2607c478bd9Sstevel@tonic-gate if (checksump && checksump->checksum_type != 0x8003) 2617c478bd9Sstevel@tonic-gate free(checksump->contents); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate cleanup: 2647c478bd9Sstevel@tonic-gate if (request.ticket) 2657c478bd9Sstevel@tonic-gate krb5_free_ticket(context, request.ticket); 2667c478bd9Sstevel@tonic-gate if (request.authenticator.ciphertext.data) { 2677c478bd9Sstevel@tonic-gate (void) memset(request.authenticator.ciphertext.data, 0, 2687c478bd9Sstevel@tonic-gate request.authenticator.ciphertext.length); 2697c478bd9Sstevel@tonic-gate free(request.authenticator.ciphertext.data); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate if (scratch) { 2727c478bd9Sstevel@tonic-gate memset(scratch->data, 0, scratch->length); 2737c478bd9Sstevel@tonic-gate krb5_xfree(scratch->data); 2747c478bd9Sstevel@tonic-gate krb5_xfree(scratch); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate return retval; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate static krb5_error_code 280*159d09a2SMark Phalan krb5_generate_authenticator(krb5_context context, krb5_authenticator *authent, krb5_principal client, krb5_checksum *cksum, krb5_keyblock *key, krb5_ui_4 seq_number, krb5_authdata **authorization) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate krb5_error_code retval; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate authent->client = client; 285505d05c7Sgtb authent->checksum = cksum; 2867c478bd9Sstevel@tonic-gate if (key) { 2877c478bd9Sstevel@tonic-gate retval = krb5_copy_keyblock(context, key, &authent->subkey); 2887c478bd9Sstevel@tonic-gate if (retval) 2897c478bd9Sstevel@tonic-gate return retval; 2907c478bd9Sstevel@tonic-gate } else 2917c478bd9Sstevel@tonic-gate authent->subkey = 0; 2927c478bd9Sstevel@tonic-gate authent->seq_number = seq_number; 2937c478bd9Sstevel@tonic-gate authent->authorization_data = authorization; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec)); 2967c478bd9Sstevel@tonic-gate } 297