xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/ser_sctx.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/ser_sctx.c - [De]serialization of security context */
3 /*
4  * Copyright 1995, 2004, 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 "gssapiP_krb5.h"
29 
30 /*
31  * This module contains routines to [de]serialize
32  *      krb5_gss_enc_desc and krb5_gss_ctx_id_t.
33  * XXX This whole serialization abstraction is unnecessary in a
34  * non-messaging environment, which krb5 is.  Someday, this should
35  * all get redone without the extra level of indirection. I've done
36  * some of this work here, since adding new serializers is an internal
37  * krb5 interface, and I won't use those.  There is some more
38  * deobfuscation (no longer anonymizing pointers, mostly) which could
39  * still be done. --marc
40  */
41 
42 static krb5_error_code
kg_oid_externalize(gss_OID oid,krb5_octet ** buffer,size_t * lenremain)43 kg_oid_externalize(gss_OID oid, krb5_octet **buffer, size_t *lenremain)
44 {
45     krb5_error_code err;
46 
47     err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
48     if (err)
49         return err;
50     err = krb5_ser_pack_int32((krb5_int32) oid->length,
51                               buffer, lenremain);
52     if (err)
53         return err;
54     err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
55                               oid->length, buffer, lenremain);
56     if (err)
57         return err;
58     err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
59     return err;
60 }
61 
62 static krb5_error_code
kg_oid_internalize(gss_OID * argp,krb5_octet ** buffer,size_t * lenremain)63 kg_oid_internalize(gss_OID *argp, krb5_octet **buffer, size_t *lenremain)
64 {
65     gss_OID oid;
66     krb5_int32 ibuf;
67     krb5_octet         *bp;
68     size_t             remain;
69 
70     bp = *buffer;
71     remain = *lenremain;
72 
73     /* Read in and check our magic number */
74     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
75         return (EINVAL);
76 
77     if (ibuf != KV5M_GSS_OID)
78         return (EINVAL);
79 
80     oid = (gss_OID) malloc(sizeof(gss_OID_desc));
81     if (oid == NULL)
82         return ENOMEM;
83     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
84         free(oid);
85         return EINVAL;
86     }
87     oid->length = ibuf;
88     oid->elements = malloc((size_t)ibuf);
89     if (oid->elements == 0) {
90         free(oid);
91         return ENOMEM;
92     }
93     if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
94                               oid->length, &bp, &remain)) {
95         free(oid->elements);
96         free(oid);
97         return EINVAL;
98     }
99 
100     /* Read in and check our trailing magic number */
101     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
102         free(oid->elements);
103         free(oid);
104         return (EINVAL);
105     }
106 
107     if (ibuf != KV5M_GSS_OID) {
108         free(oid->elements);
109         free(oid);
110         return (EINVAL);
111     }
112 
113     *buffer = bp;
114     *lenremain = remain;
115     *argp = oid;
116     return 0;
117 }
118 
119 static krb5_error_code
kg_oid_size(gss_OID oid,size_t * sizep)120 kg_oid_size(gss_OID oid, size_t *sizep)
121 {
122     krb5_error_code kret;
123     size_t required;
124 
125     kret = EINVAL;
126     if (oid != NULL) {
127         required = 2*sizeof(krb5_int32); /* For the header and trailer */
128         required += sizeof(krb5_int32);
129         required += oid->length;
130 
131         kret = 0;
132 
133         *sizep += required;
134     }
135 
136     return(kret);
137 }
138 
139 static krb5_error_code
kg_seqstate_externalize(g_seqnum_state arg,krb5_octet ** buffer,size_t * lenremain)140 kg_seqstate_externalize(g_seqnum_state arg, krb5_octet **buffer,
141                         size_t *lenremain)
142 {
143     krb5_error_code err;
144     err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
145     if (err == 0)
146         err = g_seqstate_externalize(arg, buffer, lenremain);
147     if (err == 0)
148         err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
149     return err;
150 }
151 
152 static krb5_error_code
kg_seqstate_internalize(g_seqnum_state * argp,krb5_octet ** buffer,size_t * lenremain)153 kg_seqstate_internalize(g_seqnum_state *argp, krb5_octet **buffer,
154                         size_t *lenremain)
155 {
156     krb5_int32 ibuf;
157     krb5_octet         *bp;
158     size_t             remain;
159     krb5_error_code    err;
160 
161     bp = *buffer;
162     remain = *lenremain;
163 
164     /* Read in and check our magic number */
165     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
166         return (EINVAL);
167 
168     if (ibuf != KV5M_GSS_QUEUE)
169         return (EINVAL);
170 
171     err = g_seqstate_internalize(argp, &bp, &remain);
172     if (err)
173         return err;
174 
175     /* Read in and check our trailing magic number */
176     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
177         g_seqstate_free(*argp);
178         return (EINVAL);
179     }
180 
181     if (ibuf != KV5M_GSS_QUEUE) {
182         g_seqstate_free(*argp);
183         return (EINVAL);
184     }
185 
186     *buffer = bp;
187     *lenremain = remain;
188     return 0;
189 }
190 
191 static krb5_error_code
kg_seqstate_size(g_seqnum_state arg,size_t * sizep)192 kg_seqstate_size(g_seqnum_state arg, size_t *sizep)
193 {
194     krb5_error_code kret;
195     size_t required;
196 
197     kret = EINVAL;
198     if (arg) {
199         required = 2*sizeof(krb5_int32); /* For the header and trailer */
200         g_seqstate_size(arg, &required);
201 
202         kret = 0;
203         *sizep += required;
204     }
205     return(kret);
206 }
207 
208 /*
209  * Determine the size required for this krb5_gss_ctx_id_rec.
210  */
211 krb5_error_code
kg_ctx_size(krb5_context kcontext,krb5_gss_ctx_id_t ctx,size_t * sizep)212 kg_ctx_size(krb5_context kcontext, krb5_gss_ctx_id_t ctx, size_t *sizep)
213 {
214     krb5_error_code     kret;
215     size_t              required;
216 
217     /*
218      * krb5_gss_ctx_id_rec requires:
219      *  krb5_int32      for KG_CONTEXT
220      *  krb5_int32      for initiate.
221      *  krb5_int32      for established.
222      *  krb5_int32      for have_acceptor_subkey.
223      *  krb5_int32      for seed_init.
224      *  krb5_int32      for gss_flags.
225      *  sizeof(seed)    for seed
226      *  ...             for here
227      *  ...             for there
228      *  ...             for subkey
229      *  krb5_int32      for signalg.
230      *  krb5_int32      for cksum_size.
231      *  krb5_int32      for sealalg.
232      *  ...             for enc
233      *  ...             for seq
234      *  krb5_int32      for authtime.
235      *  krb5_int32      for starttime.
236      *  krb5_int32      for endtime.
237      *  krb5_int32      for renew_till.
238      *  krb5_int32      for flags.
239      *  int64_t         for seq_send.
240      *  int64_t         for seq_recv.
241      *  ...             for seqstate
242      *  ...             for auth_context
243      *  ...             for mech_used
244      *  krb5_int32      for proto
245      *  krb5_int32      for cksumtype
246      *  ...             for acceptor_subkey
247      *  krb5_int32      for acceptor_key_cksumtype
248      *  krb5_int32      for cred_rcache
249      *  krb5_int32      for number of elements in authdata array
250      *  ...             for authdata array
251      *  krb5_int32      for trailer.
252      */
253     kret = EINVAL;
254     if (ctx != NULL) {
255         required = 21*sizeof(krb5_int32);
256         required += 2*sizeof(int64_t);
257         required += sizeof(ctx->seed);
258 
259         kret = 0;
260         if (!kret && ctx->here)
261             kret = k5_size_principal(ctx->here->princ, &required);
262 
263         if (!kret && ctx->there)
264             kret = k5_size_principal(ctx->there->princ, &required);
265 
266         if (!kret && ctx->subkey)
267             kret = k5_size_keyblock(&ctx->subkey->keyblock, &required);
268 
269         if (!kret && ctx->enc)
270             kret = k5_size_keyblock(&ctx->enc->keyblock, &required);
271 
272         if (!kret && ctx->seq)
273             kret = k5_size_keyblock(&ctx->seq->keyblock, &required);
274 
275         if (!kret)
276             kret = kg_oid_size(ctx->mech_used, &required);
277 
278         if (!kret && ctx->seqstate)
279             kret = kg_seqstate_size(ctx->seqstate, &required);
280 
281         if (!kret)
282             kret = k5_size_context(ctx->k5_context, &required);
283         if (!kret)
284             kret = k5_size_auth_context(ctx->auth_context, &required);
285         if (!kret && ctx->acceptor_subkey)
286             kret = k5_size_keyblock(&ctx->acceptor_subkey->keyblock,
287                                     &required);
288         if (!kret && ctx->authdata) {
289             krb5_int32 i;
290 
291             for (i = 0; !kret && ctx->authdata[i]; i++)
292                 kret = k5_size_authdata(ctx->authdata[i], &required);
293         }
294         if (!kret) {
295             krb5_gss_name_t initiator_name;
296 
297             initiator_name = ctx->initiate ? ctx->here : ctx->there;
298 
299             if (initiator_name && initiator_name->ad_context) {
300                 kret = k5_size_authdata_context(kcontext,
301                                                 initiator_name->ad_context,
302                                                 &required);
303             }
304         }
305         *sizep += required;
306     }
307     return(kret);
308 }
309 
310 /*
311  * Externalize this krb5_gss_ctx_id_ret.
312  */
313 krb5_error_code
kg_ctx_externalize(krb5_context kcontext,krb5_gss_ctx_id_t ctx,krb5_octet ** buffer,size_t * lenremain)314 kg_ctx_externalize(krb5_context kcontext, krb5_gss_ctx_id_t ctx,
315                    krb5_octet **buffer, size_t *lenremain)
316 {
317     krb5_error_code     kret;
318     size_t              required;
319     krb5_octet          *bp;
320     size_t              remain;
321     krb5int_access kaccess;
322 
323     kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
324     if (kret)
325         return(kret);
326 
327     required = 0;
328     bp = *buffer;
329     remain = *lenremain;
330     kret = EINVAL;
331     if (ctx != NULL) {
332         kret = ENOMEM;
333         if (!kg_ctx_size(kcontext, ctx, &required) &&
334             (required <= remain)) {
335             /* Our identifier */
336             (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
337 
338             /* Now static data */
339             (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
340                                        &bp, &remain);
341             (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
342                                        &bp, &remain);
343             (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
344                                        &bp, &remain);
345             (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
346                                        &bp, &remain);
347             (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
348                                        &bp, &remain);
349             (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
350                                        sizeof(ctx->seed),
351                                        &bp, &remain);
352             (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
353                                        &bp, &remain);
354             (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
355                                        &bp, &remain);
356             (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
357                                        &bp, &remain);
358             (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.authtime,
359                                        &bp, &remain);
360             (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.starttime,
361                                        &bp, &remain);
362             (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.endtime,
363                                        &bp, &remain);
364             (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.renew_till,
365                                        &bp, &remain);
366             (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
367                                        &bp, &remain);
368             (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_send,
369                                              &bp, &remain);
370             (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_recv,
371                                              &bp, &remain);
372 
373             /* Now dynamic data */
374             kret = 0;
375 
376             if (!kret && ctx->mech_used)
377                 kret = kg_oid_externalize(ctx->mech_used, &bp, &remain);
378 
379             if (!kret && ctx->here)
380                 kret = k5_externalize_principal(ctx->here->princ,
381                                                 &bp, &remain);
382 
383             if (!kret && ctx->there)
384                 kret = k5_externalize_principal(ctx->there->princ,
385                                                 &bp, &remain);
386 
387             if (!kret && ctx->subkey)
388                 kret = k5_externalize_keyblock(&ctx->subkey->keyblock,
389                                                &bp, &remain);
390 
391             if (!kret && ctx->enc)
392                 kret = k5_externalize_keyblock(&ctx->enc->keyblock,
393                                                &bp, &remain);
394 
395             if (!kret && ctx->seq)
396                 kret = k5_externalize_keyblock(&ctx->seq->keyblock,
397                                                &bp, &remain);
398 
399             if (!kret && ctx->seqstate)
400                 kret = kg_seqstate_externalize(ctx->seqstate, &bp, &remain);
401 
402             if (!kret)
403                 kret = k5_externalize_context(ctx->k5_context, &bp, &remain);
404 
405             if (!kret)
406                 kret = k5_externalize_auth_context(ctx->auth_context,
407                                                    &bp, &remain);
408 
409             if (!kret)
410                 kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
411                                            &bp, &remain);
412             if (!kret)
413                 kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
414                                            &bp, &remain);
415             if (!kret && ctx->acceptor_subkey)
416                 kret = k5_externalize_keyblock(&ctx->acceptor_subkey->keyblock,
417                                                &bp, &remain);
418             if (!kret)
419                 kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
420                                            &bp, &remain);
421 
422             if (!kret)
423                 kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
424                                            &bp, &remain);
425             if (!kret) {
426                 krb5_int32 i = 0;
427 
428                 if (ctx->authdata) {
429                     for (; ctx->authdata[i]; i++)
430                         ;
431                 }
432                 /* authdata count */
433                 kret = krb5_ser_pack_int32(i, &bp, &remain);
434                 if (!kret && ctx->authdata) {
435                     /* authdata */
436                     for (i = 0; !kret && ctx->authdata[i]; i++)
437                         kret = k5_externalize_authdata(ctx->authdata[i],
438                                                        &bp, &remain);
439                 }
440             }
441             /* authdata context */
442             if (!kret) {
443                 krb5_gss_name_t initiator_name;
444 
445                 initiator_name = ctx->initiate ? ctx->here : ctx->there;
446 
447                 if (initiator_name && initiator_name->ad_context) {
448                     kret = k5_externalize_authdata_context(kcontext,
449                                                            initiator_name->
450                                                            ad_context,
451                                                            &bp, &remain);
452                 }
453             }
454             /* trailer */
455             if (!kret)
456                 kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
457             if (!kret) {
458                 *buffer = bp;
459                 *lenremain = remain;
460             }
461         }
462     }
463     return(kret);
464 }
465 
466 /* Internalize a keyblock and convert it to a key. */
467 static krb5_error_code
intern_key(krb5_key * key,krb5_octet ** bp,size_t * sp)468 intern_key(krb5_key *key, krb5_octet **bp, size_t *sp)
469 {
470     krb5_keyblock *keyblock;
471     krb5_error_code ret;
472 
473     ret = k5_internalize_keyblock(&keyblock, bp, sp);
474     if (ret != 0)
475         return ret;
476     ret = krb5_k_create_key(NULL, keyblock, key);
477     krb5_free_keyblock(NULL, keyblock);
478     return ret;
479 }
480 
481 /*
482  * Internalize this krb5_gss_ctx_id_t.
483  */
484 krb5_error_code
kg_ctx_internalize(krb5_context kcontext,krb5_gss_ctx_id_t * argp,krb5_octet ** buffer,size_t * lenremain)485 kg_ctx_internalize(krb5_context kcontext, krb5_gss_ctx_id_t *argp,
486                    krb5_octet **buffer, size_t *lenremain)
487 {
488     krb5_error_code     kret;
489     krb5_gss_ctx_id_rec *ctx;
490     krb5_int32          ibuf;
491     krb5_octet          *bp;
492     size_t              remain;
493     krb5int_access kaccess;
494     krb5_principal        princ;
495 
496     kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
497     if (kret)
498         return(kret);
499 
500     bp = *buffer;
501     remain = *lenremain;
502     kret = EINVAL;
503     princ = NULL;
504     /* Read our magic number */
505     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
506         ibuf = 0;
507     if (ibuf == KG_CONTEXT) {
508         kret = ENOMEM;
509 
510         /* Get a context */
511         if ((remain >= (17*sizeof(krb5_int32)
512                         + 2*sizeof(int64_t)
513                         + sizeof(ctx->seed))) &&
514             (ctx = (krb5_gss_ctx_id_rec *)
515              xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
516             memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
517 
518             ctx->magic = ibuf;
519 
520             /* Get static data */
521             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
522             ctx->initiate = (int) ibuf;
523             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
524             ctx->established = (int) ibuf;
525             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
526             ctx->have_acceptor_subkey = (int) ibuf;
527             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
528             ctx->seed_init = (int) ibuf;
529             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
530             ctx->gss_flags = (int) ibuf;
531             (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
532                                          sizeof(ctx->seed),
533                                          &bp, &remain);
534             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
535             ctx->signalg = (int) ibuf;
536             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
537             ctx->cksum_size = (int) ibuf;
538             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
539             ctx->sealalg = (int) ibuf;
540             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
541             ctx->krb_times.authtime = (krb5_timestamp) ibuf;
542             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
543             ctx->krb_times.starttime = (krb5_timestamp) ibuf;
544             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
545             ctx->krb_times.endtime = (krb5_timestamp) ibuf;
546             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
547             ctx->krb_times.renew_till = (krb5_timestamp) ibuf;
548             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
549             ctx->krb_flags = (krb5_flags) ibuf;
550             (void) (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_send,
551                                                &bp, &remain);
552             kret = (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_recv,
553                                                &bp, &remain);
554             if (kret) {
555                 free(ctx);
556                 return kret;
557             }
558 
559             {
560                 gss_OID tmp;
561                 kret = kg_oid_internalize(&tmp, &bp, &remain);
562                 if (kret == 0)
563                     ctx->mech_used = tmp;
564                 else if (kret == EINVAL)
565                     kret = 0;
566             }
567             /* Now get substructure data */
568             kret = k5_internalize_principal(&princ, &bp, &remain);
569             if (kret == 0) {
570                 kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
571                                     KG_INIT_NAME_NO_COPY, &ctx->here);
572                 if (kret)
573                     krb5_free_principal(kcontext, princ);
574             } else if (kret == EINVAL)
575                 kret = 0;
576             if (!kret) {
577                 kret = k5_internalize_principal(&princ, &bp, &remain);
578                 if (kret == 0) {
579                     kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
580                                         KG_INIT_NAME_NO_COPY, &ctx->there);
581                     if (kret)
582                         krb5_free_principal(kcontext, princ);
583                 } else if (kret == EINVAL)
584                     kret = 0;
585             }
586             if (!kret &&
587                 (kret = intern_key(&ctx->subkey, &bp, &remain))) {
588                 if (kret == EINVAL)
589                     kret = 0;
590             }
591             if (!kret &&
592                 (kret = intern_key(&ctx->enc, &bp, &remain))) {
593                 if (kret == EINVAL)
594                     kret = 0;
595             }
596             if (!kret &&
597                 (kret = intern_key(&ctx->seq, &bp, &remain))) {
598                 if (kret == EINVAL)
599                     kret = 0;
600             }
601 
602             if (!kret) {
603                 kret = kg_seqstate_internalize(&ctx->seqstate, &bp, &remain);
604                 if (kret == EINVAL)
605                     kret = 0;
606             }
607 
608             if (!kret)
609                 kret = k5_internalize_context(&ctx->k5_context, &bp, &remain);
610 
611             if (!kret)
612                 kret = k5_internalize_auth_context(&ctx->auth_context,
613                                                    &bp, &remain);
614 
615             if (!kret)
616                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
617             ctx->proto = ibuf;
618             if (!kret)
619                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
620             ctx->cksumtype = ibuf;
621             if (!kret &&
622                 (kret = intern_key(&ctx->acceptor_subkey, &bp, &remain))) {
623                 if (kret == EINVAL)
624                     kret = 0;
625             }
626             if (!kret)
627                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
628             ctx->acceptor_subkey_cksumtype = ibuf;
629             if (!kret)
630                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
631             ctx->cred_rcache = ibuf;
632             /* authdata */
633             if (!kret)
634                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
635             if (!kret) {
636                 krb5_int32 nadata = ibuf, i;
637 
638                 if (nadata > 0) {
639                     ctx->authdata = (krb5_authdata **)calloc((size_t)nadata + 1,
640                                                              sizeof(krb5_authdata *));
641                     if (ctx->authdata == NULL) {
642                         kret = ENOMEM;
643                     } else {
644                         for (i = 0; !kret && i < nadata; i++)
645                             kret = k5_internalize_authdata(&ctx->authdata[i],
646                                                            &bp, &remain);
647                     }
648                 }
649             }
650             /* authdata context */
651             if (!kret) {
652                 krb5_gss_name_t initiator_name;
653 
654                 initiator_name = ctx->initiate ? ctx->here : ctx->there;
655                 if (initiator_name == NULL) {
656                     kret = EINVAL;
657                 } else {
658                     kret = k5_internalize_authdata_context(kcontext,
659                                                            &initiator_name->
660                                                            ad_context,
661                                                            &bp, &remain);
662                     if (kret == EINVAL)
663                         kret = 0;
664                 }
665             }
666             /* Get trailer */
667             if (!kret)
668                 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
669             if (!kret && ibuf != KG_CONTEXT)
670                 kret = EINVAL;
671 
672             if (!kret) {
673                 *buffer = bp;
674                 *lenremain = remain;
675                 *argp = ctx;
676             } else {
677                 if (ctx->seq)
678                     krb5_k_free_key(kcontext, ctx->seq);
679                 if (ctx->enc)
680                     krb5_k_free_key(kcontext, ctx->enc);
681                 if (ctx->subkey)
682                     krb5_k_free_key(kcontext, ctx->subkey);
683                 if (ctx->there)
684                     kg_release_name(kcontext, &ctx->there);
685                 if (ctx->here)
686                     kg_release_name(kcontext, &ctx->here);
687                 xfree(ctx);
688             }
689         }
690     }
691     return(kret);
692 }
693