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 gssEapContextTime(OM_uint32 *minor,
147 gss_ctx_id_t context_handle,
152 if (context_handle->expiryTime == 0) {
153 *time_rec = GSS_C_INDEFINITE;
155 time_t now, lifetime;
158 lifetime = context_handle->expiryTime - now;
161 return GSS_S_CONTEXT_EXPIRED;
163 *time_rec = lifetime;
166 return GSS_S_COMPLETE;
170 gssEapGetConversationMIC(OM_uint32 *minor,
172 gss_buffer_t convMIC)
175 gss_iov_buffer_desc iov[2];
177 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
178 iov[0].buffer = ctx->conversation;
180 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
181 iov[1].buffer.length = 0;
182 iov[1].buffer.value = NULL;
184 major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
185 if (GSS_ERROR(major))
188 *convMIC = iov[1].buffer;
191 return GSS_S_COMPLETE;
195 gssEapVerifyConversationMIC(OM_uint32 *minor,
197 const gss_buffer_t convMIC)
200 gss_iov_buffer_desc iov[3];
202 size_t tokenHeaderLength;
204 if (convMIC == GSS_C_NO_BUFFER || convMIC->length < 16) {
205 *minor = GSSEAP_TOK_TRUNC;
206 return GSS_S_BAD_SIG;
209 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
210 iov[0].buffer = ctx->conversation;
213 * The conversation state already includes the MIC and its
214 * TLV header, as well as a header for emiting a subsequent
215 * token. These should not be included as input to verifyMIC.
217 tokenHeaderLength = ITOK_HEADER_LENGTH + convMIC->length
218 + 2 + ctx->mechanismUsed->length + 2;
219 assert(ctx->conversation.length >= tokenHeaderLength);
220 iov[0].buffer.length -= tokenHeaderLength;
222 iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
223 iov[1].buffer.length = 16;
224 iov[1].buffer.value = convMIC->value;
226 iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
227 iov[2].buffer.length = convMIC->length - 16;
228 iov[2].buffer.value = (unsigned char *)convMIC->value + 16;
230 major = gssEapUnwrapOrVerifyMIC(minor, ctx, &confState, NULL,
231 iov, 3, TOK_TYPE_MIC);
238 gssEapMakeTokenChannelBindings(OM_uint32 *minor,
240 gss_channel_bindings_t userChanBindings,
241 gss_buffer_t inputToken,
242 gss_channel_bindings_t wireChanBindings)
244 gss_buffer_t wireData = &wireChanBindings->application_data;
246 size_t tokenHeaderLength = 0;
248 memset(wireChanBindings, 0, sizeof(*wireChanBindings));
250 if (!CTX_IS_INITIATOR(ctx)) {
251 assert(inputToken != GSS_C_NO_BUFFER);
253 tokenHeaderLength = ITOK_HEADER_LENGTH + inputToken->length +
254 2 + ctx->mechanismUsed->length + 2;
255 assert(ctx->conversation.length >= tokenHeaderLength);
258 wireData->length = ctx->conversation.length - tokenHeaderLength;
260 if (userChanBindings != GSS_C_NO_CHANNEL_BINDINGS)
261 wireData->length += userChanBindings->application_data.length;
263 wireData->value = GSSEAP_MALLOC(wireData->length);
264 if (wireData->value == NULL) {
266 return GSS_S_FAILURE;
269 p = (unsigned char *)wireData->value;
271 memcpy(p, ctx->conversation.value, ctx->conversation.length - tokenHeaderLength);
272 p += ctx->conversation.length - tokenHeaderLength;
274 if (userChanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
275 memcpy(p, userChanBindings->application_data.value,
276 userChanBindings->application_data.length);
277 p += userChanBindings->application_data.length;
281 return GSS_S_COMPLETE;