1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright 2021 Racktop Systems, Inc.
5 */
6
7
8 /*
9 * lib/krb5/krb/mk_safe.c
10 *
11 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
12 * All Rights Reserved.
13 *
14 * Export of this software from the United States of America may
15 * require a specific license from the United States Government.
16 * It is the responsibility of any person or organization contemplating
17 * export to obtain such a license before exporting.
18 *
19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20 * distribute this software and its documentation for any purpose and
21 * without fee is hereby granted, provided that the above copyright
22 * notice appear in all copies and that both that copyright notice and
23 * this permission notice appear in supporting documentation, and that
24 * the name of M.I.T. not be used in advertising or publicity pertaining
25 * to distribution of the software without specific, written prior
26 * permission. Furthermore if you modify this software you must label
27 * your software as modified software and not distribute it in such a
28 * fashion that it might be confused with the original M.I.T. software.
29 * M.I.T. makes no representations about the suitability of
30 * this software for any purpose. It is provided "as is" without express
31 * or implied warranty.
32 *
33 *
34 * krb5_mk_safe()
35 */
36
37 #include "k5-int.h"
38 #include "cleanup.h"
39 #include "auth_con.h"
40
41 #ifdef KRB5_DEBUG
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #endif
47
48 /*
49 Formats a KRB_SAFE message into outbuf.
50
51 userdata is formatted as the user data in the message.
52 sumtype specifies the encryption type; key specifies the key which
53 might be used to seed the checksum; sender_addr and recv_addr specify
54 the full addresses (host and port) of the sender and receiver.
55 The host portion of sender_addr is used to form the addresses used in the
56 KRB_SAFE message.
57
58 The outbuf buffer storage is allocated, and should be freed by the
59 caller when finished.
60
61 returns system errors
62 */
63 /*ARGSUSED*/
64 static krb5_error_code
krb5_mk_safe_basic(krb5_context context,const krb5_data * userdata,const krb5_keyblock * keyblock,krb5_replay_data * replaydata,krb5_address * local_addr,krb5_address * remote_addr,krb5_cksumtype sumtype,krb5_data * outbuf)65 krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata,
66 const krb5_keyblock *keyblock, krb5_replay_data *replaydata,
67 krb5_address *local_addr, krb5_address *remote_addr,
68 krb5_cksumtype sumtype, krb5_data *outbuf)
69 {
70 krb5_error_code retval;
71 krb5_safe safemsg;
72 krb5_octet zero_octet = 0;
73 krb5_checksum safe_checksum;
74 krb5_data *scratch1, *scratch2;
75
76 /* Solaris Kerberos */
77 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe_basic() start");
78
79 if (!krb5_c_valid_cksumtype(sumtype))
80 return KRB5_PROG_SUMTYPE_NOSUPP;
81 if (!krb5_c_is_coll_proof_cksum(sumtype)
82 || !krb5_c_is_keyed_cksum(sumtype))
83 return KRB5KRB_AP_ERR_INAPP_CKSUM;
84
85 safemsg.user_data = *userdata;
86 safemsg.s_address = (krb5_address *) local_addr;
87 safemsg.r_address = (krb5_address *) remote_addr;
88
89 /* We should check too make sure one exists. */
90 safemsg.timestamp = replaydata->timestamp;
91 safemsg.usec = replaydata->usec;
92 safemsg.seq_number = replaydata->seq;
93
94 /*
95 * To do the checksum stuff, we need to encode the message with a
96 * zero-length zero-type checksum, then checksum the encoding, then
97 * re-encode with the checksum.
98 */
99
100 safe_checksum.length = 0;
101 safe_checksum.checksum_type = 0;
102 safe_checksum.contents = &zero_octet;
103
104 safemsg.checksum = &safe_checksum;
105
106 /* Solaris Kerberos */
107 if ((retval = encode_krb5_safe(&safemsg, &scratch1))){
108 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() end, error retval=%d", retval);
109 return retval;
110 }
111
112 /* Solaris Kerberos */
113 if ((retval = krb5_c_make_checksum(context, sumtype, keyblock,
114 KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
115 scratch1, &safe_checksum)) != 0){
116 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval);
117 /*
118 * If krb5_c_make_checksum() fails, the value of safe_checksum.contents
119 * is either still &zero_octet (i.e. a stack allocated value) or NULL.
120 * Not calling krb5_xfree() when krb5_c_make_checksum() fails safely
121 * handles either case.
122 */
123 goto cleanup;
124 }
125
126 safemsg.checksum = &safe_checksum;
127
128 /* Solaris Kerberos */
129 if ((retval = encode_krb5_safe(&safemsg, &scratch2))) {
130 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval);
131 goto cleanup_checksum;
132 }
133 *outbuf = *scratch2;
134 krb5_xfree(scratch2);
135 retval = 0;
136
137 cleanup_checksum:
138 krb5_xfree(safe_checksum.contents);
139
140 cleanup:
141 memset((char *)scratch1->data, 0, scratch1->length);
142 krb5_free_data(context, scratch1);
143 /* Solaris Kerberos */
144 KRB5_LOG(KRB5_INFO, "krb5_mk_safe_basic() end, retval=%d", retval);
145 return retval;
146 }
147
148 krb5_error_code KRB5_CALLCONV
krb5_mk_safe(krb5_context context,krb5_auth_context auth_context,const krb5_data * userdata,krb5_data * outbuf,krb5_replay_data * outdata)149 krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *userdata, krb5_data *outbuf, krb5_replay_data *outdata)
150 {
151 krb5_error_code retval;
152 krb5_keyblock * keyblock;
153 krb5_replay_data replaydata;
154
155 /* Solaris Kerberos */
156 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() start");
157
158 /* Clear replaydata block */
159 memset((char *) &replaydata, 0, sizeof(krb5_replay_data));
160
161 /* Get keyblock */
162 if ((keyblock = auth_context->send_subkey) == NULL)
163 keyblock = auth_context->keyblock;
164
165 /* Get replay info */
166 /* Solaris Kerberos */
167 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
168 (auth_context->rcache == NULL)){
169 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED);
170 return KRB5_RC_REQUIRED;
171 }
172
173 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
174 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
175 (outdata == NULL)){
176 /* Need a better error */
177 /* Solaris Kerberos */
178 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED);
179 return KRB5_RC_REQUIRED;
180 }
181
182 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) ||
183 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) {
184 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
185 &replaydata.usec))){
186 /* Solaris Kerberos */
187 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval);
188 return retval;
189 }
190 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
191 outdata->timestamp = replaydata.timestamp;
192 outdata->usec = replaydata.usec;
193 }
194 }
195 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
196 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
197 replaydata.seq = auth_context->local_seq_number++;
198 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) {
199 outdata->seq = replaydata.seq;
200 }
201 }
202
203 {
204 krb5_address * premote_fulladdr = NULL;
205 krb5_address * plocal_fulladdr = NULL;
206 krb5_address remote_fulladdr;
207 krb5_address local_fulladdr;
208 krb5_cksumtype sumtype;
209
210 CLEANUP_INIT(2);
211
212 if (auth_context->local_addr) {
213 if (auth_context->local_port) {
214 if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr,
215 auth_context->local_port,
216 &local_fulladdr))){
217 CLEANUP_PUSH(local_fulladdr.contents, free);
218 plocal_fulladdr = &local_fulladdr;
219 } else {
220 goto error;
221 }
222 } else {
223 plocal_fulladdr = auth_context->local_addr;
224 }
225
226 }
227
228 if (auth_context->remote_addr) {
229 if (auth_context->remote_port) {
230 if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
231 auth_context->remote_port,
232 &remote_fulladdr))){
233 CLEANUP_PUSH(remote_fulladdr.contents, free);
234 premote_fulladdr = &remote_fulladdr;
235 } else {
236 CLEANUP_DONE();
237 goto error;
238 }
239 } else {
240 premote_fulladdr = auth_context->remote_addr;
241 }
242 }
243
244 {
245 unsigned int nsumtypes;
246 unsigned int i;
247 krb5_cksumtype *sumtypes;
248 retval = krb5_c_keyed_checksum_types (context, keyblock->enctype,
249 &nsumtypes, &sumtypes);
250 if (retval) {
251 CLEANUP_DONE ();
252 goto error;
253 }
254 if (nsumtypes == 0) {
255 retval = KRB5_BAD_ENCTYPE;
256 krb5_free_cksumtypes (context, sumtypes);
257 CLEANUP_DONE ();
258 goto error;
259 }
260 for (i = 0; i < nsumtypes; i++)
261 if (auth_context->safe_cksumtype == sumtypes[i])
262 break;
263 if (i == nsumtypes)
264 i = 0;
265 sumtype = sumtypes[i];
266 krb5_free_cksumtypes (context, sumtypes);
267 }
268 if ((retval = krb5_mk_safe_basic(context, userdata, keyblock, &replaydata,
269 plocal_fulladdr, premote_fulladdr,
270 sumtype, outbuf))) {
271 CLEANUP_DONE();
272 goto error;
273 }
274
275 CLEANUP_DONE();
276 }
277
278 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
279 krb5_donot_replay replay;
280
281 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr,
282 "_safe", &replay.client))) {
283 krb5_xfree(outbuf);
284 goto error;
285 }
286
287 replay.server = ""; /* XXX */
288 replay.cusec = replaydata.usec;
289 replay.ctime = replaydata.timestamp;
290 /* Solaris Kerberos */
291 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay)) != 0) {
292 /* should we really error out here? XXX */
293 krb5_xfree(outbuf);
294 goto error;
295 }
296 krb5_xfree(replay.client);
297 }
298 /* Solaris Kerberos */
299 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() end");
300 return 0;
301
302 error:
303 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
304 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
305 auth_context->local_seq_number--;
306
307 /* Solaris Kerberos */
308 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval);
309 return retval;
310 }
311
312