17c478bd9Sstevel@tonic-gate /*
2159d09a2SMark 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.
17*55fea89dSDan Cross  *
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.
31*55fea89dSDan Cross  *
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * krb5_mk_req_extended()
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate 
37159d09a2SMark Phalan #include "k5-int.h"
38159d09a2SMark 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 
73*55fea89dSDan Cross 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
krb5int_generate_and_save_subkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock * keyblock)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.
90159d09a2SMark Phalan        This isn't strong cryptographically; the point here is not
91159d09a2SMark Phalan        to guarantee randomness, but to make it less likely that multiple
92159d09a2SMark Phalan        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 
105159d09a2SMark 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 
114159d09a2SMark 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
krb5_mk_req_extended(krb5_context context,krb5_auth_context * auth_context,krb5_flags ap_req_options,krb5_data * in_data,krb5_creds * in_creds,krb5_data * outbuf)130159d09a2SMark Phalan krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context,
131159d09a2SMark Phalan 		     krb5_flags ap_req_options, krb5_data *in_data,
132159d09a2SMark 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;
146*55fea89dSDan Cross 
147*55fea89dSDan Cross     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);
153*55fea89dSDan Cross 
1547c478bd9Sstevel@tonic-gate     /* verify that the ticket is not expired */
155159d09a2SMark 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     }
169159d09a2SMark Phalan 
170159d09a2SMark Phalan     /* set auth context keyblock */
171*55fea89dSDan Cross     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))
178*55fea89dSDan Cross       && ((*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;
182*55fea89dSDan Cross 
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate     /* generate subkey if needed */
1857c478bd9Sstevel@tonic-gate     if (!in_data &&(*auth_context)->checksum_func) {
186159d09a2SMark Phalan 	retval = (*auth_context)->checksum_func( context,
187159d09a2SMark Phalan 						 *auth_context,
188159d09a2SMark Phalan 						 (*auth_context)->checksum_func_data,
189159d09a2SMark Phalan 						 &in_data);
1907c478bd9Sstevel@tonic-gate 	if (retval)
191159d09a2SMark Phalan 	    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,
196159d09a2SMark Phalan 						   &in_creds->keyblock);
1977c478bd9Sstevel@tonic-gate 	if (retval)
198159d09a2SMark Phalan 	    goto cleanup;
1997c478bd9Sstevel@tonic-gate     }
2007c478bd9Sstevel@tonic-gate 
201159d09a2SMark Phalan 
2027c478bd9Sstevel@tonic-gate     if (in_data) {
203159d09a2SMark Phalan 
204159d09a2SMark Phalan       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*55fea89dSDan Cross 	    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,
214159d09a2SMark 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;
234*55fea89dSDan Cross 
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;
239*55fea89dSDan Cross 
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 */
248159d09a2SMark Phalan     if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
2497c478bd9Sstevel@tonic-gate 				      KRB5_KEYUSAGE_AP_REQ_AUTH,
250159d09a2SMark 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
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)280159d09a2SMark 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;
283*55fea89dSDan Cross 
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