1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * lib/krb5/krb/mk_req_ext.c
9 *
10 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
11 * All Rights Reserved.
12 *
13 * Export of this software from the United States of America may
14 * require a specific license from the United States Government.
15 * It is the responsibility of any person or organization contemplating
16 * export to obtain such a license before exporting.
17 *
18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19 * distribute this software and its documentation for any purpose and
20 * without fee is hereby granted, provided that the above copyright
21 * notice appear in all copies and that both that copyright notice and
22 * this permission notice appear in supporting documentation, and that
23 * the name of M.I.T. not be used in advertising or publicity pertaining
24 * to distribution of the software without specific, written prior
25 * permission. Furthermore if you modify this software you must label
26 * your software as modified software and not distribute it in such a
27 * fashion that it might be confused with the original M.I.T. software.
28 * M.I.T. makes no representations about the suitability of
29 * this software for any purpose. It is provided "as is" without express
30 * or implied warranty.
31 *
32 *
33 * krb5_mk_req_extended()
34 */
35
36
37 #include "k5-int.h"
38 #include "auth_con.h"
39
40 /*
41 Formats a KRB_AP_REQ message into outbuf, with more complete options than
42 krb_mk_req.
43
44 outbuf, ap_req_options, checksum, and ccache are used in the
45 same fashion as for krb5_mk_req.
46
47 creds is used to supply the credentials (ticket and session key) needed
48 to form the request.
49
50 if creds->ticket has no data (length == 0), then a ticket is obtained
51 from either the cache or the TGS, passing creds to krb5_get_credentials().
52 kdc_options specifies the options requested for the ticket to be used.
53 If a ticket with appropriate flags is not found in the cache, then these
54 options are passed on in a request to an appropriate KDC.
55
56 ap_req_options specifies the KRB_AP_REQ options desired.
57
58 if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
59 must contain the appropriate ENC-TKT-IN-SKEY ticket.
60
61 checksum specifies the checksum to be used in the authenticator.
62
63 The outbuf buffer storage is allocated, and should be freed by the
64 caller when finished.
65
66 On an error return, the credentials pointed to by creds might have been
67 augmented with additional fields from the obtained credentials; the entire
68 credentials should be released by calling krb5_free_creds().
69
70 returns system errors
71 */
72
73 static krb5_error_code
74 krb5_generate_authenticator (krb5_context,
75 krb5_authenticator *, krb5_principal,
76 krb5_checksum *, krb5_keyblock *,
77 krb5_ui_4, krb5_authdata ** );
78
79 krb5_error_code
krb5int_generate_and_save_subkey(krb5_context context,krb5_auth_context auth_context,krb5_keyblock * keyblock)80 krb5int_generate_and_save_subkey (krb5_context context,
81 krb5_auth_context auth_context,
82 krb5_keyblock *keyblock)
83 {
84 #if 0
85 /*
86 * Solaris Kerberos: Don't bother with this PRNG stuff,
87 * we have /dev/random and PKCS#11 to handle Random Numbers.
88 */
89 /* Provide some more fodder for random number code.
90 This isn't strong cryptographically; the point here is not
91 to guarantee randomness, but to make it less likely that multiple
92 sessions could pick the same subkey. */
93 struct {
94 krb5_int32 sec, usec;
95 } rnd_data;
96 krb5_data d;
97
98 krb5_crypto_us_timeofday (&rnd_data.sec, &rnd_data.usec);
99 d.length = sizeof (rnd_data);
100 d.data = (char *) &rnd_data;
101 (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_TIMING, &d);
102 #endif
103 krb5_error_code retval;
104
105 /* Solaris Kerberos */
106 if (auth_context->send_subkey != NULL) {
107 krb5_free_keyblock(context, auth_context->send_subkey);
108 auth_context->send_subkey = NULL;
109 }
110
111 if ((retval = krb5_generate_subkey(context, keyblock, &auth_context->send_subkey)))
112 return retval;
113
114 /* Solaris Kerberos */
115 if (auth_context->recv_subkey != NULL) {
116 krb5_free_keyblock(context, auth_context->recv_subkey);
117 auth_context->recv_subkey = NULL;
118 }
119 retval = krb5_copy_keyblock(context, auth_context->send_subkey,
120 &auth_context->recv_subkey);
121 if (retval) {
122 krb5_free_keyblock(context, auth_context->send_subkey);
123 auth_context->send_subkey = NULL;
124 return retval;
125 }
126 return 0;
127 }
128
129 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)130 krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context,
131 krb5_flags ap_req_options, krb5_data *in_data,
132 krb5_creds *in_creds, krb5_data *outbuf)
133 {
134 krb5_error_code retval;
135 krb5_checksum checksum;
136 krb5_checksum *checksump = 0;
137 krb5_auth_context new_auth_context;
138
139 krb5_ap_req request;
140 krb5_data *scratch = 0;
141 krb5_data *toutbuf;
142
143 request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
144 request.authenticator.ciphertext.data = 0;
145 request.ticket = 0;
146
147 if (!in_creds->ticket.length)
148 return(KRB5_NO_TKT_SUPPLIED);
149
150 /* we need a native ticket */
151 if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
152 return(retval);
153
154 /* verify that the ticket is not expired */
155 if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
156 goto cleanup;
157
158 /* generate auth_context if needed */
159 if (*auth_context == NULL) {
160 if ((retval = krb5_auth_con_init(context, &new_auth_context)))
161 goto cleanup;
162 *auth_context = new_auth_context;
163 }
164
165 if ((*auth_context)->keyblock != NULL) {
166 krb5_free_keyblock(context, (*auth_context)->keyblock);
167 (*auth_context)->keyblock = NULL;
168 }
169
170 /* set auth context keyblock */
171 if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock,
172 &((*auth_context)->keyblock))))
173 goto cleanup;
174
175 /* generate seq number if needed */
176 if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
177 || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
178 && ((*auth_context)->local_seq_number == 0))
179 if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
180 &(*auth_context)->local_seq_number)))
181 goto cleanup;
182
183
184 /* generate subkey if needed */
185 if (!in_data &&(*auth_context)->checksum_func) {
186 retval = (*auth_context)->checksum_func( context,
187 *auth_context,
188 (*auth_context)->checksum_func_data,
189 &in_data);
190 if (retval)
191 goto cleanup;
192 }
193
194 if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) {
195 retval = krb5int_generate_and_save_subkey (context, *auth_context,
196 &in_creds->keyblock);
197 if (retval)
198 goto cleanup;
199 }
200
201
202 if (in_data) {
203
204 if ((*auth_context)->req_cksumtype == 0x8003) {
205 /* XXX Special hack for GSSAPI */
206 checksum.checksum_type = 0x8003;
207 checksum.length = in_data->length;
208 checksum.contents = (krb5_octet *) in_data->data;
209 } else {
210 if ((retval = krb5_c_make_checksum(context,
211 (*auth_context)->req_cksumtype,
212 (*auth_context)->keyblock,
213 KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
214 in_data, &checksum)))
215 goto cleanup_cksum;
216 }
217 checksump = &checksum;
218 }
219
220 /* Generate authenticator */
221 if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
222 krb5_authenticator))) == NULL) {
223 retval = ENOMEM;
224 goto cleanup_cksum;
225 }
226
227 if ((retval = krb5_generate_authenticator(context,
228 (*auth_context)->authentp,
229 (in_creds)->client, checksump,
230 (*auth_context)->send_subkey,
231 (*auth_context)->local_seq_number,
232 (in_creds)->authdata)))
233 goto cleanup_cksum;
234
235 /* encode the authenticator */
236 if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
237 &scratch)))
238 goto cleanup_cksum;
239
240 /* Null out these fields, to prevent pointer sharing problems;
241 * they were supplied by the caller
242 */
243 (*auth_context)->authentp->client = NULL;
244 (*auth_context)->authentp->checksum = NULL;
245 (*auth_context)->authentp->authorization_data = NULL;
246
247 /* call the encryption routine */
248 if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
249 KRB5_KEYUSAGE_AP_REQ_AUTH,
250 scratch, &request.authenticator)))
251 goto cleanup_cksum;
252
253 if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
254 goto cleanup_cksum;
255 *outbuf = *toutbuf;
256
257 krb5_xfree(toutbuf);
258
259 cleanup_cksum:
260 if (checksump && checksump->checksum_type != 0x8003)
261 free(checksump->contents);
262
263 cleanup:
264 if (request.ticket)
265 krb5_free_ticket(context, request.ticket);
266 if (request.authenticator.ciphertext.data) {
267 (void) memset(request.authenticator.ciphertext.data, 0,
268 request.authenticator.ciphertext.length);
269 free(request.authenticator.ciphertext.data);
270 }
271 if (scratch) {
272 memset(scratch->data, 0, scratch->length);
273 krb5_xfree(scratch->data);
274 krb5_xfree(scratch);
275 }
276 return retval;
277 }
278
279 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)280 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)
281 {
282 krb5_error_code retval;
283
284 authent->client = client;
285 authent->checksum = cksum;
286 if (key) {
287 retval = krb5_copy_keyblock(context, key, &authent->subkey);
288 if (retval)
289 return retval;
290 } else
291 authent->subkey = 0;
292 authent->seq_number = seq_number;
293 authent->authorization_data = authorization;
294
295 return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
296 }
297