xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/ser_actx.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * Copyright 2004 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  * lib/krb5/krb/ser_actx.c
9  *
10  * Copyright 1995 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 
34 /*
35  * ser_actx.c - Serialize krb5_auth_context structure.
36  */
37 #include <k5-int.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 krb5_error_code krb5_ser_authdata_init (krb5_context);
65 krb5_error_code krb5_ser_address_init (krb5_context);
66 krb5_error_code krb5_ser_authenticator_init (krb5_context);
67 krb5_error_code krb5_ser_checksum_init (krb5_context);
68 krb5_error_code krb5_ser_keyblock_init (krb5_context);
69 krb5_error_code krb5_ser_principal_init (krb5_context);
70 
71 /* Local data */
72 static const krb5_ser_entry krb5_auth_context_ser_entry = {
73     KV5M_AUTH_CONTEXT,			/* Type			*/
74     krb5_auth_context_size,		/* Sizer routine	*/
75     krb5_auth_context_externalize,	/* Externalize routine	*/
76     krb5_auth_context_internalize	/* Internalize routine	*/
77 };
78 
79 /*
80  * krb5_auth_context_size()	- Determine the size required to externalize
81  *				  the krb5_auth_context.
82  */
83 static krb5_error_code
84 krb5_auth_context_size(
85     krb5_context	kcontext,
86     krb5_pointer	arg,
87     size_t		*sizep)
88 {
89     krb5_error_code	kret;
90     krb5_auth_context	auth_context;
91     size_t		required;
92 
93     /*
94      * krb5_auth_context requires at minimum:
95      *	krb5_int32		for KV5M_AUTH_CONTEXT
96      *	krb5_int32		for auth_context_flags
97      *	krb5_int32		for remote_seq_number
98      *	krb5_int32		for local_seq_number
99      *	krb5_int32		for req_cksumtype
100      *	krb5_int32		for safe_cksumtype
101      *	krb5_int32		for size of i_vector
102      *	krb5_int32		for KV5M_AUTH_CONTEXT
103      */
104     kret = EINVAL;
105     auth_context = (krb5_auth_context) arg;
106     if (auth_context) {
107 	kret = 0;
108 
109 	/* Calculate size required by i_vector - ptooey */
110 	if (auth_context->i_vector && auth_context->keyblock) {
111 	    kret = krb5_c_block_size(kcontext, auth_context->keyblock->enctype,
112 				     &required);
113 	} else {
114 	    required = 0;
115 	}
116 
117 	required += sizeof(krb5_int32)*8;
118 
119 	/* Calculate size required by remote_addr, if appropriate */
120 	if (!kret && auth_context->remote_addr) {
121 	    kret = krb5_size_opaque(kcontext,
122 				    KV5M_ADDRESS,
123 				    (krb5_pointer) auth_context->remote_addr,
124 				    &required);
125 	    if (!kret)
126 		required += sizeof(krb5_int32);
127 	}
128 
129 	/* Calculate size required by remote_port, if appropriate */
130 	if (!kret && auth_context->remote_port) {
131 	    kret = krb5_size_opaque(kcontext,
132 				    KV5M_ADDRESS,
133 				    (krb5_pointer) auth_context->remote_port,
134 				    &required);
135 	    if (!kret)
136 		required += sizeof(krb5_int32);
137 	}
138 
139 	/* Calculate size required by local_addr, if appropriate */
140 	if (!kret && auth_context->local_addr) {
141 	    kret = krb5_size_opaque(kcontext,
142 				    KV5M_ADDRESS,
143 				    (krb5_pointer) auth_context->local_addr,
144 				    &required);
145 	    if (!kret)
146 		required += sizeof(krb5_int32);
147 	}
148 
149 	/* Calculate size required by local_port, if appropriate */
150 	if (!kret && auth_context->local_port) {
151 	    kret = krb5_size_opaque(kcontext,
152 				    KV5M_ADDRESS,
153 				    (krb5_pointer) auth_context->local_port,
154 				    &required);
155 	    if (!kret)
156 		required += sizeof(krb5_int32);
157 	}
158 
159 	/* Calculate size required by keyblock, if appropriate */
160 	if (!kret && auth_context->keyblock) {
161 	    kret = krb5_size_opaque(kcontext,
162 				    KV5M_KEYBLOCK,
163 				    (krb5_pointer) auth_context->keyblock,
164 				    &required);
165 	    if (!kret)
166 		required += sizeof(krb5_int32);
167 	}
168 
169 	/* Calculate size required by send_subkey, if appropriate */
170 	if (!kret && auth_context->send_subkey) {
171 	    kret = krb5_size_opaque(kcontext,
172 				    KV5M_KEYBLOCK,
173 				    (krb5_pointer) auth_context->send_subkey,
174 				    &required);
175 	    if (!kret)
176 		required += sizeof(krb5_int32);
177 	}
178 
179 	/* Calculate size required by recv_subkey, if appropriate */
180 	if (!kret && auth_context->recv_subkey) {
181 	    kret = krb5_size_opaque(kcontext,
182 				    KV5M_KEYBLOCK,
183 				    (krb5_pointer) auth_context->recv_subkey,
184 				    &required);
185 	    if (!kret)
186 		required += sizeof(krb5_int32);
187 	}
188 
189 	/* Calculate size required by authentp, if appropriate */
190 	if (!kret && auth_context->authentp)
191 	    kret = krb5_size_opaque(kcontext,
192 				    KV5M_AUTHENTICATOR,
193 				    (krb5_pointer) auth_context->authentp,
194 				    &required);
195 
196     }
197     if (!kret)
198 	*sizep += required;
199     return(kret);
200 }
201 
202 /*
203  * krb5_auth_context_externalize()	- Externalize the krb5_auth_context.
204  */
205 static krb5_error_code
206 krb5_auth_context_externalize(
207     krb5_context	kcontext,
208     krb5_pointer	arg,
209     krb5_octet		**buffer,
210     size_t		*lenremain)
211 {
212     krb5_error_code	kret;
213     krb5_auth_context	auth_context;
214     size_t		required;
215     krb5_octet		*bp;
216     size_t		remain;
217     size_t		obuf;
218 
219     required = 0;
220     bp = *buffer;
221     remain = *lenremain;
222     kret = EINVAL;
223     auth_context = (krb5_auth_context) arg;
224     if (auth_context) {
225 	kret = ENOMEM;
226 	if (!krb5_auth_context_size(kcontext, arg, &required) &&
227 	    (required <= remain)) {
228 
229 	    /* Write fixed portion */
230 	    (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
231 	    (void) krb5_ser_pack_int32(auth_context->auth_context_flags,
232 				       &bp, &remain);
233 	    (void) krb5_ser_pack_int32(auth_context->remote_seq_number,
234 				       &bp, &remain);
235 	    (void) krb5_ser_pack_int32(auth_context->local_seq_number,
236 				       &bp, &remain);
237 	    (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype,
238 				       &bp, &remain);
239 	    (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
240 				       &bp, &remain);
241 
242 	    kret = 0;
243 
244 	    /* Now figure out the number of bytes for i_vector and write it */
245 	    if (auth_context->i_vector) {
246 		kret = krb5_c_block_size(kcontext,
247 					 auth_context->keyblock->enctype,
248 					 &obuf);
249 	    } else {
250 		obuf = 0;
251 	    }
252 
253 	    if (!kret)
254 		(void) krb5_ser_pack_int32(obuf, &bp, &remain);
255 
256 	    /* Now copy i_vector */
257 	    if (!kret && auth_context->i_vector)
258 		(void) krb5_ser_pack_bytes(auth_context->i_vector,
259 					   (size_t) obuf,
260 					   &bp, &remain);
261 
262 	    /* Now handle remote_addr, if appropriate */
263 	    if (!kret && auth_context->remote_addr) {
264 		(void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain);
265 		kret = krb5_externalize_opaque(kcontext,
266 					       KV5M_ADDRESS,
267 					       (krb5_pointer)
268 					       auth_context->remote_addr,
269 					       &bp,
270 					       &remain);
271 	    }
272 
273 	    /* Now handle remote_port, if appropriate */
274 	    if (!kret && auth_context->remote_port) {
275 		(void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain);
276 		kret = krb5_externalize_opaque(kcontext,
277 					       KV5M_ADDRESS,
278 					       (krb5_pointer)
279 					       auth_context->remote_addr,
280 					       &bp,
281 					       &remain);
282 	    }
283 
284 	    /* Now handle local_addr, if appropriate */
285 	    if (!kret && auth_context->local_addr) {
286 		(void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain);
287 		kret = krb5_externalize_opaque(kcontext,
288 					       KV5M_ADDRESS,
289 					       (krb5_pointer)
290 					       auth_context->local_addr,
291 					       &bp,
292 					       &remain);
293 	    }
294 
295 	    /* Now handle local_port, if appropriate */
296 	    if (!kret && auth_context->local_port) {
297 		(void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain);
298 		kret = krb5_externalize_opaque(kcontext,
299 					       KV5M_ADDRESS,
300 					       (krb5_pointer)
301 					       auth_context->local_addr,
302 					       &bp,
303 					       &remain);
304 	    }
305 
306 	    /* Now handle keyblock, if appropriate */
307 	    if (!kret && auth_context->keyblock) {
308 		(void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain);
309 		kret = krb5_externalize_opaque(kcontext,
310 					       KV5M_KEYBLOCK,
311 					       (krb5_pointer)
312 					       auth_context->keyblock,
313 					       &bp,
314 					       &remain);
315 	    }
316 
317 	    /* Now handle subkey, if appropriate */
318 	    if (!kret && auth_context->send_subkey) {
319 		(void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain);
320 		kret = krb5_externalize_opaque(kcontext,
321 					       KV5M_KEYBLOCK,
322 					       (krb5_pointer)
323 					       auth_context->send_subkey,
324 					       &bp,
325 					       &remain);
326 	    }
327 
328 	    /* Now handle subkey, if appropriate */
329 	    if (!kret && auth_context->recv_subkey) {
330 		(void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain);
331 		kret = krb5_externalize_opaque(kcontext,
332 					       KV5M_KEYBLOCK,
333 					       (krb5_pointer)
334 					       auth_context->recv_subkey,
335 					       &bp,
336 					       &remain);
337 	    }
338 
339 	    /* Now handle authentp, if appropriate */
340 	    if (!kret && auth_context->authentp)
341 		kret = krb5_externalize_opaque(kcontext,
342 					       KV5M_AUTHENTICATOR,
343 					       (krb5_pointer)
344 					       auth_context->authentp,
345 					       &bp,
346 					       &remain);
347 
348 	    /*
349 	     * If we were successful, write trailer then update the pointer and
350 	     * remaining length;
351 	     */
352 	    if (!kret) {
353 		/* Write our trailer */
354 		(void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
355 		*buffer = bp;
356 		*lenremain = remain;
357 	    }
358 	}
359     }
360     return(kret);
361 }
362 
363 /*
364  * krb5_auth_context_internalize()	- Internalize the krb5_auth_context.
365  */
366 static krb5_error_code
367 krb5_auth_context_internalize(
368     krb5_context	kcontext,
369     krb5_pointer	*argp,
370     krb5_octet		**buffer,
371     size_t		*lenremain)
372 {
373     krb5_error_code	kret;
374     krb5_auth_context	auth_context;
375     krb5_int32		ibuf;
376     krb5_octet		*bp;
377     size_t		remain;
378     krb5_int32		ivlen;
379     krb5_int32		tag;
380 
381     bp = *buffer;
382     remain = *lenremain;
383     kret = EINVAL;
384     /* Read our magic number */
385     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
386 	ibuf = 0;
387     if (ibuf == KV5M_AUTH_CONTEXT) {
388 	kret = ENOMEM;
389 
390 	/* Get memory for the auth_context */
391 	if ((remain >= (5*sizeof(krb5_int32))) &&
392 	    (auth_context = (krb5_auth_context)
393 	     MALLOC(sizeof(struct _krb5_auth_context)))) {
394 	    (void) memset(auth_context, 0, sizeof(struct _krb5_auth_context));
395 
396 	    /* Get auth_context_flags */
397 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
398 	    auth_context->auth_context_flags = ibuf;
399 
400 	    /* Get remote_seq_number */
401 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
402 	    auth_context->remote_seq_number = ibuf;
403 
404 	    /* Get local_seq_number */
405 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
406 	    auth_context->local_seq_number = ibuf;
407 
408 	    /* Get req_cksumtype */
409 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
410 	    auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
411 
412 	    /* Get safe_cksumtype */
413 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
414 	    auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
415 
416 	    /* Get length of i_vector */
417 	    (void) krb5_ser_unpack_int32(&ivlen, &bp, &remain);
418 
419 	    if (ivlen) {
420 		if ((auth_context->i_vector =
421 		     (krb5_pointer) MALLOC((size_t)ivlen)))
422 		    kret = krb5_ser_unpack_bytes(auth_context->i_vector,
423 						 (size_t) ivlen,
424 						 &bp,
425 						 &remain);
426 		else
427 		    kret = ENOMEM;
428 	    }
429 	    else
430 		kret = 0;
431 
432 	    /* Peek at next token */
433 	    tag = 0;
434 	    if (!kret)
435 		kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
436 
437 	    /* This is the remote_addr */
438 	    if (!kret && (tag == TOKEN_RADDR)) {
439 		if (!(kret = krb5_internalize_opaque(kcontext,
440 						     KV5M_ADDRESS,
441 						     (krb5_pointer *)
442 						     &auth_context->
443 						     remote_addr,
444 						     &bp,
445 						     &remain)))
446 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
447 	    }
448 
449 	    /* This is the remote_port */
450 	    if (!kret && (tag == TOKEN_RPORT)) {
451 		if (!(kret = krb5_internalize_opaque(kcontext,
452 						     KV5M_ADDRESS,
453 						     (krb5_pointer *)
454 						     &auth_context->
455 						     remote_port,
456 						     &bp,
457 						     &remain)))
458 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
459 	    }
460 
461 	    /* This is the local_addr */
462 	    if (!kret && (tag == TOKEN_LADDR)) {
463 		if (!(kret = krb5_internalize_opaque(kcontext,
464 						     KV5M_ADDRESS,
465 						     (krb5_pointer *)
466 						     &auth_context->
467 						     local_addr,
468 						     &bp,
469 						     &remain)))
470 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
471 	    }
472 
473 	    /* This is the local_port */
474 	    if (!kret && (tag == TOKEN_LPORT)) {
475 		if (!(kret = krb5_internalize_opaque(kcontext,
476 						     KV5M_ADDRESS,
477 						     (krb5_pointer *)
478 						     &auth_context->
479 						     local_port,
480 						     &bp,
481 						     &remain)))
482 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
483 	    }
484 
485 	    /* This is the keyblock */
486 	    if (!kret && (tag == TOKEN_KEYBLOCK)) {
487 		if (!(kret = krb5_internalize_opaque(kcontext,
488 						     KV5M_KEYBLOCK,
489 						     (krb5_pointer *)
490 						     &auth_context->keyblock,
491 						     &bp,
492 						     &remain)))
493 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
494 	    }
495 
496 	    /* This is the send_subkey */
497 	    if (!kret && (tag == TOKEN_LSKBLOCK)) {
498 		if (!(kret = krb5_internalize_opaque(kcontext,
499 						     KV5M_KEYBLOCK,
500 						     (krb5_pointer *)
501 						     &auth_context->
502 						     send_subkey,
503 						     &bp,
504 						     &remain)))
505 		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
506 	    }
507 
508 	    /* This is the recv_subkey */
509 	    if (!kret) {
510 		if (tag == TOKEN_RSKBLOCK) {
511 		    kret = krb5_internalize_opaque(kcontext,
512 						   KV5M_KEYBLOCK,
513 						   (krb5_pointer *)
514 						   &auth_context->
515 						   recv_subkey,
516 						   &bp,
517 						   &remain);
518 		}
519 		else {
520 		    /*
521 		     * We read the next tag, but it's not of any use here, so
522 		     * we effectively 'unget' it here.
523 		     */
524 		    bp -= sizeof(krb5_int32);
525 		    remain += sizeof(krb5_int32);
526 		}
527 	    }
528 
529 	    /* Now find the authentp */
530 	    if (!kret) {
531 		if ((kret = krb5_internalize_opaque(kcontext,
532 						    KV5M_AUTHENTICATOR,
533 						    (krb5_pointer *)
534 						    &auth_context->authentp,
535 						    &bp,
536 						    &remain))) {
537 		    if (kret == EINVAL)
538 			kret = 0;
539 		}
540 	    }
541 
542 	    /* Finally, find the trailer */
543 	    if (!kret) {
544 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
545 		if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
546 		    kret = EINVAL;
547 	    }
548 	    if (!kret) {
549 		*buffer = bp;
550 		*lenremain = remain;
551 		auth_context->magic = KV5M_AUTH_CONTEXT;
552 		*argp = (krb5_pointer) auth_context;
553 	    }
554 /* We don't import the auth_context into the kernel */
555 #ifndef _KERNEL
556 	    else
557 		krb5_auth_con_free(kcontext, auth_context);
558 #endif
559 	}
560     }
561     return(kret);
562 }
563 
564 /*
565  * Register the auth_context serializer.
566  */
567 krb5_error_code KRB5_CALLCONV
568 krb5_ser_auth_context_init(krb5_context	kcontext)
569 {
570     krb5_error_code	kret;
571     kret = krb5_register_serializer(kcontext, &krb5_auth_context_ser_entry);
572     if (!kret)
573 	kret = krb5_ser_authdata_init(kcontext);
574     if (!kret)
575 	kret = krb5_ser_address_init(kcontext);
576     if (!kret)
577 	kret = krb5_ser_authenticator_init(kcontext);
578     if (!kret)
579 	kret = krb5_ser_checksum_init(kcontext);
580     if (!kret)
581 	kret = krb5_ser_keyblock_init(kcontext);
582     if (!kret)
583 	kret = krb5_ser_principal_init(kcontext);
584     return(kret);
585 }
586