2 * lib/krb5/krb/mk_req_ext.c
4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. M.I.T. makes no representations about the suitability of
20 * this software for any purpose. It is provided "as is" without express
21 * or implied warranty.
24 * krb5_mk_req_extended()
32 Formats a KRB_AP_REQ message into outbuf, with more complete options than
35 outbuf, ap_req_options, checksum, and ccache are used in the
36 same fashion as for krb5_mk_req.
38 creds is used to supply the credentials (ticket and session key) needed
41 if creds->ticket has no data (length == 0), then a ticket is obtained
42 from either the cache or the TGS, passing creds to krb5_get_credentials().
43 kdc_options specifies the options requested for the ticket to be used.
44 If a ticket with appropriate flags is not found in the cache, then these
45 options are passed on in a request to an appropriate KDC.
47 ap_req_options specifies the KRB_AP_REQ options desired.
49 if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
50 must contain the appropriate ENC-TKT-IN-SKEY ticket.
52 checksum specifies the checksum to be used in the authenticator.
54 The outbuf buffer storage is allocated, and should be freed by the
57 On an error return, the credentials pointed to by creds might have been
58 augmented with additional fields from the obtained credentials; the entire
59 credentials should be released by calling krb5_free_creds().
64 static krb5_error_code
65 krb5_generate_authenticator PROTOTYPE((krb5_context,
66 krb5_authenticator *, krb5_principal,
67 const krb5_checksum *, krb5_keyblock *,
68 krb5_int32, krb5_authdata ** ));
70 krb5_error_code INTERFACE
71 krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds,
74 krb5_auth_context * auth_context;
75 const krb5_flags ap_req_options;
77 krb5_creds * in_creds;
80 krb5_error_code retval;
81 krb5_checksum checksum;
82 krb5_checksum *checksump = 0;
83 krb5_auth_context new_auth_context;
86 krb5_data *scratch = 0;
87 krb5_encrypt_block eblock;
90 request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
91 request.authenticator.ciphertext.data = 0;
94 if (!in_creds->ticket.length)
95 return(KRB5_NO_TKT_SUPPLIED);
97 /* we need a native ticket */
98 if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
101 /* verify a valid enctype is available */
102 if (!valid_enctype(request.ticket->enc_part.enctype)) {
103 retval = KRB5_PROG_ETYPE_NOSUPP;
107 /* verify that the ticket is not expired */
108 if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
111 /* generate auth_context if needed */
112 if (*auth_context == NULL) {
113 if ((retval = krb5_auth_con_init(context, &new_auth_context)))
115 *auth_context = new_auth_context;
118 /* set auth context keyblock */
119 if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock,
120 &((*auth_context)->keyblock))))
123 /* generate seq number if needed */
124 if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
125 || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
126 && ((*auth_context)->local_seq_number == 0))
127 if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
128 &(*auth_context)->local_seq_number)))
132 /* generate subkey if needed */
133 if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->local_subkey))
134 if ((retval = krb5_generate_subkey(context, &(in_creds)->keyblock,
135 &(*auth_context)->local_subkey)))
140 if ((*auth_context)->cksumtype == 0x8003) {
141 /* XXX Special hack for GSSAPI */
142 checksum.checksum_type = 0x8003;
143 checksum.length = in_data->length;
144 checksum.contents = (krb5_octet *) in_data->data;
146 /* Generate checksum, XXX What should the seed be? */
147 if ((checksum.contents = (krb5_octet *)malloc(krb5_checksum_size(context,
148 (*auth_context)->cksumtype))) == NULL) {
152 if ((retval = krb5_calculate_checksum(context,
153 (*auth_context)->cksumtype,
154 in_data->data, in_data->length,
155 (*auth_context)->keyblock->contents,
156 (*auth_context)->keyblock->length,
160 checksump = &checksum;
163 /* Generate authenticator */
164 if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
165 krb5_authenticator))) == NULL) {
170 if ((retval = krb5_generate_authenticator(context,
171 (*auth_context)->authentp,
172 (in_creds)->client, checksump,
173 (*auth_context)->local_subkey,
174 (*auth_context)->local_seq_number,
175 (in_creds)->authdata)))
178 /* encode the authenticator */
179 if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
183 /* Null out these fields, to prevent pointer sharing problems;
184 * they were supplied by the caller
186 (*auth_context)->authentp->client = NULL;
187 (*auth_context)->authentp->checksum = NULL;
188 (*auth_context)->authentp->authorization_data = NULL;
190 /* put together an eblock for this encryption */
192 krb5_use_enctype(context, &eblock, in_creds->keyblock.enctype);
193 request.authenticator.enctype = in_creds->keyblock.enctype;
194 request.authenticator.kvno = 0;
195 request.authenticator.ciphertext.length =
196 krb5_encrypt_size(scratch->length, eblock.crypto_entry);
197 /* add padding area, and zero it */
198 if (!(scratch->data = realloc(scratch->data,
199 request.authenticator.ciphertext.length))) {
200 /* may destroy scratch->data */
204 memset(scratch->data + scratch->length, 0,
205 request.authenticator.ciphertext.length - scratch->length);
206 if (!(request.authenticator.ciphertext.data =
207 malloc(request.authenticator.ciphertext.length))) {
212 /* do any necessary key pre-processing */
213 if ((retval = krb5_process_key(context, &eblock, &(in_creds)->keyblock)))
216 /* call the encryption routine */
217 if ((retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
218 (krb5_pointer) request.authenticator.ciphertext.data,
219 scratch->length, &eblock, 0))) {
220 krb5_finish_key(context, &eblock);
224 if ((retval = krb5_finish_key(context, &eblock)))
227 if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
229 #ifdef HAVE_C_STRUCTURE_ASSIGNMENT
232 memcpy(outbuf, toutbuf, sizeof(krb5_data));
238 if (checksump && checksump->checksum_type != 0x8003)
239 free(checksump->contents);
243 krb5_free_ticket(context, request.ticket);
244 if (request.authenticator.ciphertext.data) {
245 (void) memset(request.authenticator.ciphertext.data, 0,
246 request.authenticator.ciphertext.length);
247 free(request.authenticator.ciphertext.data);
250 memset(scratch->data, 0, scratch->length);
251 krb5_xfree(scratch->data);
257 static krb5_error_code
258 krb5_generate_authenticator(context, authent, client, cksum, key, seq_number, authorization)
259 krb5_context context;
260 krb5_authenticator *authent;
261 krb5_principal client;
262 const krb5_checksum *cksum;
264 krb5_int32 seq_number;
265 krb5_authdata **authorization;
267 krb5_error_code retval;
269 authent->client = client;
270 authent->checksum = (krb5_checksum *)cksum;
272 retval = krb5_copy_keyblock(context, key, &authent->subkey);
277 authent->seq_number = seq_number;
278 authent->authorization_data = authorization;
280 return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));