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_priv.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_priv() 35 */ 36 37 #include <k5-int.h> 38 #include "cleanup.h" 39 #include <auth_con.h> 40 41 /*ARGSUSED*/ 42 static krb5_error_code 43 krb5_mk_priv_basic( 44 krb5_context context, 45 const krb5_data * userdata, 46 const krb5_keyblock * keyblock, 47 krb5_replay_data * replaydata, 48 krb5_address * local_addr, 49 krb5_address * remote_addr, 50 krb5_pointer i_vector, 51 krb5_data * outbuf) 52 { 53 krb5_error_code retval; 54 krb5_priv privmsg; 55 krb5_priv_enc_part privmsg_enc_part; 56 krb5_data *scratch1, *scratch2, ivdata; 57 size_t blocksize, enclen; 58 59 privmsg.enc_part.kvno = 0; /* XXX allow user-set? */ 60 privmsg.enc_part.enctype = keyblock->enctype; 61 62 privmsg_enc_part.user_data = *userdata; 63 privmsg_enc_part.s_address = local_addr; 64 privmsg_enc_part.r_address = remote_addr; 65 66 /* We should check too make sure one exists. */ 67 privmsg_enc_part.timestamp = replaydata->timestamp; 68 privmsg_enc_part.usec = replaydata->usec; 69 privmsg_enc_part.seq_number = replaydata->seq; 70 71 /* start by encoding to-be-encrypted part of the message */ 72 if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1))) 73 return retval; 74 75 /* put together an eblock for this encryption */ 76 if ((retval = krb5_c_encrypt_length(context, keyblock->enctype, 77 scratch1->length, &enclen))) 78 goto clean_scratch; 79 80 privmsg.enc_part.ciphertext.length = enclen; 81 if (!(privmsg.enc_part.ciphertext.data = 82 malloc(privmsg.enc_part.ciphertext.length))) { 83 retval = ENOMEM; 84 goto clean_scratch; 85 } 86 87 /* call the encryption routine */ 88 if (i_vector) { 89 if ((retval = krb5_c_block_size(context, keyblock->enctype, 90 &blocksize))) 91 goto clean_encpart; 92 93 ivdata.length = blocksize; 94 ivdata.data = i_vector; 95 } 96 97 retval = krb5_c_encrypt(context, keyblock, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, 98 i_vector?&ivdata:0, scratch1, &privmsg.enc_part); 99 if (retval) 100 goto clean_encpart; 101 102 retval = encode_krb5_priv(&privmsg, &scratch2); 103 if (retval) 104 goto clean_encpart; 105 106 *outbuf = *scratch2; 107 krb5_xfree(scratch2); 108 retval = 0; 109 110 clean_encpart: 111 memset(privmsg.enc_part.ciphertext.data, 0, 112 privmsg.enc_part.ciphertext.length); 113 free(privmsg.enc_part.ciphertext.data); 114 privmsg.enc_part.ciphertext.length = 0; 115 privmsg.enc_part.ciphertext.data = 0; 116 117 clean_scratch: 118 memset(scratch1->data, 0, scratch1->length); 119 krb5_free_data(context, scratch1); 120 121 return retval; 122 } 123 124 125 krb5_error_code KRB5_CALLCONV 126 krb5_mk_priv( 127 krb5_context context, 128 krb5_auth_context auth_context, 129 const krb5_data *userdata, 130 krb5_data *outbuf, 131 krb5_replay_data *outdata) 132 { 133 krb5_error_code retval; 134 krb5_keyblock * keyblock; 135 krb5_replay_data replaydata; 136 137 /* Clear replaydata block */ 138 memset((char *) &replaydata, 0, sizeof(krb5_replay_data)); 139 140 /* Get keyblock */ 141 if ((keyblock = auth_context->send_subkey) == NULL) 142 keyblock = auth_context->keyblock; 143 144 /* Get replay info */ 145 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 146 (auth_context->rcache == NULL)) 147 return KRB5_RC_REQUIRED; 148 149 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 150 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 151 (outdata == NULL)) 152 /* Need a better error */ 153 return KRB5_RC_REQUIRED; 154 155 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || 156 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { 157 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, 158 &replaydata.usec))) 159 return retval; 160 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { 161 outdata->timestamp = replaydata.timestamp; 162 outdata->usec = replaydata.usec; 163 } 164 } 165 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 166 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 167 replaydata.seq = auth_context->local_seq_number; 168 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { 169 auth_context->local_seq_number++; 170 } else { 171 outdata->seq = replaydata.seq; 172 } 173 } 174 175 { 176 krb5_address * premote_fulladdr = NULL; 177 krb5_address * plocal_fulladdr = NULL; 178 krb5_address remote_fulladdr; 179 krb5_address local_fulladdr; 180 CLEANUP_INIT(2); 181 182 if (auth_context->local_addr) { 183 if (auth_context->local_port) { 184 if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, 185 auth_context->local_port, 186 &local_fulladdr))) { 187 CLEANUP_PUSH(local_fulladdr.contents, free); 188 plocal_fulladdr = &local_fulladdr; 189 } else { 190 goto error; 191 } 192 } else { 193 plocal_fulladdr = auth_context->local_addr; 194 } 195 } 196 197 if (auth_context->remote_addr) { 198 if (auth_context->remote_port) { 199 if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, 200 auth_context->remote_port, 201 &remote_fulladdr))){ 202 CLEANUP_PUSH(remote_fulladdr.contents, free); 203 premote_fulladdr = &remote_fulladdr; 204 } else { 205 CLEANUP_DONE(); 206 goto error; 207 } 208 } else { 209 premote_fulladdr = auth_context->remote_addr; 210 } 211 } 212 213 if ((retval = krb5_mk_priv_basic(context, userdata, keyblock, &replaydata, 214 plocal_fulladdr, premote_fulladdr, 215 auth_context->i_vector, outbuf))) { 216 CLEANUP_DONE(); 217 goto error; 218 } 219 220 CLEANUP_DONE(); 221 } 222 223 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 224 krb5_donot_replay replay; 225 226 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, 227 "_priv", &replay.client))) { 228 krb5_xfree(outbuf); 229 goto error; 230 } 231 232 replay.server = ""; /* XXX */ 233 replay.cusec = replaydata.usec; 234 replay.ctime = replaydata.timestamp; 235 retval = krb5_rc_store(context, auth_context->rcache, &replay); 236 if (retval) { 237 /* should we really error out here? XXX */ 238 krb5_xfree(replay.client); 239 goto error; 240 } 241 krb5_xfree(replay.client); 242 } 243 244 return 0; 245 246 error: 247 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || 248 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 249 auth_context->local_seq_number--; 250 251 return retval; 252 } 253