1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/ser_actx.c - Serialize krb5_auth_context structure */
3 /*
4 * Copyright 1995, 2008 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include "int-proto.h"
29 #include "auth_con.h"
30
31 #define TOKEN_RADDR 950916
32 #define TOKEN_RPORT 950917
33 #define TOKEN_LADDR 950918
34 #define TOKEN_LPORT 950919
35 #define TOKEN_KEYBLOCK 950920
36 #define TOKEN_LSKBLOCK 950921
37 #define TOKEN_RSKBLOCK 950922
38
39 krb5_error_code
k5_size_auth_context(krb5_auth_context auth_context,size_t * sizep)40 k5_size_auth_context(krb5_auth_context auth_context, size_t *sizep)
41 {
42 krb5_error_code kret;
43 size_t required;
44
45 /*
46 * krb5_auth_context requires at minimum:
47 * krb5_int32 for KV5M_AUTH_CONTEXT
48 * krb5_int32 for auth_context_flags
49 * krb5_int32 for remote_seq_number
50 * krb5_int32 for local_seq_number
51 * krb5_int32 for req_cksumtype
52 * krb5_int32 for safe_cksumtype
53 * krb5_int32 for size of i_vector
54 * krb5_int32 for KV5M_AUTH_CONTEXT
55 */
56 kret = EINVAL;
57 if (auth_context != NULL) {
58 kret = 0;
59
60 required = auth_context->cstate.length;
61 required += sizeof(krb5_int32)*8;
62
63 /* Calculate size required by remote_addr, if appropriate */
64 if (!kret && auth_context->remote_addr) {
65 kret = k5_size_address(auth_context->remote_addr, &required);
66 if (!kret)
67 required += sizeof(krb5_int32);
68 }
69
70 /* Calculate size required by remote_port, if appropriate */
71 if (!kret && auth_context->remote_port) {
72 kret = k5_size_address(auth_context->remote_port, &required);
73 if (!kret)
74 required += sizeof(krb5_int32);
75 }
76
77 /* Calculate size required by local_addr, if appropriate */
78 if (!kret && auth_context->local_addr) {
79 kret = k5_size_address(auth_context->local_addr, &required);
80 if (!kret)
81 required += sizeof(krb5_int32);
82 }
83
84 /* Calculate size required by local_port, if appropriate */
85 if (!kret && auth_context->local_port) {
86 kret = k5_size_address(auth_context->local_port, &required);
87 if (!kret)
88 required += sizeof(krb5_int32);
89 }
90
91 /* Calculate size required by key, if appropriate */
92 if (!kret && auth_context->key) {
93 kret = k5_size_keyblock(&auth_context->key->keyblock, &required);
94 if (!kret)
95 required += sizeof(krb5_int32);
96 }
97
98 /* Calculate size required by send_subkey, if appropriate */
99 if (!kret && auth_context->send_subkey) {
100 kret = k5_size_keyblock(&auth_context->send_subkey->keyblock,
101 &required);
102 if (!kret)
103 required += sizeof(krb5_int32);
104 }
105
106 /* Calculate size required by recv_subkey, if appropriate */
107 if (!kret && auth_context->recv_subkey) {
108 kret = k5_size_keyblock(&auth_context->recv_subkey->keyblock,
109 &required);
110 if (!kret)
111 required += sizeof(krb5_int32);
112 }
113
114 /* Calculate size required by authentp, if appropriate */
115 if (!kret && auth_context->authentp)
116 kret = k5_size_authenticator(auth_context->authentp, &required);
117
118 }
119 if (!kret)
120 *sizep += required;
121 return(kret);
122 }
123
124 krb5_error_code
k5_externalize_auth_context(krb5_auth_context auth_context,krb5_octet ** buffer,size_t * lenremain)125 k5_externalize_auth_context(krb5_auth_context auth_context,
126 krb5_octet **buffer, size_t *lenremain)
127 {
128 krb5_error_code kret;
129 size_t required;
130 krb5_octet *bp;
131 size_t remain;
132
133 required = 0;
134 bp = *buffer;
135 remain = *lenremain;
136 kret = EINVAL;
137 if (auth_context != NULL) {
138 kret = ENOMEM;
139 if (!k5_size_auth_context(auth_context, &required) &&
140 required <= remain) {
141
142 /* Write fixed portion */
143 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
144 (void) krb5_ser_pack_int32(auth_context->auth_context_flags,
145 &bp, &remain);
146 (void) krb5_ser_pack_int32(auth_context->remote_seq_number,
147 &bp, &remain);
148 (void) krb5_ser_pack_int32(auth_context->local_seq_number,
149 &bp, &remain);
150 (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype,
151 &bp, &remain);
152 (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
153 &bp, &remain);
154
155 /* Write the cipher state */
156 (void) krb5_ser_pack_int32(auth_context->cstate.length, &bp,
157 &remain);
158 (void) krb5_ser_pack_bytes((krb5_octet *)auth_context->cstate.data,
159 auth_context->cstate.length,
160 &bp, &remain);
161
162 kret = 0;
163
164 /* Now handle remote_addr, if appropriate */
165 if (!kret && auth_context->remote_addr) {
166 (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain);
167 kret = k5_externalize_address(auth_context->remote_addr,
168 &bp, &remain);
169 }
170
171 /* Now handle remote_port, if appropriate */
172 if (!kret && auth_context->remote_port) {
173 (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain);
174 kret = k5_externalize_address(auth_context->remote_addr,
175 &bp, &remain);
176 }
177
178 /* Now handle local_addr, if appropriate */
179 if (!kret && auth_context->local_addr) {
180 (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain);
181 kret = k5_externalize_address(auth_context->local_addr,
182 &bp, &remain);
183 }
184
185 /* Now handle local_port, if appropriate */
186 if (!kret && auth_context->local_port) {
187 (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain);
188 kret = k5_externalize_address(auth_context->local_addr,
189 &bp, &remain);
190 }
191
192 /* Now handle keyblock, if appropriate */
193 if (!kret && auth_context->key) {
194 (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain);
195 kret = k5_externalize_keyblock(&auth_context->key->keyblock,
196 &bp, &remain);
197 }
198
199 /* Now handle subkey, if appropriate */
200 if (!kret && auth_context->send_subkey) {
201 (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain);
202 kret = k5_externalize_keyblock(&auth_context->
203 send_subkey->keyblock,
204 &bp, &remain);
205 }
206
207 /* Now handle subkey, if appropriate */
208 if (!kret && auth_context->recv_subkey) {
209 (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain);
210 kret = k5_externalize_keyblock(&auth_context->
211 recv_subkey->keyblock,
212 &bp, &remain);
213 }
214
215 /* Now handle authentp, if appropriate */
216 if (!kret && auth_context->authentp)
217 kret = k5_externalize_authenticator(auth_context->authentp,
218 &bp, &remain);
219
220 /*
221 * If we were successful, write trailer then update the pointer and
222 * remaining length;
223 */
224 if (!kret) {
225 /* Write our trailer */
226 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
227 *buffer = bp;
228 *lenremain = remain;
229 }
230 }
231 }
232 return(kret);
233 }
234
235 /* Internalize a keyblock and convert it to a key. */
236 static krb5_error_code
intern_key(krb5_key * key,krb5_octet ** bp,size_t * sp)237 intern_key(krb5_key *key, krb5_octet **bp, size_t *sp)
238 {
239 krb5_keyblock *keyblock;
240 krb5_error_code ret;
241
242 ret = k5_internalize_keyblock(&keyblock, bp, sp);
243 if (ret != 0)
244 return ret;
245 ret = krb5_k_create_key(NULL, keyblock, key);
246 krb5_free_keyblock(NULL, keyblock);
247 return ret;
248 }
249
250 krb5_error_code
k5_internalize_auth_context(krb5_auth_context * argp,krb5_octet ** buffer,size_t * lenremain)251 k5_internalize_auth_context(krb5_auth_context *argp,
252 krb5_octet **buffer, size_t *lenremain)
253 {
254 krb5_error_code kret;
255 krb5_auth_context auth_context;
256 krb5_int32 ibuf;
257 krb5_octet *bp;
258 size_t remain;
259 krb5_int32 cstate_len;
260 krb5_int32 tag;
261
262 bp = *buffer;
263 remain = *lenremain;
264 kret = EINVAL;
265 /* Read our magic number */
266 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
267 ibuf = 0;
268 if (ibuf == KV5M_AUTH_CONTEXT) {
269 kret = ENOMEM;
270
271 /* Get memory for the auth_context */
272 if ((remain >= (5*sizeof(krb5_int32))) &&
273 (auth_context = (krb5_auth_context)
274 calloc(1, sizeof(struct _krb5_auth_context)))) {
275
276 /* Get auth_context_flags */
277 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
278 auth_context->auth_context_flags = ibuf;
279
280 /* Get remote_seq_number */
281 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
282 auth_context->remote_seq_number = ibuf;
283
284 /* Get local_seq_number */
285 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
286 auth_context->local_seq_number = ibuf;
287
288 /* Get req_cksumtype */
289 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
290 auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
291
292 /* Get safe_cksumtype */
293 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
294 auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
295
296 /* Get length of cstate */
297 (void) krb5_ser_unpack_int32(&cstate_len, &bp, &remain);
298
299 if (cstate_len) {
300 kret = alloc_data(&auth_context->cstate, cstate_len);
301 if (!kret) {
302 kret = krb5_ser_unpack_bytes((krb5_octet *)
303 auth_context->cstate.data,
304 cstate_len, &bp, &remain);
305 }
306 }
307 else
308 kret = 0;
309
310 /* Peek at next token */
311 tag = 0;
312 if (!kret)
313 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
314
315 /* This is the remote_addr */
316 if (!kret && (tag == TOKEN_RADDR)) {
317 if (!(kret = k5_internalize_address(&auth_context->remote_addr,
318 &bp, &remain)))
319 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
320 }
321
322 /* This is the remote_port */
323 if (!kret && (tag == TOKEN_RPORT)) {
324 if (!(kret = k5_internalize_address(&auth_context->remote_port,
325 &bp, &remain)))
326 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
327 }
328
329 /* This is the local_addr */
330 if (!kret && (tag == TOKEN_LADDR)) {
331 if (!(kret = k5_internalize_address(&auth_context->local_addr,
332 &bp, &remain)))
333 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
334 }
335
336 /* This is the local_port */
337 if (!kret && (tag == TOKEN_LPORT)) {
338 if (!(kret = k5_internalize_address(&auth_context->local_port,
339 &bp, &remain)))
340 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
341 }
342
343 /* This is the keyblock */
344 if (!kret && (tag == TOKEN_KEYBLOCK)) {
345 if (!(kret = intern_key(&auth_context->key, &bp, &remain)))
346 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
347 }
348
349 /* This is the send_subkey */
350 if (!kret && (tag == TOKEN_LSKBLOCK)) {
351 if (!(kret = intern_key(&auth_context->send_subkey,
352 &bp, &remain)))
353 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
354 }
355
356 /* This is the recv_subkey */
357 if (!kret) {
358 if (tag == TOKEN_RSKBLOCK) {
359 kret = intern_key(&auth_context->recv_subkey,
360 &bp, &remain);
361 }
362 else {
363 /*
364 * We read the next tag, but it's not of any use here, so
365 * we effectively 'unget' it here.
366 */
367 bp -= sizeof(krb5_int32);
368 remain += sizeof(krb5_int32);
369 }
370 }
371
372 /* Now find the authentp */
373 if (!kret) {
374 kret = k5_internalize_authenticator(&auth_context->authentp,
375 &bp, &remain);
376 if (kret == EINVAL)
377 kret = 0;
378 }
379
380 /* Finally, find the trailer */
381 if (!kret) {
382 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
383 if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
384 kret = EINVAL;
385 }
386 if (!kret) {
387 *buffer = bp;
388 *lenremain = remain;
389 auth_context->magic = KV5M_AUTH_CONTEXT;
390 *argp = auth_context;
391 }
392 else
393 krb5_auth_con_free(NULL, auth_context);
394 }
395 }
396 return(kret);
397 }
398