2 * Copyright (c) 2011, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
34 * Utility routines for context handles.
37 #include "gssapiP_eap.h"
40 gssEapAllocContext(OM_uint32 *minor,
46 assert(*pCtx == GSS_C_NO_CONTEXT);
48 ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
54 if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
56 gssEapReleaseContext(&tmpMinor, &ctx);
60 ctx->state = GSSEAP_STATE_INITIAL;
63 * Integrity, confidentiality, sequencing and replay detection are
64 * always available. Regardless of what flags are requested in
65 * GSS_Init_sec_context, implementations MUST set the flag corresponding
66 * to these services in the output of GSS_Init_sec_context and
67 * GSS_Accept_sec_context.
69 ctx->gssFlags = GSS_C_TRANS_FLAG | /* exporting contexts */
70 GSS_C_INTEG_FLAG | /* integrity */
71 GSS_C_CONF_FLAG | /* confidentiality */
72 GSS_C_SEQUENCE_FLAG | /* sequencing */
73 GSS_C_REPLAY_FLAG; /* replay detection */
77 return GSS_S_COMPLETE;
81 releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
83 eap_peer_sm_deinit(ctx->eap);
87 releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
91 if (ctx->radConn != NULL)
92 rs_conn_destroy(ctx->radConn);
93 if (ctx->radContext != NULL)
94 rs_context_destroy(ctx->radContext);
95 if (ctx->radServer != NULL)
96 GSSEAP_FREE(ctx->radServer);
97 gss_release_buffer(&tmpMinor, &ctx->state);
99 gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
103 gssEapReleaseContext(OM_uint32 *minor,
107 gss_ctx_id_t ctx = *pCtx;
108 krb5_context krbContext = NULL;
110 if (ctx == GSS_C_NO_CONTEXT) {
111 return GSS_S_COMPLETE;
114 gssEapKerberosInit(&tmpMinor, &krbContext);
116 #ifdef GSSEAP_ENABLE_REAUTH
117 if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
118 gssDeleteSecContext(&tmpMinor, &ctx->kerberosCtx, GSS_C_NO_BUFFER);
121 if (CTX_IS_INITIATOR(ctx)) {
122 releaseInitiatorContext(&ctx->initiatorCtx);
124 releaseAcceptorContext(&ctx->acceptorCtx);
127 krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
128 gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
129 gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
130 gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
131 sequenceFree(&tmpMinor, &ctx->seqState);
132 gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
133 gss_release_buffer(&tmpMinor, &ctx->conversation);
135 GSSEAP_MUTEX_DESTROY(&ctx->mutex);
137 memset(ctx, 0, sizeof(*ctx));
139 *pCtx = GSS_C_NO_CONTEXT;
142 return GSS_S_COMPLETE;
146 recordTokens(OM_uint32 *minor,
152 size_t i, size, offset;
154 size = ctx->conversation.length;
156 for (i = 0; i < tokensCount; i++)
157 size += tokens[i].length;
159 buf = GSSEAP_REALLOC(ctx->conversation.value, size);
162 return GSS_S_FAILURE;
165 offset = ctx->conversation.length;
167 ctx->conversation.length = size;
168 ctx->conversation.value = buf;
170 for (i = 0; i < tokensCount; i++) {
171 memcpy(buf + offset, tokens[i].value, tokens[i].length);
172 offset += tokens[i].length;
176 return GSS_S_COMPLETE;
180 gssEapRecordContextTokenHeader(OM_uint32 *minor,
182 enum gss_eap_token_type tokType)
184 unsigned char wireOidHeader[2], wireTokType[2];
185 gss_buffer_desc buffers[3];
187 assert(ctx->mechanismUsed != GSS_C_NO_OID);
189 wireOidHeader[0] = 0x06;
190 wireOidHeader[1] = ctx->mechanismUsed->length;
191 buffers[0].length = sizeof(wireOidHeader);
192 buffers[0].value = wireOidHeader;
194 buffers[1].length = ctx->mechanismUsed->length;
195 buffers[1].value = ctx->mechanismUsed->elements;
197 store_uint16_be(tokType, wireTokType);
198 buffers[2].length = sizeof(wireTokType);
199 buffers[2].value = wireTokType;
201 return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
205 gssEapRecordInnerContextToken(OM_uint32 *minor,
207 gss_buffer_t innerToken,
210 gss_buffer_desc buffers[3];
211 unsigned char wireItokType[4], wireLength[4];
213 assert(innerToken != GSS_C_NO_BUFFER);
215 store_uint32_be(itokType, wireItokType);
216 buffers[0].length = sizeof(wireItokType);
217 buffers[0].value = wireItokType;
219 store_uint32_be(innerToken->length, wireLength);
220 buffers[1].length = sizeof(wireLength);
221 buffers[1].value = wireLength;
223 buffers[2] = *innerToken;
225 return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
229 gssEapVerifyContextToken(OM_uint32 *minor,
231 const gss_buffer_t inputToken,
232 enum gss_eap_token_type tokType,
233 gss_buffer_t innerInputToken)
237 unsigned char *p = (unsigned char *)inputToken->value;
240 enum gss_eap_token_type actualTokType;
241 gss_buffer_desc tokenBuf;
243 if (ctx->mechanismUsed != GSS_C_NO_OID) {
244 oid = ctx->mechanismUsed;
246 oidBuf.elements = NULL;
251 major = verifyTokenHeader(minor, oid, &bodySize, &p,
252 inputToken->length, &actualTokType);
253 if (GSS_ERROR(major))
256 if (actualTokType != tokType) {
257 *minor = GSSEAP_WRONG_TOK_ID;
258 return GSS_S_DEFECTIVE_TOKEN;
261 if (ctx->mechanismUsed == GSS_C_NO_OID) {
262 if (!gssEapIsConcreteMechanismOid(oid)) {
263 *minor = GSSEAP_WRONG_MECH;
264 return GSS_S_BAD_MECH;
267 if (!gssEapInternalizeOid(oid, &ctx->mechanismUsed)) {
268 major = duplicateOid(minor, oid, &ctx->mechanismUsed);
269 if (GSS_ERROR(major))
274 innerInputToken->length = bodySize;
275 innerInputToken->value = p;
278 * Add OID, tokenType, body to conversation; variable length
279 * header omitted. A better API to verifyTokenHeader would
280 * avoid this ugly pointer arithmetic. XXX FIXME
282 tokenBuf.value = p - (2 + oid->length + 2);
283 tokenBuf.length = 2 + oid->length + 2 + bodySize;
285 major = recordTokens(minor, ctx, &tokenBuf, 1);
286 if (GSS_ERROR(major))
290 return GSS_S_COMPLETE;
294 gssEapContextTime(OM_uint32 *minor,
295 gss_ctx_id_t context_handle,
298 if (context_handle->expiryTime == 0) {
299 *time_rec = GSS_C_INDEFINITE;
301 time_t now, lifetime;
304 lifetime = context_handle->expiryTime - now;
307 return GSS_S_CONTEXT_EXPIRED;
309 *time_rec = lifetime;
312 return GSS_S_COMPLETE;
316 gssEapGetConversationMIC(OM_uint32 *minor,
318 gss_buffer_t convMIC)
321 gss_iov_buffer_desc iov[2];
323 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
324 iov[0].buffer = ctx->conversation;
326 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
327 iov[1].buffer.length = 0;
328 iov[1].buffer.value = NULL;
330 major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
331 if (GSS_ERROR(major))
334 *convMIC = iov[1].buffer;
337 return GSS_S_COMPLETE;
341 gssEapVerifyConversationMIC(OM_uint32 *minor,
343 const gss_buffer_t convMIC)
346 gss_iov_buffer_desc iov[3];
348 size_t tokenHeaderLength;
350 if (convMIC == GSS_C_NO_BUFFER || convMIC->length < 16) {
351 *minor = GSSEAP_TOK_TRUNC;
352 return GSS_S_BAD_SIG;
355 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
356 iov[0].buffer = ctx->conversation;
359 * The conversation state already includes the MIC and its
360 * TLV header, as well as a header for emiting a subsequent
361 * token. These should not be included as input to verifyMIC.
363 tokenHeaderLength = 8 + convMIC->length + 2 + ctx->mechanismUsed->length + 2;
364 assert(ctx->conversation.length > tokenHeaderLength);
365 iov[0].buffer.length -= tokenHeaderLength;
367 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
368 iov[1].buffer.length = 16;
369 iov[1].buffer.value = convMIC->value;
371 iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
372 iov[2].buffer.length = convMIC->length - 16;
373 iov[2].buffer.value = (unsigned char *)convMIC->value + 16;
375 major = gssEapUnwrapOrVerifyMIC(minor, ctx, &confState, NULL,
376 iov, 3, TOK_TYPE_MIC);
383 gssEapEncodeExtensions(OM_uint32 *minor,
386 gss_buffer_t outputToken)
391 outputToken->value = GSSEAP_MALLOC(4 * typesCount);
392 if (outputToken->value == NULL) {
394 return GSS_S_FAILURE;
396 p = (unsigned char *)outputToken->value;
398 outputToken->length = 4 * typesCount;
400 for (i = 0; i < typesCount; i++) {
401 store_uint32_be(types[i], p);
406 return GSS_S_COMPLETE;
410 gssEapProcessExtensions(OM_uint32 *minor,
411 gss_buffer_t inputToken,
412 struct gss_eap_itok_map *map,
419 if ((inputToken->length % 4) != 0) {
420 *minor = GSSEAP_TOK_TRUNC;
421 return GSS_S_DEFECTIVE_TOKEN;
424 p = (unsigned char *)inputToken->value;
426 for (i = 0; i < inputToken->length / 4; i++) {
427 OM_uint32 type = load_uint32_be(p);
430 for (j = 0; j < mapCount; j++) {
431 if (map->type == type) {
441 return GSS_S_COMPLETE;