use correct free
[mech_eap.orig] / import_sec_context.c
1 /*
2  * Copyright (c) 2010, 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 #include "gssapiP_eap.h"
34
35 static OM_uint32
36 gssEapImportPartialContext(OM_uint32 *minor,
37                            unsigned char **pBuf,
38                            size_t *pRemain,
39                            gss_ctx_id_t ctx)
40 {
41     OM_uint32 major;
42     unsigned char *p = *pBuf;
43     size_t remain = *pRemain;
44     gss_buffer_desc buf;
45
46     /* XXX we also need to deserialise the current server name */
47
48     if (remain < 4) {
49         *minor = ERANGE;
50         return GSS_S_DEFECTIVE_TOKEN;
51     }
52     buf.length = load_uint32_be(p);
53
54     if (remain < buf.length) {
55         *minor = ERANGE;
56         return GSS_S_DEFECTIVE_TOKEN;
57
58     }
59     buf.value = &p[4];
60
61     major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
62     if (GSS_ERROR(major))
63         return major;
64
65     *pBuf += 4 + buf.length;
66     *pRemain -= 4 + buf.length;
67
68     return GSS_S_COMPLETE;
69 }
70
71 static OM_uint32
72 importMechanismOid(OM_uint32 *minor,
73                    unsigned char **pBuf,
74                    size_t *pRemain,
75                    gss_OID *pOid)
76 {
77     OM_uint32 major;
78     unsigned char *p = *pBuf;
79     size_t remain = *pRemain;
80     gss_OID_desc oidBuf;
81
82     oidBuf.length = load_uint32_be(p);
83     if (remain < 4 + oidBuf.length || oidBuf.length == 0) {
84         *minor = ERANGE;
85         return GSS_S_DEFECTIVE_TOKEN;
86     }
87
88     oidBuf.elements = &p[4];
89
90     if (!gssEapIsConcreteMechanismOid(&oidBuf)) {
91         return GSS_S_BAD_MECH;
92     }
93
94     if (!gssEapInternalizeOid(&oidBuf, pOid)) {
95         major = duplicateOid(minor, &oidBuf, pOid);
96         if (GSS_ERROR(major))
97             return major;
98     }
99
100     *pBuf    += 4 + oidBuf.length;
101     *pRemain -= 4 + oidBuf.length;
102
103     *minor = 0;
104     return GSS_S_COMPLETE;
105 }
106
107 static OM_uint32
108 importKerberosKey(OM_uint32 *minor,
109                   unsigned char **pBuf,
110                   size_t *pRemain,
111                   krb5_cksumtype *checksumType,
112                   krb5_enctype *pEncryptionType,
113                   krb5_keyblock *key)
114 {
115     unsigned char *p = *pBuf;
116     size_t remain = *pRemain;
117     OM_uint32 encryptionType;
118     OM_uint32 length;
119     gss_buffer_desc tmp;
120
121     if (remain < 12) {
122         *minor = ERANGE;
123         return GSS_S_DEFECTIVE_TOKEN;
124     }
125
126     *checksumType  = load_uint32_be(&p[0]);
127     encryptionType = load_uint32_be(&p[4]);
128     length         = load_uint32_be(&p[8]);
129
130     if ((length != 0) != (encryptionType != ENCTYPE_NULL)) {
131         *minor = ERANGE;
132         return GSS_S_DEFECTIVE_TOKEN;
133     }
134
135     if (remain - 12 < length) {
136         *minor = ERANGE;
137         return GSS_S_DEFECTIVE_TOKEN;
138     }
139
140     if (load_buffer(&p[12], length, &tmp) == NULL) {
141         *minor = ENOMEM;
142         return GSS_S_FAILURE;
143     }
144
145     KRB_KEY_TYPE(key)   = encryptionType;
146     KRB_KEY_LENGTH(key) = tmp.length;
147     KRB_KEY_DATA(key)   = (unsigned char *)tmp.value;
148
149     *pBuf    += 12 + length;
150     *pRemain -= 12 + length;
151     *pEncryptionType = encryptionType;
152
153     *minor = 0;
154     return GSS_S_COMPLETE;
155 }
156
157 static OM_uint32
158 importName(OM_uint32 *minor,
159            unsigned char **pBuf,
160            size_t *pRemain,
161            gss_name_t *pName)
162 {
163     OM_uint32 major;
164     unsigned char *p = *pBuf;
165     size_t remain = *pRemain;
166     gss_buffer_desc tmp;
167
168     if (remain < 4) {
169         *minor = ERANGE;
170         return GSS_S_DEFECTIVE_TOKEN;
171     }
172
173     tmp.length = load_uint32_be(p);
174     if (tmp.length != 0) {
175         if (remain - 4 < tmp.length) {
176             *minor = ERANGE;
177             return GSS_S_DEFECTIVE_TOKEN;
178         }
179
180         tmp.value = p + 4;
181
182         major = gssEapImportNameInternal(minor, &tmp, pName,
183                                          EXPORT_NAME_FLAG_COMPOSITE);
184         if (GSS_ERROR(major))
185             return major;
186     }
187
188     *pBuf    += 4 + tmp.length;
189     *pRemain -= 4 + tmp.length;
190
191     *minor = 0;
192     return GSS_S_COMPLETE;
193 }
194
195 static OM_uint32
196 gssEapImportContext(OM_uint32 *minor,
197                     gss_buffer_t token,
198                     gss_ctx_id_t ctx)
199 {
200     OM_uint32 major;
201     unsigned char *p = (unsigned char *)token->value;
202     size_t remain = token->length;
203
204     if (remain < 16) {
205         *minor = ERANGE;
206         return GSS_S_DEFECTIVE_TOKEN;
207     }
208     if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) {
209         *minor = EINVAL;
210         return GSS_S_DEFECTIVE_TOKEN;
211     }
212     ctx->state      = load_uint32_be(&p[4]);
213     ctx->flags      = load_uint32_be(&p[8]);
214     ctx->gssFlags   = load_uint32_be(&p[12]);
215     p      += 16;
216     remain -= 16;
217
218     /* Validate state */
219     if (ctx->state < EAP_STATE_IDENTITY ||
220         ctx->state > EAP_STATE_ESTABLISHED)
221         return GSS_S_DEFECTIVE_TOKEN;
222
223     /* Only acceptor can export partial context tokens */
224     if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
225         return GSS_S_DEFECTIVE_TOKEN;
226
227     major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed);
228     if (GSS_ERROR(major))
229         return major;
230
231     major = importKerberosKey(minor, &p, &remain,
232                               &ctx->checksumType,
233                               &ctx->encryptionType,
234                               &ctx->rfc3961Key);
235     if (GSS_ERROR(major))
236         return major;
237
238     major = importName(minor, &p, &remain, &ctx->initiatorName);
239     if (GSS_ERROR(major))
240         return major;
241
242     major = importName(minor, &p, &remain, &ctx->acceptorName);
243     if (GSS_ERROR(major))
244         return major;
245
246     /* Check that, if context is established, names are valid */
247     if (CTX_IS_ESTABLISHED(ctx) &&
248         (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME
249                                : ctx->initiatorName == GSS_C_NO_NAME)) {
250         return GSS_S_DEFECTIVE_TOKEN;
251     }
252
253     if (remain < 24 + sequenceSize(ctx->seqState)) {
254         *minor = ERANGE;
255         return GSS_S_DEFECTIVE_TOKEN;
256     }
257     ctx->expiryTime = (time_t)load_uint64_be(&p[0]); /* XXX */
258     ctx->sendSeq    = load_uint64_be(&p[8]);
259     ctx->recvSeq    = load_uint64_be(&p[16]);
260     p      += 24;
261     remain -= 24;
262
263     major = sequenceInternalize(minor, &ctx->seqState, &p, &remain);
264     if (GSS_ERROR(major))
265         return major;
266
267     /*
268      * The partial context should only be expected for unestablished
269      * acceptor contexts.
270      */
271     if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) {
272         major = gssEapImportPartialContext(minor, &p, &remain, ctx);
273         if (GSS_ERROR(major))
274             return major;
275     }
276
277 #ifdef GSSEAP_DEBUG
278     assert(remain == 0);
279 #endif
280
281     *minor = 0;
282     major = GSS_S_COMPLETE;
283
284     return major;
285 }
286
287 OM_uint32
288 gss_import_sec_context(OM_uint32 *minor,
289                        gss_buffer_t interprocess_token,
290                        gss_ctx_id_t *context_handle)
291 {
292     OM_uint32 major, tmpMinor;
293     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
294
295     *context_handle = GSS_C_NO_CONTEXT;
296
297     if (interprocess_token == GSS_C_NO_BUFFER ||
298         interprocess_token->length == 0)
299         return GSS_S_DEFECTIVE_TOKEN;
300
301     major = gssEapAllocContext(minor, &ctx);
302     if (GSS_ERROR(major))
303         goto cleanup;
304
305     major = gssEapImportContext(minor, interprocess_token, ctx);
306     if (GSS_ERROR(major))
307         goto cleanup;
308
309     *context_handle = ctx;
310
311 cleanup:
312     if (GSS_ERROR(major))
313         gssEapReleaseContext(&tmpMinor, &ctx);
314
315     return major;
316 }