1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * lib/krb5/krb/rd_priv.c 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * Copyright 1990,1991 by the Massachusetts Institute of Technology. 12*7c478bd9Sstevel@tonic-gate * All Rights Reserved. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 15*7c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 16*7c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 17*7c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 18*7c478bd9Sstevel@tonic-gate * 19*7c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20*7c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 21*7c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 22*7c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 23*7c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 24*7c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 25*7c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 26*7c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 27*7c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 28*7c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 29*7c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 30*7c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 31*7c478bd9Sstevel@tonic-gate * or implied warranty. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * krb5_rd_priv() 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 38*7c478bd9Sstevel@tonic-gate #include "cleanup.h" 39*7c478bd9Sstevel@tonic-gate #include <auth_con.h> 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate Parses a KRB_PRIV message from inbuf, placing the confidential user 46*7c478bd9Sstevel@tonic-gate data in *outbuf. 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate key specifies the key to be used for decryption of the message. 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate remote_addr and local_addr specify the full 51*7c478bd9Sstevel@tonic-gate addresses (host and port) of the sender and receiver. 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate outbuf points to allocated storage which the caller should 54*7c478bd9Sstevel@tonic-gate free when finished. 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate i_vector is used as an initialization vector for the 57*7c478bd9Sstevel@tonic-gate encryption, and if non-NULL its contents are replaced with the last 58*7c478bd9Sstevel@tonic-gate block of the encrypted data upon exit. 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate Returns system errors, integrity errors. 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate static krb5_error_code 65*7c478bd9Sstevel@tonic-gate krb5_rd_priv_basic( 66*7c478bd9Sstevel@tonic-gate krb5_context context, 67*7c478bd9Sstevel@tonic-gate const krb5_data * inbuf, 68*7c478bd9Sstevel@tonic-gate const krb5_keyblock * keyblock, 69*7c478bd9Sstevel@tonic-gate const krb5_address * local_addr, 70*7c478bd9Sstevel@tonic-gate const krb5_address * remote_addr, 71*7c478bd9Sstevel@tonic-gate krb5_pointer i_vector, 72*7c478bd9Sstevel@tonic-gate krb5_replay_data * replaydata, 73*7c478bd9Sstevel@tonic-gate krb5_data * outbuf) 74*7c478bd9Sstevel@tonic-gate { 75*7c478bd9Sstevel@tonic-gate krb5_error_code retval; 76*7c478bd9Sstevel@tonic-gate krb5_priv * privmsg; 77*7c478bd9Sstevel@tonic-gate krb5_data scratch; 78*7c478bd9Sstevel@tonic-gate krb5_priv_enc_part * privmsg_enc_part; 79*7c478bd9Sstevel@tonic-gate size_t blocksize; 80*7c478bd9Sstevel@tonic-gate krb5_data ivdata; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate if (!krb5_is_krb_priv(inbuf)) 83*7c478bd9Sstevel@tonic-gate return KRB5KRB_AP_ERR_MSG_TYPE; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* decode private message */ 86*7c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_priv(inbuf, &privmsg))) 87*7c478bd9Sstevel@tonic-gate return retval; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate if (i_vector) { 90*7c478bd9Sstevel@tonic-gate if ((retval = krb5_c_block_size(context, keyblock->enctype, 91*7c478bd9Sstevel@tonic-gate &blocksize))) 92*7c478bd9Sstevel@tonic-gate goto cleanup_privmsg; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate ivdata.length = blocksize; 95*7c478bd9Sstevel@tonic-gate ivdata.data = i_vector; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate scratch.length = privmsg->enc_part.ciphertext.length; 99*7c478bd9Sstevel@tonic-gate if (!(scratch.data = malloc(scratch.length))) { 100*7c478bd9Sstevel@tonic-gate retval = ENOMEM; 101*7c478bd9Sstevel@tonic-gate goto cleanup_privmsg; 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, keyblock, 105*7c478bd9Sstevel@tonic-gate KRB5_KEYUSAGE_KRB_PRIV_ENCPART, 106*7c478bd9Sstevel@tonic-gate i_vector?&ivdata:0, 107*7c478bd9Sstevel@tonic-gate &privmsg->enc_part, &scratch))) 108*7c478bd9Sstevel@tonic-gate goto cleanup_scratch; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* now decode the decrypted stuff */ 111*7c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part))) 112*7c478bd9Sstevel@tonic-gate goto cleanup_scratch; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate if (!krb5_address_compare(context,remote_addr,privmsg_enc_part->s_address)){ 115*7c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_BADADDR; 116*7c478bd9Sstevel@tonic-gate goto cleanup_data; 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate if (privmsg_enc_part->r_address) { 120*7c478bd9Sstevel@tonic-gate if (local_addr) { 121*7c478bd9Sstevel@tonic-gate if (!krb5_address_compare(context, local_addr, 122*7c478bd9Sstevel@tonic-gate privmsg_enc_part->r_address)) { 123*7c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_BADADDR; 124*7c478bd9Sstevel@tonic-gate goto cleanup_data; 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate } else { 127*7c478bd9Sstevel@tonic-gate krb5_address **our_addrs; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate if ((retval = krb5_os_localaddr(context, &our_addrs))) { 130*7c478bd9Sstevel@tonic-gate goto cleanup_data; 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate if (!krb5_address_search(context, privmsg_enc_part->r_address, 133*7c478bd9Sstevel@tonic-gate our_addrs)) { 134*7c478bd9Sstevel@tonic-gate krb5_free_addresses(context, our_addrs); 135*7c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_BADADDR; 136*7c478bd9Sstevel@tonic-gate goto cleanup_data; 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate krb5_free_addresses(context, our_addrs); 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate replaydata->timestamp = privmsg_enc_part->timestamp; 143*7c478bd9Sstevel@tonic-gate replaydata->usec = privmsg_enc_part->usec; 144*7c478bd9Sstevel@tonic-gate replaydata->seq = privmsg_enc_part->seq_number; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* everything is ok - return data to the user */ 147*7c478bd9Sstevel@tonic-gate *outbuf = privmsg_enc_part->user_data; 148*7c478bd9Sstevel@tonic-gate retval = 0; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate cleanup_data:; 151*7c478bd9Sstevel@tonic-gate if (retval == 0) 152*7c478bd9Sstevel@tonic-gate privmsg_enc_part->user_data.data = 0; 153*7c478bd9Sstevel@tonic-gate krb5_free_priv_enc_part(context, privmsg_enc_part); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate cleanup_scratch:; 156*7c478bd9Sstevel@tonic-gate (void) memset(scratch.data, 0, scratch.length); 157*7c478bd9Sstevel@tonic-gate krb5_xfree(scratch.data); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate cleanup_privmsg:; 160*7c478bd9Sstevel@tonic-gate krb5_xfree(privmsg->enc_part.ciphertext.data); 161*7c478bd9Sstevel@tonic-gate krb5_xfree(privmsg); 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate return retval; 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV 167*7c478bd9Sstevel@tonic-gate krb5_rd_priv( 168*7c478bd9Sstevel@tonic-gate krb5_context context, 169*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 170*7c478bd9Sstevel@tonic-gate const krb5_data * inbuf, 171*7c478bd9Sstevel@tonic-gate krb5_data * outbuf, 172*7c478bd9Sstevel@tonic-gate krb5_replay_data * outdata) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate krb5_error_code retval; 175*7c478bd9Sstevel@tonic-gate krb5_keyblock * keyblock; 176*7c478bd9Sstevel@tonic-gate krb5_replay_data replaydata; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* Get keyblock */ 179*7c478bd9Sstevel@tonic-gate if ((keyblock = auth_context->recv_subkey) == NULL) 180*7c478bd9Sstevel@tonic-gate keyblock = auth_context->keyblock; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 183*7c478bd9Sstevel@tonic-gate (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 184*7c478bd9Sstevel@tonic-gate (outdata == NULL)) 185*7c478bd9Sstevel@tonic-gate /* Need a better error */ 186*7c478bd9Sstevel@tonic-gate return KRB5_RC_REQUIRED; 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 189*7c478bd9Sstevel@tonic-gate (auth_context->rcache == NULL)) 190*7c478bd9Sstevel@tonic-gate return KRB5_RC_REQUIRED; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate krb5_address * premote_fulladdr = NULL; 194*7c478bd9Sstevel@tonic-gate krb5_address * plocal_fulladdr = NULL; 195*7c478bd9Sstevel@tonic-gate krb5_address remote_fulladdr; 196*7c478bd9Sstevel@tonic-gate krb5_address local_fulladdr; 197*7c478bd9Sstevel@tonic-gate CLEANUP_INIT(2); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate if (auth_context->local_addr) { 200*7c478bd9Sstevel@tonic-gate if (auth_context->local_port) { 201*7c478bd9Sstevel@tonic-gate if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, 202*7c478bd9Sstevel@tonic-gate auth_context->local_port, 203*7c478bd9Sstevel@tonic-gate &local_fulladdr))){ 204*7c478bd9Sstevel@tonic-gate CLEANUP_PUSH(local_fulladdr.contents, free); 205*7c478bd9Sstevel@tonic-gate plocal_fulladdr = &local_fulladdr; 206*7c478bd9Sstevel@tonic-gate } else { 207*7c478bd9Sstevel@tonic-gate return retval; 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate } else { 210*7c478bd9Sstevel@tonic-gate plocal_fulladdr = auth_context->local_addr; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate if (auth_context->remote_addr) { 215*7c478bd9Sstevel@tonic-gate if (auth_context->remote_port) { 216*7c478bd9Sstevel@tonic-gate if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, 217*7c478bd9Sstevel@tonic-gate auth_context->remote_port, 218*7c478bd9Sstevel@tonic-gate &remote_fulladdr))){ 219*7c478bd9Sstevel@tonic-gate CLEANUP_PUSH(remote_fulladdr.contents, free); 220*7c478bd9Sstevel@tonic-gate premote_fulladdr = &remote_fulladdr; 221*7c478bd9Sstevel@tonic-gate } else { 222*7c478bd9Sstevel@tonic-gate CLEANUP_DONE(); 223*7c478bd9Sstevel@tonic-gate return retval; 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate } else { 226*7c478bd9Sstevel@tonic-gate premote_fulladdr = auth_context->remote_addr; 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate if ((retval = krb5_rd_priv_basic(context, inbuf, keyblock, 231*7c478bd9Sstevel@tonic-gate plocal_fulladdr, 232*7c478bd9Sstevel@tonic-gate premote_fulladdr, 233*7c478bd9Sstevel@tonic-gate auth_context->i_vector, 234*7c478bd9Sstevel@tonic-gate &replaydata, outbuf))) { 235*7c478bd9Sstevel@tonic-gate CLEANUP_DONE(); 236*7c478bd9Sstevel@tonic-gate return retval; 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate CLEANUP_DONE(); 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 243*7c478bd9Sstevel@tonic-gate krb5_donot_replay replay; 244*7c478bd9Sstevel@tonic-gate krb5_timestamp currenttime; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate if ((retval = krb5_timeofday(context, ¤ttime))) 247*7c478bd9Sstevel@tonic-gate goto error; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (!in_clock_skew(replaydata.timestamp)) { 250*7c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_SKEW; 251*7c478bd9Sstevel@tonic-gate goto error; 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 255*7c478bd9Sstevel@tonic-gate "_priv", &replay.client))) 256*7c478bd9Sstevel@tonic-gate goto error; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate replay.server = ""; /* XXX */ 259*7c478bd9Sstevel@tonic-gate replay.cusec = replaydata.usec; 260*7c478bd9Sstevel@tonic-gate replay.ctime = replaydata.timestamp; 261*7c478bd9Sstevel@tonic-gate retval = krb5_rc_store(context, auth_context->rcache, &replay); 262*7c478bd9Sstevel@tonic-gate if (retval) { 263*7c478bd9Sstevel@tonic-gate krb5_xfree(replay.client); 264*7c478bd9Sstevel@tonic-gate goto error; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate krb5_xfree(replay.client); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { 270*7c478bd9Sstevel@tonic-gate if (auth_context->remote_seq_number != replaydata.seq) { 271*7c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_BADORDER; 272*7c478bd9Sstevel@tonic-gate goto error; 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate auth_context->remote_seq_number++; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 278*7c478bd9Sstevel@tonic-gate (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 279*7c478bd9Sstevel@tonic-gate outdata->timestamp = replaydata.timestamp; 280*7c478bd9Sstevel@tonic-gate outdata->usec = replaydata.usec; 281*7c478bd9Sstevel@tonic-gate outdata->seq = replaydata.seq; 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* everything is ok - return data to the user */ 285*7c478bd9Sstevel@tonic-gate return 0; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate error:; 288*7c478bd9Sstevel@tonic-gate krb5_xfree(outbuf->data); 289*7c478bd9Sstevel@tonic-gate return retval; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate } 292