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_auth_context * new_auth_context;
85 krb5_data *scratch = 0;
86 krb5_encrypt_block eblock;
89 request.authenticator.ciphertext.data = 0;
90 request.ap_options = ap_req_options;
93 if (!in_creds->ticket.length)
94 return(KRB5_NO_TKT_SUPPLIED);
96 /* we need a native ticket */
97 if (retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket))
100 /* verify a valid etype is available */
101 if (!valid_etype(request.ticket->enc_part.etype)) {
102 retval = KRB5_PROG_ETYPE_NOSUPP;
106 /* generate auth_context if needed */
107 if (*auth_context == NULL) {
108 if (retval = krb5_auth_con_init(context, &new_auth_context))
110 *auth_context = new_auth_context;
113 /* set auth context keyblock */
114 if (retval = krb5_copy_keyblock(context, &in_creds->keyblock,
115 &((*auth_context)->keyblock)))
118 /* generate seq number if needed */
119 if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
120 || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
121 && ((*auth_context)->local_seq_number == 0))
122 if (retval = krb5_generate_seq_number(context, &in_creds->keyblock,
123 &(*auth_context)->local_seq_number))
127 /* generate subkey if needed */
128 if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->local_subkey))
129 if (retval = krb5_generate_subkey(context, &(in_creds)->keyblock,
130 &(*auth_context)->local_subkey))
134 /* Generate checksum, XXX What should the seed be? */
135 if ((checksum.contents = (krb5_octet *)malloc(krb5_checksum_size(
136 context, CKSUMTYPE_CRC32))) == NULL) {
141 if (in_data == NULL) {
142 if (retval = krb5_calculate_checksum(context,
143 (*auth_context)->cksumtype,
144 0, 0, 0, 0, &checksum))
147 if ((*auth_context)->cksumtype == 0x8003) {
148 /* XXX Special hack for GSSAPI */
149 checksum.checksum_type = 0x8003;
150 checksum.length = in_data->length;
151 checksum.contents = in_data->data;
153 if (retval = krb5_calculate_checksum(context,
154 (*auth_context)->cksumtype,
155 in_data->data, in_data->length,
159 /* Generate authenticator */
160 if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
161 krb5_authenticator))) == NULL) {
166 if (retval = krb5_generate_authenticator(context, (*auth_context)->authentp,
167 (in_creds)->client, &checksum,
168 (*auth_context)->local_subkey,
169 (*auth_context)->local_seq_number,
170 (in_creds)->authdata))
173 /* encode the authenticator */
174 if (retval = encode_krb5_authenticator((*auth_context)->authentp, &scratch))
177 /* Null out these fields, to prevent pointer sharing problems;
178 * they were supplied by the caller
180 (*auth_context)->authentp->client = NULL;
181 (*auth_context)->authentp->checksum = NULL;
182 (*auth_context)->authentp->authorization_data = NULL;
184 /* put together an eblock for this encryption */
186 krb5_use_cstype(context, &eblock, request.ticket->enc_part.etype);
187 request.authenticator.etype = request.ticket->enc_part.etype;
188 request.authenticator.kvno = 0;
189 request.authenticator.ciphertext.length =
190 krb5_encrypt_size(scratch->length, eblock.crypto_entry);
191 /* add padding area, and zero it */
192 if (!(scratch->data = realloc(scratch->data,
193 request.authenticator.ciphertext.length))) {
194 /* may destroy scratch->data */
198 memset(scratch->data + scratch->length, 0,
199 request.authenticator.ciphertext.length - scratch->length);
200 if (!(request.authenticator.ciphertext.data =
201 malloc(request.authenticator.ciphertext.length))) {
206 /* do any necessary key pre-processing */
207 if (retval = krb5_process_key(context, &eblock, &(in_creds)->keyblock))
210 /* call the encryption routine */
211 if (retval = krb5_encrypt(context, (krb5_pointer) scratch->data,
212 (krb5_pointer) request.authenticator.ciphertext.data,
213 scratch->length, &eblock, 0)) {
214 krb5_finish_key(context, &eblock);
218 if (retval = krb5_finish_key(context, &eblock))
221 if (retval = encode_krb5_ap_req(&request, &toutbuf))
228 free(checksum.contents);
232 krb5_free_ticket(context, request.ticket);
233 if (request.authenticator.ciphertext.data) {
234 (void) memset(request.authenticator.ciphertext.data, 0,
235 request.authenticator.ciphertext.length);
236 free(request.authenticator.ciphertext.data);
239 memset(scratch->data, 0, scratch->length);
240 krb5_xfree(scratch->data);
246 static krb5_error_code
247 krb5_generate_authenticator(context, authent, client, cksum, key, seq_number, authorization)
248 krb5_context context;
249 krb5_authenticator *authent;
250 krb5_principal client;
251 const krb5_checksum *cksum;
253 krb5_int32 seq_number;
254 krb5_authdata **authorization;
256 krb5_error_code retval;
258 authent->client = client;
259 authent->checksum = (krb5_checksum *)cksum;
261 retval = krb5_copy_keyblock(context, key, &authent->subkey);
266 authent->subkey = key;
267 authent->seq_number = seq_number;
268 authent->authorization_data = authorization;
270 return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));