xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/ser_actx.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
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
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
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
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
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