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