1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 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 65 krb5_mk_safe_basic( 66 krb5_context context, 67 const krb5_data * userdata, 68 const krb5_keyblock * keyblock, 69 krb5_replay_data * replaydata, 70 const krb5_address * local_addr, 71 const krb5_address * remote_addr, 72 const krb5_cksumtype sumtype, 73 krb5_data * outbuf) 74 { 75 krb5_error_code retval; 76 krb5_safe safemsg; 77 krb5_octet zero_octet = 0; 78 krb5_checksum safe_checksum; 79 krb5_data *scratch1, *scratch2; 80 81 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe_basic() start"); 82 83 if (!krb5_c_valid_cksumtype(sumtype)) 84 return KRB5_PROG_SUMTYPE_NOSUPP; 85 if (!krb5_c_is_coll_proof_cksum(sumtype) || 86 !krb5_c_is_keyed_cksum(sumtype)) 87 return KRB5KRB_AP_ERR_INAPP_CKSUM; 88 89 safemsg.user_data = *userdata; 90 safemsg.s_address = (krb5_address *) local_addr; 91 safemsg.r_address = (krb5_address *) remote_addr; 92 93 /* We should check too make sure one exists. */ 94 safemsg.timestamp = replaydata->timestamp; 95 safemsg.usec = replaydata->usec; 96 safemsg.seq_number = replaydata->seq; 97 98 /* 99 * To do the checksum stuff, we need to encode the message with a 100 * zero-length zero-type checksum, then checksum the encoding, then 101 * re-encode with the checksum. 102 */ 103 104 safe_checksum.length = 0; 105 safe_checksum.checksum_type = 0; 106 safe_checksum.contents = &zero_octet; 107 108 safemsg.checksum = &safe_checksum; 109 110 if ((retval = encode_krb5_safe(&safemsg, &scratch1))){ 111 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() end, error retval=%d", retval); 112 return retval; 113 } 114 115 if ((retval = krb5_c_make_checksum(context, sumtype, keyblock, 116 KRB5_KEYUSAGE_KRB_SAFE_CKSUM, 117 scratch1, &safe_checksum)) != 0){ 118 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval); 119 goto cleanup_checksum; 120 } 121 122 safemsg.checksum = &safe_checksum; 123 if ((retval = encode_krb5_safe(&safemsg, &scratch2))) { 124 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval); 125 goto cleanup_checksum; 126 } 127 *outbuf = *scratch2; 128 krb5_xfree(scratch2); 129 retval = 0; 130 131 cleanup_checksum: 132 krb5_xfree(safe_checksum.contents); 133 134 cleanup_scratch: 135 memset((char *)scratch1->data, 0, scratch1->length); 136 krb5_free_data(context, scratch1); 137 KRB5_LOG(KRB5_INFO, "krb5_mk_safe_basic() end, retval=%d", retval); 138 return retval; 139 } 140 141 krb5_error_code KRB5_CALLCONV 142 krb5_mk_safe( 143 krb5_context context, 144 krb5_auth_context auth_context, 145 const krb5_data *userdata, 146 krb5_data *outbuf, 147 krb5_replay_data *outdata) 148 { 149 krb5_error_code retval; 150 krb5_keyblock * keyblock; 151 krb5_replay_data replaydata; 152 153 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() start"); 154 155 /* Clear replaydata block */ 156 memset((char *) &replaydata, 0, sizeof(krb5_replay_data)); 157 158 /* Get keyblock */ 159 if ((keyblock = auth_context->send_subkey) == NULL) 160 keyblock = auth_context->keyblock; 161 162 /* Get replay info */ 163 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 164 (auth_context->rcache == NULL)){ 165 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED); 166 return KRB5_RC_REQUIRED; 167 } 168 169 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 170 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 171 (outdata == NULL)){ 172 /* Need a better error */ 173 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED); 174 return KRB5_RC_REQUIRED; 175 } 176 177 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || 178 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { 179 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, 180 &replaydata.usec))){ 181 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval); 182 return retval; 183 } 184 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { 185 outdata->timestamp = replaydata.timestamp; 186 outdata->usec = replaydata.usec; 187 } 188 } 189 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 190 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 191 replaydata.seq = auth_context->local_seq_number++; 192 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) { 193 outdata->seq = replaydata.seq; 194 } 195 } 196 197 { 198 krb5_address * premote_fulladdr = NULL; 199 krb5_address * plocal_fulladdr = NULL; 200 krb5_address remote_fulladdr; 201 krb5_address local_fulladdr; 202 krb5_cksumtype sumtype; 203 204 CLEANUP_INIT(2); 205 206 if (auth_context->local_addr) { 207 if (auth_context->local_port) { 208 if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, 209 auth_context->local_port, 210 &local_fulladdr))){ 211 CLEANUP_PUSH(local_fulladdr.contents, free); 212 plocal_fulladdr = &local_fulladdr; 213 } else { 214 goto error; 215 } 216 } else { 217 plocal_fulladdr = auth_context->local_addr; 218 } 219 220 } 221 222 if (auth_context->remote_addr) { 223 if (auth_context->remote_port) { 224 if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, 225 auth_context->remote_port, 226 &remote_fulladdr))){ 227 CLEANUP_PUSH(remote_fulladdr.contents, free); 228 premote_fulladdr = &remote_fulladdr; 229 } else { 230 CLEANUP_DONE(); 231 goto error; 232 } 233 } else { 234 premote_fulladdr = auth_context->remote_addr; 235 } 236 } 237 238 { 239 unsigned int nsumtypes; 240 unsigned int i; 241 krb5_cksumtype *sumtypes; 242 retval = krb5_c_keyed_checksum_types (context, keyblock->enctype, 243 &nsumtypes, &sumtypes); 244 if (retval) { 245 CLEANUP_DONE (); 246 goto error; 247 } 248 if (nsumtypes == 0) { 249 retval = KRB5_BAD_ENCTYPE; 250 krb5_free_cksumtypes (context, sumtypes); 251 CLEANUP_DONE (); 252 goto error; 253 } 254 for (i = 0; i < nsumtypes; i++) 255 if (auth_context->safe_cksumtype == sumtypes[i]) 256 break; 257 if (i == nsumtypes) 258 i = 0; 259 sumtype = sumtypes[i]; 260 krb5_free_cksumtypes (context, sumtypes); 261 } 262 263 if ((retval = krb5_mk_safe_basic(context, userdata, keyblock, &replaydata, 264 plocal_fulladdr, premote_fulladdr, 265 sumtype, outbuf))) { 266 CLEANUP_DONE(); 267 goto error; 268 } 269 270 CLEANUP_DONE(); 271 } 272 273 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 274 krb5_donot_replay replay; 275 276 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, 277 "_safe", &replay.client))) { 278 krb5_xfree(outbuf); 279 goto error; 280 } 281 282 replay.server = ""; /* XXX */ 283 replay.cusec = replaydata.usec; 284 replay.ctime = replaydata.timestamp; 285 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay)) != 0) { 286 /* should we really error out here? XXX */ 287 krb5_xfree(outbuf); 288 goto error; 289 } 290 krb5_xfree(replay.client); 291 } 292 293 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() end"); 294 return 0; 295 296 error: 297 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 298 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 299 auth_context->local_seq_number--; 300 301 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval); 302 return retval; 303 } 304