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_safe.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_safe() 34 */ 35 36 #include "k5-int.h" 37 #include "cleanup.h" 38 #include "auth_con.h" 39 40 #ifdef KRB5_DEBUG 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #endif 46 47 /* 48 Formats a KRB_SAFE message into outbuf. 49 50 userdata is formatted as the user data in the message. 51 sumtype specifies the encryption type; key specifies the key which 52 might be used to seed the checksum; sender_addr and recv_addr specify 53 the full addresses (host and port) of the sender and receiver. 54 The host portion of sender_addr is used to form the addresses used in the 55 KRB_SAFE message. 56 57 The outbuf buffer storage is allocated, and should be freed by the 58 caller when finished. 59 60 returns system errors 61 */ 62 /*ARGSUSED*/ 63 static krb5_error_code 64 krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata, 65 const krb5_keyblock *keyblock, krb5_replay_data *replaydata, 66 krb5_address *local_addr, krb5_address *remote_addr, 67 krb5_cksumtype sumtype, krb5_data *outbuf) 68 { 69 krb5_error_code retval; 70 krb5_safe safemsg; 71 krb5_octet zero_octet = 0; 72 krb5_checksum safe_checksum; 73 krb5_data *scratch1, *scratch2; 74 75 /* Solaris Kerberos */ 76 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe_basic() start"); 77 78 if (!krb5_c_valid_cksumtype(sumtype)) 79 return KRB5_PROG_SUMTYPE_NOSUPP; 80 if (!krb5_c_is_coll_proof_cksum(sumtype) 81 || !krb5_c_is_keyed_cksum(sumtype)) 82 return KRB5KRB_AP_ERR_INAPP_CKSUM; 83 84 safemsg.user_data = *userdata; 85 safemsg.s_address = (krb5_address *) local_addr; 86 safemsg.r_address = (krb5_address *) remote_addr; 87 88 /* We should check too make sure one exists. */ 89 safemsg.timestamp = replaydata->timestamp; 90 safemsg.usec = replaydata->usec; 91 safemsg.seq_number = replaydata->seq; 92 93 /* 94 * To do the checksum stuff, we need to encode the message with a 95 * zero-length zero-type checksum, then checksum the encoding, then 96 * re-encode with the checksum. 97 */ 98 99 safe_checksum.length = 0; 100 safe_checksum.checksum_type = 0; 101 safe_checksum.contents = &zero_octet; 102 103 safemsg.checksum = &safe_checksum; 104 105 /* Solaris Kerberos */ 106 if ((retval = encode_krb5_safe(&safemsg, &scratch1))){ 107 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() end, error retval=%d", retval); 108 return retval; 109 } 110 111 /* Solaris Kerberos */ 112 if ((retval = krb5_c_make_checksum(context, sumtype, keyblock, 113 KRB5_KEYUSAGE_KRB_SAFE_CKSUM, 114 scratch1, &safe_checksum)) != 0){ 115 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval); 116 goto cleanup_checksum; 117 } 118 119 safemsg.checksum = &safe_checksum; 120 121 /* Solaris Kerberos */ 122 if ((retval = encode_krb5_safe(&safemsg, &scratch2))) { 123 KRB5_LOG(KRB5_ERR, "krb5_mk_safe_basic() error retval=%d", retval); 124 goto cleanup_checksum; 125 } 126 *outbuf = *scratch2; 127 krb5_xfree(scratch2); 128 retval = 0; 129 130 cleanup_checksum: 131 krb5_xfree(safe_checksum.contents); 132 133 memset((char *)scratch1->data, 0, scratch1->length); 134 krb5_free_data(context, scratch1); 135 /* Solaris Kerberos */ 136 KRB5_LOG(KRB5_INFO, "krb5_mk_safe_basic() end, retval=%d", retval); 137 return retval; 138 } 139 140 krb5_error_code KRB5_CALLCONV 141 krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *userdata, krb5_data *outbuf, krb5_replay_data *outdata) 142 { 143 krb5_error_code retval; 144 krb5_keyblock * keyblock; 145 krb5_replay_data replaydata; 146 147 /* Solaris Kerberos */ 148 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() start"); 149 150 /* Clear replaydata block */ 151 memset((char *) &replaydata, 0, sizeof(krb5_replay_data)); 152 153 /* Get keyblock */ 154 if ((keyblock = auth_context->send_subkey) == NULL) 155 keyblock = auth_context->keyblock; 156 157 /* Get replay info */ 158 /* Solaris Kerberos */ 159 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 160 (auth_context->rcache == NULL)){ 161 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED); 162 return KRB5_RC_REQUIRED; 163 } 164 165 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 166 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 167 (outdata == NULL)){ 168 /* Need a better error */ 169 /* Solaris Kerberos */ 170 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", KRB5_RC_REQUIRED); 171 return KRB5_RC_REQUIRED; 172 } 173 174 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || 175 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { 176 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, 177 &replaydata.usec))){ 178 /* Solaris Kerberos */ 179 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval); 180 return retval; 181 } 182 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { 183 outdata->timestamp = replaydata.timestamp; 184 outdata->usec = replaydata.usec; 185 } 186 } 187 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 188 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 189 replaydata.seq = auth_context->local_seq_number++; 190 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) { 191 outdata->seq = replaydata.seq; 192 } 193 } 194 195 { 196 krb5_address * premote_fulladdr = NULL; 197 krb5_address * plocal_fulladdr = NULL; 198 krb5_address remote_fulladdr; 199 krb5_address local_fulladdr; 200 krb5_cksumtype sumtype; 201 202 CLEANUP_INIT(2); 203 204 if (auth_context->local_addr) { 205 if (auth_context->local_port) { 206 if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, 207 auth_context->local_port, 208 &local_fulladdr))){ 209 CLEANUP_PUSH(local_fulladdr.contents, free); 210 plocal_fulladdr = &local_fulladdr; 211 } else { 212 goto error; 213 } 214 } else { 215 plocal_fulladdr = auth_context->local_addr; 216 } 217 218 } 219 220 if (auth_context->remote_addr) { 221 if (auth_context->remote_port) { 222 if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, 223 auth_context->remote_port, 224 &remote_fulladdr))){ 225 CLEANUP_PUSH(remote_fulladdr.contents, free); 226 premote_fulladdr = &remote_fulladdr; 227 } else { 228 CLEANUP_DONE(); 229 goto error; 230 } 231 } else { 232 premote_fulladdr = auth_context->remote_addr; 233 } 234 } 235 236 { 237 unsigned int nsumtypes; 238 unsigned int i; 239 krb5_cksumtype *sumtypes; 240 retval = krb5_c_keyed_checksum_types (context, keyblock->enctype, 241 &nsumtypes, &sumtypes); 242 if (retval) { 243 CLEANUP_DONE (); 244 goto error; 245 } 246 if (nsumtypes == 0) { 247 retval = KRB5_BAD_ENCTYPE; 248 krb5_free_cksumtypes (context, sumtypes); 249 CLEANUP_DONE (); 250 goto error; 251 } 252 for (i = 0; i < nsumtypes; i++) 253 if (auth_context->safe_cksumtype == sumtypes[i]) 254 break; 255 if (i == nsumtypes) 256 i = 0; 257 sumtype = sumtypes[i]; 258 krb5_free_cksumtypes (context, sumtypes); 259 } 260 if ((retval = krb5_mk_safe_basic(context, userdata, keyblock, &replaydata, 261 plocal_fulladdr, premote_fulladdr, 262 sumtype, outbuf))) { 263 CLEANUP_DONE(); 264 goto error; 265 } 266 267 CLEANUP_DONE(); 268 } 269 270 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 271 krb5_donot_replay replay; 272 273 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, 274 "_safe", &replay.client))) { 275 krb5_xfree(outbuf); 276 goto error; 277 } 278 279 replay.server = ""; /* XXX */ 280 replay.cusec = replaydata.usec; 281 replay.ctime = replaydata.timestamp; 282 /* Solaris Kerberos */ 283 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay)) != 0) { 284 /* should we really error out here? XXX */ 285 krb5_xfree(outbuf); 286 goto error; 287 } 288 krb5_xfree(replay.client); 289 } 290 /* Solaris Kerberos */ 291 KRB5_LOG0(KRB5_INFO, "krb5_mk_safe() end"); 292 return 0; 293 294 error: 295 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 296 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 297 auth_context->local_seq_number--; 298 299 /* Solaris Kerberos */ 300 KRB5_LOG(KRB5_ERR, "krb5_mk_safe() end error retval=%d", retval); 301 return retval; 302 } 303 304