Fixes for Heimdal (macOS) builds from Stefan.
[mech_eap.git] / mech_eap / util_krb.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Kerberos 5 helpers.
35  */
36
37 #include "gssapiP_eap.h"
38
39 void
40 gssEapDestroyKrbContext(krb5_context context)
41 {
42     if (context != NULL)
43         krb5_free_context(context);
44 }
45
46 static krb5_error_code
47 initKrbContext(krb5_context *pKrbContext)
48 {
49     krb5_context krbContext;
50     krb5_error_code code;
51     char *defaultRealm = NULL;
52
53     *pKrbContext = NULL;
54
55     code = krb5_init_context(&krbContext);
56     if (code != 0)
57         goto cleanup;
58
59     krb5_appdefault_string(krbContext, "eap_gss",
60                            NULL, "default_realm", "", &defaultRealm);
61
62     if (defaultRealm != NULL && defaultRealm[0] != '\0') {
63         code = krb5_set_default_realm(krbContext, defaultRealm);
64         if (code != 0)
65             goto cleanup;
66     }
67
68     *pKrbContext = krbContext;
69
70 cleanup:
71 #ifdef HAVE_HEIMDAL_VERSION
72     krb5_xfree(defaultRealm);
73 #else
74     krb5_free_default_realm(krbContext, defaultRealm);
75 #endif
76
77     if (code != 0 && krbContext != NULL)
78         krb5_free_context(krbContext);
79
80     return code;
81 }
82
83 OM_uint32
84 gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
85 {
86     struct gss_eap_thread_local_data *tld;
87
88     *minor = 0;
89     *context = NULL;
90
91     tld = gssEapGetThreadLocalData();
92     if (tld != NULL) {
93         if (tld->krbContext == NULL) {
94             *minor = initKrbContext(&tld->krbContext);
95             if (*minor != 0)
96                 tld->krbContext = NULL;
97         }
98         *context = tld->krbContext;
99     } else {
100         *minor = GSSEAP_GET_LAST_ERROR();
101     }
102
103     GSSEAP_ASSERT(*context != NULL || *minor != 0);
104
105     return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
106 }
107
108 /*
109  * Derive a key K for RFC 4121 use by using the following
110  * derivation function (based on RFC 4402);
111  *
112  * KMSK = random-to-key(MSK)
113  * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
114  * L = output key size
115  * K = truncate(L, T1 || T2 || .. || Tn)
116  *
117  * The output must be freed by krb5_free_keyblock_contents(),
118  * not GSSEAP_FREE().
119  */
120 OM_uint32
121 gssEapDeriveRfc3961Key(OM_uint32 *minor,
122                        const unsigned char *inputKey,
123                        size_t inputKeyLength,
124                        krb5_enctype encryptionType,
125                        krb5_keyblock *pKey)
126 {
127     krb5_context krbContext;
128 #ifdef HAVE_HEIMDAL_VERSION
129     krb5_crypto krbCrypto = NULL;
130 #else
131     krb5_data data;
132 #endif
133     krb5_data ns, t, derivedKeyData;
134     krb5_keyblock kd;
135     krb5_error_code code;
136     size_t randomLength, keyLength, prfLength;
137     unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
138     ssize_t i, remain;
139
140     GSSEAP_KRB_INIT(&krbContext);
141     GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL);
142
143     KRB_KEY_INIT(pKey);
144     KRB_KEY_INIT(&kd);
145     KRB_KEY_TYPE(&kd) = encryptionType;
146
147     KRB_DATA_INIT(&ns);
148     KRB_DATA_INIT(&t);
149     KRB_DATA_INIT(&derivedKeyData);
150
151 #ifdef HAVE_HEIMDAL_VERSION
152     code = krb5_enctype_keybits(krbContext, encryptionType, &randomLength);
153     if (code != 0)
154         goto cleanup;
155
156     randomLength = (randomLength + 7) / 8; /* from mit_glue.c */
157
158     code = krb5_enctype_keysize(krbContext, encryptionType, &keyLength);
159     if (code != 0)
160         goto cleanup;
161 #else
162     code = krb5_c_keylengths(krbContext, encryptionType,
163                              &randomLength, &keyLength);
164     if (code != 0)
165         goto cleanup;
166 #endif /* HAVE_HEIMDAL_VERSION */
167
168     /* Convert EAP MSK into a Kerberos key */
169
170 #ifdef HAVE_HEIMDAL_VERSION
171     code = krb5_random_to_key(krbContext, encryptionType, inputKey,
172                               MIN(inputKeyLength, randomLength), &kd);
173 #else
174     data.length = MIN(inputKeyLength, randomLength);
175     data.data = (char *)inputKey;
176
177     KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength);
178     if (KRB_KEY_DATA(&kd) == NULL) {
179         code = ENOMEM;
180         goto cleanup;
181     }
182     KRB_KEY_LENGTH(&kd) = keyLength;
183
184     code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
185 #endif /* HAVE_HEIMDAL_VERSION */
186     if (code != 0)
187         goto cleanup;
188
189     memset(&constant[0], 0, 4);
190     memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
191
192     ns.length = sizeof(constant);
193     ns.data = (char *)constant;
194
195     /* Plug derivation constant and key into PRF */
196 #ifdef HAVE_HEIMDAL_VERSION
197     code = krb5_crypto_prf_length(krbContext, encryptionType, &prfLength);
198 #else
199     code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
200 #endif
201     if (code != 0)
202         goto cleanup;
203
204 #ifdef HAVE_HEIMDAL_VERSION
205     code = krb5_crypto_init(krbContext, &kd, 0, &krbCrypto);
206     if (code != 0)
207         goto cleanup;
208 #else
209     t.length = prfLength;
210     t.data = GSSEAP_MALLOC(t.length);
211     if (t.data == NULL) {
212         code = ENOMEM;
213         goto cleanup;
214     }
215 #endif
216
217     derivedKeyData.length = randomLength;
218     derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length);
219     if (derivedKeyData.data == NULL) {
220         code = ENOMEM;
221         goto cleanup;
222     }
223
224     for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength;
225          remain > 0;
226          p += t.length, remain -= t.length, i++)
227     {
228         store_uint32_be(i, ns.data);
229
230 #ifdef HAVE_HEIMDAL_VERSION
231         code = krb5_crypto_prf(krbContext, krbCrypto, &ns, &t);
232 #else
233         code = krb5_c_prf(krbContext, &kd, &ns, &t);
234 #endif
235         if (code != 0)
236             goto cleanup;
237
238         memcpy(p, t.data, MIN(t.length, remain));
239      }
240
241     /* Finally, convert PRF output into a new key which we will return */
242 #ifdef HAVE_HEIMDAL_VERSION
243     krb5_free_keyblock_contents(krbContext, &kd);
244     KRB_KEY_INIT(&kd);
245
246     code = krb5_random_to_key(krbContext, encryptionType,
247                               derivedKeyData.data, derivedKeyData.length, &kd);
248 #else
249     code = krb5_c_random_to_key(krbContext, encryptionType,
250                                 &derivedKeyData, &kd);
251 #endif
252     if (code != 0)
253         goto cleanup;
254
255     *pKey = kd;
256
257 cleanup:
258     if (code != 0)
259         krb5_free_keyblock_contents(krbContext, &kd);
260 #ifdef HAVE_HEIMDAL_VERSION
261     krb5_crypto_destroy(krbContext, krbCrypto);
262     krb5_data_free(&t);
263 #else
264     if (t.data != NULL) {
265         memset(t.data, 0, t.length);
266         GSSEAP_FREE(t.data);
267     }
268 #endif
269     if (derivedKeyData.data != NULL) {
270         memset(derivedKeyData.data, 0, derivedKeyData.length);
271         GSSEAP_FREE(derivedKeyData.data);
272     }
273
274     *minor = code;
275
276     return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
277 }
278
279 #ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
280 extern krb5_error_code
281 krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
282 #endif
283
284 OM_uint32
285 rfc3961ChecksumTypeForKey(OM_uint32 *minor,
286                           krb5_keyblock *key,
287                           krb5_cksumtype *cksumtype)
288 {
289     krb5_context krbContext;
290 #if !defined(HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE) && !defined(HAVE_HEIMDAL_VERSION)
291     krb5_data data;
292     krb5_checksum cksum;
293 #endif
294 #ifdef HAVE_HEIMDAL_VERSION
295     krb5_crypto krbCrypto = NULL;
296 #endif
297
298     GSSEAP_KRB_INIT(&krbContext);
299
300 #ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
301     *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
302                                            cksumtype);
303     if (*minor != 0)
304         return GSS_S_FAILURE;
305 #elif defined(HAVE_HEIMDAL_VERSION)
306     *minor = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
307     if (*minor != 0)
308         return GSS_S_FAILURE;
309
310     *minor = krb5_crypto_get_checksum_type(krbContext, krbCrypto, cksumtype);
311
312     krb5_crypto_destroy(krbContext, krbCrypto);
313
314     if (*minor != 0)
315         return GSS_S_FAILURE;
316 #else
317     KRB_DATA_INIT(&data);
318
319     memset(&cksum, 0, sizeof(cksum));
320
321     /*
322      * This is a complete hack but it's the only way to work with
323      * MIT Kerberos pre-1.9 without using private API, as it does
324      * not support passing in zero as the checksum type.
325      */
326     *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
327     if (*minor != 0)
328         return GSS_S_FAILURE;
329
330     *cksumtype = KRB_CHECKSUM_TYPE(&cksum);
331
332     KRB_CHECKSUM_FREE(krbContext, &cksum);
333 #endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
334
335 #ifdef HAVE_HEIMDAL_VERSION
336     if (!krb5_checksum_is_keyed(krbContext, *cksumtype))
337 #else
338     if (!krb5_c_is_keyed_cksum(*cksumtype))
339 #endif
340     {
341         *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
342         return GSS_S_FAILURE;
343     }
344
345     return GSS_S_COMPLETE;
346 }
347
348 krb5_error_code
349 krbCryptoLength(krb5_context krbContext,
350 #ifdef HAVE_HEIMDAL_VERSION
351                 krb5_crypto krbCrypto,
352 #else
353                 const krb5_keyblock *key,
354 #endif
355                 int type,
356                 size_t *length)
357 {
358 #ifdef HAVE_HEIMDAL_VERSION
359     return krb5_crypto_length(krbContext, krbCrypto, type, length);
360 #else
361     unsigned int len;
362     krb5_error_code code;
363
364     code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len);
365     if (code == 0)
366         *length = (size_t)len;
367
368     return code;
369 #endif
370 }
371
372 krb5_error_code
373 krbPaddingLength(krb5_context krbContext,
374 #ifdef HAVE_HEIMDAL_VERSION
375                  krb5_crypto krbCrypto,
376 #else
377                  const krb5_keyblock *key,
378 #endif
379                  size_t dataLength,
380                  size_t *padLength)
381 {
382     krb5_error_code code;
383 #ifdef HAVE_HEIMDAL_VERSION
384     size_t headerLength, paddingLength;
385
386     code = krbCryptoLength(krbContext, krbCrypto,
387                            KRB5_CRYPTO_TYPE_HEADER, &headerLength);
388     if (code != 0)
389         return code;
390
391     dataLength += headerLength;
392
393     code = krb5_crypto_length(krbContext, krbCrypto,
394                               KRB5_CRYPTO_TYPE_PADDING, &paddingLength);
395     if (code != 0)
396         return code;
397
398     if (paddingLength != 0 && (dataLength % paddingLength) != 0)
399         *padLength = paddingLength - (dataLength % paddingLength);
400     else
401         *padLength = 0;
402
403     return 0;
404 #else
405     unsigned int pad;
406
407     code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad);
408     if (code == 0)
409         *padLength = (size_t)pad;
410
411     return code;
412 #endif /* HAVE_HEIMDAL_VERSION */
413 }
414
415 krb5_error_code
416 krbBlockSize(krb5_context krbContext,
417 #ifdef HAVE_HEIMDAL_VERSION
418                  krb5_crypto krbCrypto,
419 #else
420                  const krb5_keyblock *key,
421 #endif
422                  size_t *blockSize)
423 {
424 #ifdef HAVE_HEIMDAL_VERSION
425     return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize);
426 #else
427     return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize);
428 #endif
429 }
430
431 krb5_error_code
432 krbEnctypeToString(
433 #ifdef HAVE_HEIMDAL_VERSION
434                    krb5_context krbContext,
435 #else
436                    krb5_context krbContext GSSEAP_UNUSED,
437 #endif
438                    krb5_enctype enctype,
439                    const char *prefix,
440                    gss_buffer_t string)
441 {
442     krb5_error_code code;
443 #ifdef HAVE_HEIMDAL_VERSION
444     char *enctypeBuf = NULL;
445 #else
446     char enctypeBuf[128];
447 #endif
448     size_t prefixLength, enctypeLength;
449
450 #ifdef HAVE_HEIMDAL_VERSION
451     code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf);
452 #else
453     code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf));
454 #endif
455     if (code != 0)
456         return code;
457
458     prefixLength = (prefix != NULL) ? strlen(prefix) : 0;
459     enctypeLength = strlen(enctypeBuf);
460
461     string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1);
462     if (string->value == NULL) {
463 #ifdef HAVE_HEIMDAL_VERSION
464         krb5_xfree(enctypeBuf);
465 #endif
466         return ENOMEM;
467     }
468
469     if (prefixLength != 0)
470         memcpy(string->value, prefix, prefixLength);
471     memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength);
472
473     string->length = prefixLength + enctypeLength;
474     ((char *)string->value)[string->length] = '\0';
475
476 #ifdef HAVE_HEIMDAL_VERSION
477     krb5_xfree(enctypeBuf);
478 #endif
479
480     return 0;
481 }
482
483 #ifdef GSSEAP_ENABLE_REAUTH
484 krb5_error_code
485 krbMakeAuthDataKdcIssued(krb5_context context,
486                          const krb5_keyblock *key,
487                          krb5_const_principal issuer,
488 #ifdef HAVE_HEIMDAL_VERSION
489                          const AuthorizationData *authdata,
490                          AuthorizationData *adKdcIssued
491 #else
492                          krb5_authdata *const *authdata,
493                          krb5_authdata ***adKdcIssued
494 #endif
495                          )
496 {
497 #ifdef HAVE_HEIMDAL_VERSION
498     krb5_error_code code;
499     AD_KDCIssued kdcIssued;
500     AuthorizationDataElement adDatum;
501     unsigned char *buf;
502     size_t buf_size, len;
503     krb5_crypto crypto = NULL;
504
505     memset(&kdcIssued, 0, sizeof(kdcIssued));
506     memset(adKdcIssued, 0, sizeof(*adKdcIssued));
507
508     kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL;
509     kdcIssued.i_sname = (PrincipalName *)&issuer->name;
510     kdcIssued.elements = *authdata;
511
512     ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code);
513     if (code != 0)
514         goto cleanup;
515
516     code = krb5_crypto_init(context, key, 0, &crypto);
517     if (code != 0)
518         goto cleanup;
519
520     code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED,
521                                 0, buf, buf_size, &kdcIssued.ad_checksum);
522     if (code != 0)
523         goto cleanup;
524
525     free(buf); /* match ASN1_MALLOC_ENCODE */
526     buf = NULL;
527
528     ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
529     if (code != 0)
530         goto cleanup;
531
532     adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED;
533     adDatum.ad_data.length = buf_size;
534     adDatum.ad_data.data = buf;
535
536     code = add_AuthorizationData(adKdcIssued, &adDatum);
537     if (code != 0)
538         goto cleanup;
539
540 cleanup:
541     if (buf != NULL)
542         free(buf); /* match ASN1_MALLOC_ENCODE */
543     if (crypto != NULL)
544         krb5_crypto_destroy(context, crypto);
545     free_Checksum(&kdcIssued.ad_checksum);
546
547     return code;
548 #else
549     return krb5_make_authdata_kdc_issued(context, key, issuer, authdata,
550                                          adKdcIssued);
551 #endif /* HAVE_HEIMDAL_VERSION */
552 }
553
554 krb5_error_code
555 krbMakeCred(krb5_context krbContext,
556             krb5_auth_context authContext,
557             krb5_creds *creds,
558             krb5_data *data)
559 {
560     krb5_error_code code;
561 #ifdef HAVE_HEIMDAL_VERSION
562     KRB_CRED krbCred;
563     KrbCredInfo krbCredInfo;
564     EncKrbCredPart encKrbCredPart;
565     krb5_keyblock *key;
566     krb5_crypto krbCrypto = NULL;
567     krb5_data encKrbCredPartData;
568     krb5_replay_data rdata;
569     size_t len;
570 #else
571     krb5_data *d = NULL;
572 #endif
573
574     memset(data, 0, sizeof(*data));
575 #ifdef HAVE_HEIMDAL_VERSION
576     memset(&krbCred,        0, sizeof(krbCred));
577     memset(&krbCredInfo,    0, sizeof(krbCredInfo));
578     memset(&encKrbCredPart, 0, sizeof(encKrbCredPart));
579     memset(&rdata,          0, sizeof(rdata));
580
581     if (authContext->local_subkey)
582         key = authContext->local_subkey;
583     else if (authContext->remote_subkey)
584         key = authContext->remote_subkey;
585     else
586         key = authContext->keyblock;
587
588     krbCred.pvno = 5;
589     krbCred.msg_type = krb_cred;
590     krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket));
591     if (krbCred.tickets.val == NULL) {
592         code = ENOMEM;
593         goto cleanup;
594     }
595     krbCred.tickets.len = 1;
596
597     code = decode_Ticket(creds->ticket.data,
598                          creds->ticket.length,
599                          krbCred.tickets.val, &len);
600     if (code != 0)
601         goto cleanup;
602
603     krbCredInfo.key         = creds->session;
604     krbCredInfo.prealm      = &creds->client->realm;
605     krbCredInfo.pname       = &creds->client->name;
606     krbCredInfo.flags       = &creds->flags.b;
607     krbCredInfo.authtime    = &creds->times.authtime;
608     krbCredInfo.starttime   = &creds->times.starttime;
609     krbCredInfo.endtime     = &creds->times.endtime;
610     krbCredInfo.renew_till  = &creds->times.renew_till;
611     krbCredInfo.srealm      = &creds->server->realm;
612     krbCredInfo.sname       = &creds->server->name;
613     krbCredInfo.caddr       = creds->addresses.len ? &creds->addresses : NULL;
614
615     encKrbCredPart.ticket_info.len = 1;
616     encKrbCredPart.ticket_info.val = &krbCredInfo;
617     if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
618         rdata.seq                  = authContext->local_seqnumber;
619         encKrbCredPart.nonce       = (int32_t *)&rdata.seq;
620     } else {
621         encKrbCredPart.nonce       = NULL;
622     }
623     if (authContext->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
624         krb5_us_timeofday(krbContext, &rdata.timestamp, &rdata.usec);
625         encKrbCredPart.timestamp   = &rdata.timestamp;
626         encKrbCredPart.usec        = &rdata.usec;
627     } else {
628         encKrbCredPart.timestamp   = NULL;
629         encKrbCredPart.usec        = NULL;
630     }
631     encKrbCredPart.s_address       = authContext->local_address;
632     encKrbCredPart.r_address       = authContext->remote_address;
633
634     ASN1_MALLOC_ENCODE(EncKrbCredPart, encKrbCredPartData.data,
635                        encKrbCredPartData.length, &encKrbCredPart,
636                        &len, code);
637     if (code != 0)
638         goto cleanup;
639
640     code = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
641     if (code != 0)
642         goto cleanup;
643
644     code = krb5_encrypt_EncryptedData(krbContext,
645                                       krbCrypto,
646                                       KRB5_KU_KRB_CRED,
647                                       encKrbCredPartData.data,
648                                       encKrbCredPartData.length,
649                                       0,
650                                       &krbCred.enc_part);
651     if (code != 0)
652         goto cleanup;
653
654     ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length,
655                        &krbCred, &len, code);
656     if (code != 0)
657         goto cleanup;
658
659     if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
660         authContext->local_seqnumber++;
661
662 cleanup:
663     if (krbCrypto != NULL)
664         krb5_crypto_destroy(krbContext, krbCrypto);
665     free_KRB_CRED(&krbCred);
666     krb5_data_free(&encKrbCredPartData);
667
668     return code;
669 #else
670     code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL);
671     if (code == 0) {
672         *data = *d;
673         GSSEAP_FREE(d);
674     }
675
676     return code;
677 #endif /* HAVE_HEIMDAL_VERSION */
678 }
679 #endif /* GSSEAP_ENABLE_REAUTH */