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 */
74 GSS_C_MUTUAL_FLAG; /*xxx big hack */
78 return GSS_S_COMPLETE;
82 releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
84 eap_peer_sm_deinit(ctx->eap);
88 releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
92 if (ctx->radConn != NULL)
93 rs_conn_destroy(ctx->radConn);
94 if (ctx->radContext != NULL)
95 rs_context_destroy(ctx->radContext);
96 if (ctx->radServer != NULL)
97 GSSEAP_FREE(ctx->radServer);
98 gss_release_buffer(&tmpMinor, &ctx->state);
100 gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
104 gssEapReleaseContext(OM_uint32 *minor,
108 gss_ctx_id_t ctx = *pCtx;
109 krb5_context krbContext = NULL;
111 if (ctx == GSS_C_NO_CONTEXT) {
112 return GSS_S_COMPLETE;
115 gssEapKerberosInit(&tmpMinor, &krbContext);
117 #ifdef GSSEAP_ENABLE_REAUTH
118 if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
119 gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
122 if (CTX_IS_INITIATOR(ctx)) {
123 releaseInitiatorContext(&ctx->initiatorCtx);
125 releaseAcceptorContext(&ctx->acceptorCtx);
128 krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
129 gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
130 gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
131 gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
132 sequenceFree(&tmpMinor, &ctx->seqState);
133 gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
134 gss_release_buffer(&tmpMinor, &ctx->conversation);
136 GSSEAP_MUTEX_DESTROY(&ctx->mutex);
138 memset(ctx, 0, sizeof(*ctx));
140 *pCtx = GSS_C_NO_CONTEXT;
143 return GSS_S_COMPLETE;
147 gssEapContextTime(OM_uint32 *minor,
148 gss_ctx_id_t context_handle,
153 if (context_handle->expiryTime == 0) {
154 *time_rec = GSS_C_INDEFINITE;
156 time_t now, lifetime;
159 lifetime = context_handle->expiryTime - now;
162 return GSS_S_CONTEXT_EXPIRED;
164 *time_rec = lifetime;
167 return GSS_S_COMPLETE;
171 gssEapGetConversationMIC(OM_uint32 *minor,
173 gss_buffer_t convMIC)
176 gss_iov_buffer_desc iov[2];
178 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
179 iov[0].buffer = ctx->conversation;
181 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
182 iov[1].buffer.length = 0;
183 iov[1].buffer.value = NULL;
185 major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
186 if (GSS_ERROR(major))
189 *convMIC = iov[1].buffer;
192 return GSS_S_COMPLETE;
196 gssEapVerifyConversationMIC(OM_uint32 *minor,
198 const gss_buffer_t convMIC)
201 gss_iov_buffer_desc iov[3];
203 size_t tokenHeaderLength;
205 if (convMIC == GSS_C_NO_BUFFER || convMIC->length < 16) {
206 *minor = GSSEAP_TOK_TRUNC;
207 return GSS_S_BAD_SIG;
210 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
211 iov[0].buffer = ctx->conversation;
214 * The conversation state already includes the MIC and its
215 * TLV header, as well as a header for emiting a subsequent
216 * token. These should not be included as input to verifyMIC.
218 tokenHeaderLength = ITOK_HEADER_LENGTH + convMIC->length
219 + 2 + ctx->mechanismUsed->length + 2;
220 assert(ctx->conversation.length >= tokenHeaderLength);
221 iov[0].buffer.length -= tokenHeaderLength;
223 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
224 iov[1].buffer.length = 16;
225 iov[1].buffer.value = convMIC->value;
227 iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
228 iov[2].buffer.length = convMIC->length - 16;
229 iov[2].buffer.value = (unsigned char *)convMIC->value + 16;
231 major = gssEapUnwrapOrVerifyMIC(minor, ctx, &confState, NULL,
232 iov, 3, TOK_TYPE_MIC);
239 gssEapMakeTokenChannelBindings(OM_uint32 *minor,
241 gss_channel_bindings_t userChanBindings,
242 gss_buffer_t inputToken,
243 gss_channel_bindings_t wireChanBindings)
245 gss_buffer_t wireData = &wireChanBindings->application_data;
247 size_t tokenHeaderLength = 0;
249 memset(wireChanBindings, 0, sizeof(*wireChanBindings));
251 if (!CTX_IS_INITIATOR(ctx)) {
252 assert(inputToken != GSS_C_NO_BUFFER);
254 tokenHeaderLength = ITOK_HEADER_LENGTH + inputToken->length +
255 2 + ctx->mechanismUsed->length + 2;
256 assert(ctx->conversation.length >= tokenHeaderLength);
259 wireData->length = ctx->conversation.length - tokenHeaderLength;
261 if (userChanBindings != GSS_C_NO_CHANNEL_BINDINGS)
262 wireData->length += userChanBindings->application_data.length;
264 wireData->value = GSSEAP_MALLOC(wireData->length);
265 if (wireData->value == NULL) {
267 return GSS_S_FAILURE;
270 p = (unsigned char *)wireData->value;
272 memcpy(p, ctx->conversation.value, ctx->conversation.length - tokenHeaderLength);
273 p += ctx->conversation.length - tokenHeaderLength;
275 if (userChanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
276 memcpy(p, userChanBindings->application_data.value,
277 userChanBindings->application_data.length);
278 p += userChanBindings->application_data.length;
282 return GSS_S_COMPLETE;