1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * lib/krb5/krb/ser_actx.c
8 *
9 * Copyright 1995 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
11 *
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
30 *
31 */
32
33 /*
34 * ser_actx.c - Serialize krb5_auth_context structure.
35 */
36 #include "k5-int.h"
37 #include "int-proto.h"
38 #include "auth_con.h"
39
40 #define TOKEN_RADDR 950916
41 #define TOKEN_RPORT 950917
42 #define TOKEN_LADDR 950918
43 #define TOKEN_LPORT 950919
44 #define TOKEN_KEYBLOCK 950920
45 #define TOKEN_LSKBLOCK 950921
46 #define TOKEN_RSKBLOCK 950922
47
48 /*
49 * Routines to deal with externalizing the krb5_auth_context:
50 * krb5_auth_context_size();
51 * krb5_auth_context_externalize();
52 * krb5_auth_context_internalize();
53 */
54 static krb5_error_code krb5_auth_context_size
55 (krb5_context, krb5_pointer, size_t *);
56 static krb5_error_code krb5_auth_context_externalize
57 (krb5_context, krb5_pointer, krb5_octet **, size_t *);
58 static krb5_error_code krb5_auth_context_internalize
59 (krb5_context,krb5_pointer *, krb5_octet **, size_t *);
60
61 /*
62 * Other metadata serialization initializers.
63 */
64
65 /* Local data */
66 static const krb5_ser_entry krb5_auth_context_ser_entry = {
67 KV5M_AUTH_CONTEXT, /* Type */
68 krb5_auth_context_size, /* Sizer routine */
69 krb5_auth_context_externalize, /* Externalize routine */
70 krb5_auth_context_internalize /* Internalize routine */
71 };
72
73 /*
74 * krb5_auth_context_size() - Determine the size required to externalize
75 * the krb5_auth_context.
76 */
77 static krb5_error_code
krb5_auth_context_size(krb5_context kcontext,krb5_pointer arg,size_t * sizep)78 krb5_auth_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
79 {
80 krb5_error_code kret;
81 krb5_auth_context auth_context;
82 size_t required;
83
84 /*
85 * krb5_auth_context requires at minimum:
86 * krb5_int32 for KV5M_AUTH_CONTEXT
87 * krb5_int32 for auth_context_flags
88 * krb5_int32 for remote_seq_number
89 * krb5_int32 for local_seq_number
90 * krb5_int32 for req_cksumtype
91 * krb5_int32 for safe_cksumtype
92 * krb5_int32 for size of i_vector
93 * krb5_int32 for KV5M_AUTH_CONTEXT
94 */
95 kret = EINVAL;
96 /* Solaris Kerberos */
97 auth_context = (krb5_auth_context) arg;
98 if (auth_context) {
99 kret = 0;
100
101 /* Calculate size required by i_vector - ptooey */
102 if (auth_context->i_vector && auth_context->keyblock) {
103 kret = krb5_c_block_size(kcontext, auth_context->keyblock->enctype,
104 &required);
105 } else {
106 required = 0;
107 }
108
109 required += sizeof(krb5_int32)*8;
110
111 /* Calculate size required by remote_addr, if appropriate */
112 if (!kret && auth_context->remote_addr) {
113 kret = krb5_size_opaque(kcontext,
114 KV5M_ADDRESS,
115 (krb5_pointer) auth_context->remote_addr,
116 &required);
117 if (!kret)
118 required += sizeof(krb5_int32);
119 }
120
121 /* Calculate size required by remote_port, if appropriate */
122 if (!kret && auth_context->remote_port) {
123 kret = krb5_size_opaque(kcontext,
124 KV5M_ADDRESS,
125 (krb5_pointer) auth_context->remote_port,
126 &required);
127 if (!kret)
128 required += sizeof(krb5_int32);
129 }
130
131 /* Calculate size required by local_addr, if appropriate */
132 if (!kret && auth_context->local_addr) {
133 kret = krb5_size_opaque(kcontext,
134 KV5M_ADDRESS,
135 (krb5_pointer) auth_context->local_addr,
136 &required);
137 if (!kret)
138 required += sizeof(krb5_int32);
139 }
140
141 /* Calculate size required by local_port, if appropriate */
142 if (!kret && auth_context->local_port) {
143 kret = krb5_size_opaque(kcontext,
144 KV5M_ADDRESS,
145 (krb5_pointer) auth_context->local_port,
146 &required);
147 if (!kret)
148 required += sizeof(krb5_int32);
149 }
150
151 /* Calculate size required by keyblock, if appropriate */
152 if (!kret && auth_context->keyblock) {
153 kret = krb5_size_opaque(kcontext,
154 KV5M_KEYBLOCK,
155 (krb5_pointer) auth_context->keyblock,
156 &required);
157 if (!kret)
158 required += sizeof(krb5_int32);
159 }
160
161 /* Calculate size required by send_subkey, if appropriate */
162 if (!kret && auth_context->send_subkey) {
163 kret = krb5_size_opaque(kcontext,
164 KV5M_KEYBLOCK,
165 (krb5_pointer) auth_context->send_subkey,
166 &required);
167 if (!kret)
168 required += sizeof(krb5_int32);
169 }
170
171 /* Calculate size required by recv_subkey, if appropriate */
172 if (!kret && auth_context->recv_subkey) {
173 kret = krb5_size_opaque(kcontext,
174 KV5M_KEYBLOCK,
175 (krb5_pointer) auth_context->recv_subkey,
176 &required);
177 if (!kret)
178 required += sizeof(krb5_int32);
179 }
180
181 /* Calculate size required by authentp, if appropriate */
182 if (!kret && auth_context->authentp)
183 kret = krb5_size_opaque(kcontext,
184 KV5M_AUTHENTICATOR,
185 (krb5_pointer) auth_context->authentp,
186 &required);
187
188 }
189 if (!kret)
190 *sizep += required;
191 return(kret);
192 }
193
194 /*
195 * krb5_auth_context_externalize() - Externalize the krb5_auth_context.
196 */
197 static krb5_error_code
krb5_auth_context_externalize(krb5_context kcontext,krb5_pointer arg,krb5_octet ** buffer,size_t * lenremain)198 krb5_auth_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
199 {
200 krb5_error_code kret;
201 krb5_auth_context auth_context;
202 size_t required;
203 krb5_octet *bp;
204 size_t remain;
205 size_t obuf;
206 krb5_int32 obuf32;
207
208 required = 0;
209 bp = *buffer;
210 remain = *lenremain;
211 kret = EINVAL;
212 /* Solaris Kerberos */
213 auth_context = (krb5_auth_context) arg;
214 if (auth_context) {
215 kret = ENOMEM;
216 if (!krb5_auth_context_size(kcontext, arg, &required) &&
217 (required <= remain)) {
218
219 /* Write fixed portion */
220 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
221 (void) krb5_ser_pack_int32(auth_context->auth_context_flags,
222 &bp, &remain);
223 (void) krb5_ser_pack_int32(auth_context->remote_seq_number,
224 &bp, &remain);
225 (void) krb5_ser_pack_int32(auth_context->local_seq_number,
226 &bp, &remain);
227 (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype,
228 &bp, &remain);
229 (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
230 &bp, &remain);
231
232 kret = 0;
233
234 /* Now figure out the number of bytes for i_vector and write it */
235 if (auth_context->i_vector) {
236 kret = krb5_c_block_size(kcontext,
237 auth_context->keyblock->enctype,
238 &obuf);
239 } else {
240 obuf = 0;
241 }
242
243 /* Convert to signed 32 bit integer */
244 obuf32 = obuf;
245 if (kret == 0 && obuf != obuf32)
246 kret = EINVAL;
247 if (!kret)
248 (void) krb5_ser_pack_int32(obuf32, &bp, &remain);
249
250 /* Now copy i_vector */
251 if (!kret && auth_context->i_vector)
252 (void) krb5_ser_pack_bytes(auth_context->i_vector,
253 obuf,
254 &bp, &remain);
255
256 /* Now handle remote_addr, if appropriate */
257 if (!kret && auth_context->remote_addr) {
258 (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain);
259 kret = krb5_externalize_opaque(kcontext,
260 KV5M_ADDRESS,
261 (krb5_pointer)
262 auth_context->remote_addr,
263 &bp,
264 &remain);
265 }
266
267 /* Now handle remote_port, if appropriate */
268 if (!kret && auth_context->remote_port) {
269 (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain);
270 kret = krb5_externalize_opaque(kcontext,
271 KV5M_ADDRESS,
272 (krb5_pointer)
273 auth_context->remote_addr,
274 &bp,
275 &remain);
276 }
277
278 /* Now handle local_addr, if appropriate */
279 if (!kret && auth_context->local_addr) {
280 (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain);
281 kret = krb5_externalize_opaque(kcontext,
282 KV5M_ADDRESS,
283 (krb5_pointer)
284 auth_context->local_addr,
285 &bp,
286 &remain);
287 }
288
289 /* Now handle local_port, if appropriate */
290 if (!kret && auth_context->local_port) {
291 (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain);
292 kret = krb5_externalize_opaque(kcontext,
293 KV5M_ADDRESS,
294 (krb5_pointer)
295 auth_context->local_addr,
296 &bp,
297 &remain);
298 }
299
300 /* Now handle keyblock, if appropriate */
301 if (!kret && auth_context->keyblock) {
302 (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain);
303 kret = krb5_externalize_opaque(kcontext,
304 KV5M_KEYBLOCK,
305 (krb5_pointer)
306 auth_context->keyblock,
307 &bp,
308 &remain);
309 }
310
311 /* Now handle subkey, if appropriate */
312 if (!kret && auth_context->send_subkey) {
313 (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain);
314 kret = krb5_externalize_opaque(kcontext,
315 KV5M_KEYBLOCK,
316 (krb5_pointer)
317 auth_context->send_subkey,
318 &bp,
319 &remain);
320 }
321
322 /* Now handle subkey, if appropriate */
323 if (!kret && auth_context->recv_subkey) {
324 (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain);
325 kret = krb5_externalize_opaque(kcontext,
326 KV5M_KEYBLOCK,
327 (krb5_pointer)
328 auth_context->recv_subkey,
329 &bp,
330 &remain);
331 }
332
333 /* Now handle authentp, if appropriate */
334 if (!kret && auth_context->authentp)
335 kret = krb5_externalize_opaque(kcontext,
336 KV5M_AUTHENTICATOR,
337 (krb5_pointer)
338 auth_context->authentp,
339 &bp,
340 &remain);
341
342 /*
343 * If we were successful, write trailer then update the pointer and
344 * remaining length;
345 */
346 if (!kret) {
347 /* Write our trailer */
348 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
349 *buffer = bp;
350 *lenremain = remain;
351 }
352 }
353 }
354 return(kret);
355 }
356
357 /*
358 * krb5_auth_context_internalize() - Internalize the krb5_auth_context.
359 */
360 static krb5_error_code
krb5_auth_context_internalize(krb5_context kcontext,krb5_pointer * argp,krb5_octet ** buffer,size_t * lenremain)361 krb5_auth_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
362 {
363 krb5_error_code kret;
364 krb5_auth_context auth_context;
365 krb5_int32 ibuf;
366 krb5_octet *bp;
367 size_t remain;
368 krb5_int32 ivlen;
369 krb5_int32 tag;
370
371 bp = *buffer;
372 remain = *lenremain;
373 kret = EINVAL;
374 /* Read our magic number */
375 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
376 ibuf = 0;
377 if (ibuf == KV5M_AUTH_CONTEXT) {
378 kret = ENOMEM;
379
380 /* Get memory for the auth_context */
381 if ((remain >= (5*sizeof(krb5_int32))) &&
382 (auth_context = (krb5_auth_context)
383 MALLOC(sizeof(struct _krb5_auth_context)))) {
384 (void) memset(auth_context, 0, sizeof(struct _krb5_auth_context));
385
386 /* Get auth_context_flags */
387 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
388 auth_context->auth_context_flags = ibuf;
389
390 /* Get remote_seq_number */
391 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
392 auth_context->remote_seq_number = ibuf;
393
394 /* Get local_seq_number */
395 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
396 auth_context->local_seq_number = ibuf;
397
398 /* Get req_cksumtype */
399 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
400 auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
401
402 /* Get safe_cksumtype */
403 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
404 auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
405
406 /* Get length of i_vector */
407 (void) krb5_ser_unpack_int32(&ivlen, &bp, &remain);
408
409 if (ivlen) {
410 if ((auth_context->i_vector =
411 (krb5_pointer) MALLOC((size_t)ivlen)))
412 kret = krb5_ser_unpack_bytes(auth_context->i_vector,
413 (size_t) ivlen,
414 &bp,
415 &remain);
416 else
417 kret = ENOMEM;
418 }
419 else
420 kret = 0;
421
422 /* Peek at next token */
423 tag = 0;
424 if (!kret)
425 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
426
427 /* This is the remote_addr */
428 if (!kret && (tag == TOKEN_RADDR)) {
429 if (!(kret = krb5_internalize_opaque(kcontext,
430 KV5M_ADDRESS,
431 (krb5_pointer *)
432 &auth_context->
433 remote_addr,
434 &bp,
435 &remain)))
436 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
437 }
438
439 /* This is the remote_port */
440 if (!kret && (tag == TOKEN_RPORT)) {
441 if (!(kret = krb5_internalize_opaque(kcontext,
442 KV5M_ADDRESS,
443 (krb5_pointer *)
444 &auth_context->
445 remote_port,
446 &bp,
447 &remain)))
448 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
449 }
450
451 /* This is the local_addr */
452 if (!kret && (tag == TOKEN_LADDR)) {
453 if (!(kret = krb5_internalize_opaque(kcontext,
454 KV5M_ADDRESS,
455 (krb5_pointer *)
456 &auth_context->
457 local_addr,
458 &bp,
459 &remain)))
460 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
461 }
462
463 /* This is the local_port */
464 if (!kret && (tag == TOKEN_LPORT)) {
465 if (!(kret = krb5_internalize_opaque(kcontext,
466 KV5M_ADDRESS,
467 (krb5_pointer *)
468 &auth_context->
469 local_port,
470 &bp,
471 &remain)))
472 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
473 }
474
475 /* This is the keyblock */
476 if (!kret && (tag == TOKEN_KEYBLOCK)) {
477 if (!(kret = krb5_internalize_opaque(kcontext,
478 KV5M_KEYBLOCK,
479 (krb5_pointer *)
480 &auth_context->keyblock,
481 &bp,
482 &remain)))
483 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
484 }
485
486 /* This is the send_subkey */
487 if (!kret && (tag == TOKEN_LSKBLOCK)) {
488 if (!(kret = krb5_internalize_opaque(kcontext,
489 KV5M_KEYBLOCK,
490 (krb5_pointer *)
491 &auth_context->
492 send_subkey,
493 &bp,
494 &remain)))
495 kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
496 }
497
498 /* This is the recv_subkey */
499 if (!kret) {
500 if (tag == TOKEN_RSKBLOCK) {
501 kret = krb5_internalize_opaque(kcontext,
502 KV5M_KEYBLOCK,
503 (krb5_pointer *)
504 &auth_context->
505 recv_subkey,
506 &bp,
507 &remain);
508 }
509 else {
510 /*
511 * We read the next tag, but it's not of any use here, so
512 * we effectively 'unget' it here.
513 */
514 bp -= sizeof(krb5_int32);
515 remain += sizeof(krb5_int32);
516 }
517 }
518
519 /* Now find the authentp */
520 if (!kret) {
521 if ((kret = krb5_internalize_opaque(kcontext,
522 KV5M_AUTHENTICATOR,
523 (krb5_pointer *)
524 &auth_context->authentp,
525 &bp,
526 &remain))) {
527 if (kret == EINVAL)
528 kret = 0;
529 }
530 }
531
532 /* Finally, find the trailer */
533 if (!kret) {
534 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
535 if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
536 kret = EINVAL;
537 }
538 if (!kret) {
539 *buffer = bp;
540 *lenremain = remain;
541 auth_context->magic = KV5M_AUTH_CONTEXT;
542 *argp = (krb5_pointer) auth_context;
543 }
544 /* We don't import the auth_context into the kernel */
545 #ifndef _KERNEL
546 else
547 krb5_auth_con_free(kcontext, auth_context);
548 #endif
549 }
550 }
551 return(kret);
552 }
553
554 /*
555 * Register the auth_context serializer.
556 */
557 krb5_error_code KRB5_CALLCONV
krb5_ser_auth_context_init(krb5_context kcontext)558 krb5_ser_auth_context_init(krb5_context kcontext)
559 {
560 krb5_error_code kret;
561 kret = krb5_register_serializer(kcontext, &krb5_auth_context_ser_entry);
562 if (!kret)
563 kret = krb5_ser_authdata_init(kcontext);
564 if (!kret)
565 kret = krb5_ser_address_init(kcontext);
566 if (!kret)
567 kret = krb5_ser_authenticator_init(kcontext);
568 if (!kret)
569 kret = krb5_ser_checksum_init(kcontext);
570 if (!kret)
571 kret = krb5_ser_keyblock_init(kcontext);
572 if (!kret)
573 kret = krb5_ser_principal_init(kcontext);
574 return(kret);
575 }
576