Fixes for Heimdal (macOS) builds from Stefan.
[mech_eap.git] / mech_eap / util_lucid.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  * "Lucid" security context export routine (called by MIT Kerberos mechanism).
35  */
36
37 #include "gssapiP_eap.h"
38
39 OM_uint32
40 gssEapExportLucidSecContext(OM_uint32 *minor,
41                             gss_const_ctx_id_t ctx,
42                             const gss_OID desiredObject GSSEAP_UNUSED,
43                             gss_buffer_set_t *data_set)
44 {
45     OM_uint32 major = GSS_S_COMPLETE;
46     int haveAcceptorSubkey =
47         ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0);
48     gss_buffer_desc rep;
49 #ifdef HAVE_HEIMDAL_VERSION
50     krb5_error_code code;
51     krb5_storage *sp;
52     krb5_data data = { 0 };
53
54     sp = krb5_storage_emem();
55     if (sp == NULL) {
56         code = ENOMEM;
57         goto cleanup;
58     }
59
60     code = krb5_store_int32(sp, 1);     /* version */
61     if (code != 0)
62         goto cleanup;
63
64     code = krb5_store_int32(sp, CTX_IS_INITIATOR(ctx));
65     if (code != 0)
66         goto cleanup;
67
68     code = krb5_store_int32(sp, ctx->expiryTime); 
69     if (code != 0)
70         goto cleanup;
71
72     code = krb5_store_int32(sp, 0);
73     if (code != 0)
74         goto cleanup;
75
76     code = krb5_store_int32(sp, ctx->sendSeq);
77     if (code != 0)
78         goto cleanup;
79
80     code = krb5_store_int32(sp, 0);
81     if (code != 0)
82         goto cleanup;
83
84     code = krb5_store_int32(sp, ctx->recvSeq);
85     if (code != 0)
86         goto cleanup;
87
88     code = krb5_store_int32(sp, 1);     /* is_cfx */
89     if (code != 0)
90         goto cleanup;
91
92     code = krb5_store_int32(sp, haveAcceptorSubkey);
93     if (code != 0)
94         goto cleanup;
95
96     code = krb5_store_keyblock(sp, ctx->rfc3961Key);
97     if (code != 0)
98         goto cleanup;
99
100     if (haveAcceptorSubkey) {
101         code = krb5_store_keyblock(sp, ctx->rfc3961Key);
102         if (code != 0)
103             goto cleanup;
104     }
105
106     code = krb5_storage_to_data(sp, &data);
107     if (code != 0)
108         goto cleanup;
109
110     rep.length = data.length;
111     rep.value = data.data;
112
113     major = gss_add_buffer_set_member(minor, &rep, data_set);
114     if (GSS_ERROR(major))
115         goto cleanup;
116
117 cleanup:
118     krb5_data_free(&data);
119
120     if (major == GSS_S_COMPLETE) {
121         *minor = code;
122         major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
123     }
124
125     return major;
126 #else
127     gss_krb5_lucid_context_v1_t *lctx;
128     gss_krb5_lucid_key_t *lkey = NULL;
129
130     lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx));
131     if (lctx == NULL) {
132         major = GSS_S_FAILURE;
133         *minor = ENOMEM;
134         goto cleanup;
135     }
136
137     lctx->version = 1;
138     lctx->initiate = CTX_IS_INITIATOR(ctx);
139     if (ctx->expiryTime == 0)
140         lctx->endtime = KRB_TIME_FOREVER;
141     else
142         lctx->endtime = ctx->expiryTime;
143     lctx->send_seq = ctx->sendSeq;
144     lctx->recv_seq = ctx->recvSeq;
145     lctx->protocol = 1;
146
147     lctx->cfx_kd.have_acceptor_subkey = haveAcceptorSubkey;
148
149     lkey = haveAcceptorSubkey
150            ? &lctx->cfx_kd.acceptor_subkey
151            : &lctx->cfx_kd.ctx_key;
152
153     lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key);
154     lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key));
155     if (lkey->data == NULL) {
156         major = GSS_S_FAILURE;
157         *minor = ENOMEM;
158         goto cleanup;
159     }
160     lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
161     memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length);
162
163     rep.value = &lctx;
164     rep.length = sizeof(void *);
165
166     major = gss_add_buffer_set_member(minor, &rep, data_set);
167     if (GSS_ERROR(major))
168         goto cleanup;
169
170 cleanup:
171     if (GSS_ERROR(major)) {
172         if (lctx != NULL) {
173             if (lkey != NULL && lkey->data != NULL) {
174                 memset(lkey->data, 0, lkey->length);
175                 GSSEAP_FREE(lkey->data);
176             }
177             GSSEAP_FREE(lctx);
178         }
179     }
180
181     return major;
182 #endif /* HAVE_HEIMDAL_VERSION */
183 }