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
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)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
krb5_mk_priv(krb5_context context,krb5_auth_context auth_context,const krb5_data * userdata,krb5_data * outbuf,krb5_replay_data * outdata)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