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 * Establish a security context on the initiator (client). These functions
38 #include "gssapiP_eap.h"
41 policyVariableToFlag(enum eapol_bool_var variable)
46 case EAPOL_eapSuccess:
47 flag = CTX_FLAG_EAP_SUCCESS;
49 case EAPOL_eapRestart:
50 flag = CTX_FLAG_EAP_RESTART;
53 flag = CTX_FLAG_EAP_FAIL;
56 flag = CTX_FLAG_EAP_RESP;
59 flag = CTX_FLAG_EAP_NO_RESP;
62 flag = CTX_FLAG_EAP_REQ;
64 case EAPOL_portEnabled:
65 flag = CTX_FLAG_EAP_PORT_ENABLED;
68 flag = CTX_FLAG_EAP_ALT_ACCEPT;
71 flag = CTX_FLAG_EAP_ALT_REJECT;
78 static struct eap_peer_config *
79 peerGetConfig(void *ctx)
81 gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
83 return &gssCtx->initiatorCtx.eapPeerConfig;
87 peerGetBool(void *data, enum eapol_bool_var variable)
89 gss_ctx_id_t ctx = data;
92 if (ctx == GSS_C_NO_CONTEXT)
95 flag = policyVariableToFlag(variable);
97 return ((ctx->flags & flag) != 0);
101 peerSetBool(void *data, enum eapol_bool_var variable,
104 gss_ctx_id_t ctx = data;
107 if (ctx == GSS_C_NO_CONTEXT)
110 flag = policyVariableToFlag(variable);
115 ctx->flags &= ~(flag);
119 peerGetInt(void *data, enum eapol_int_var variable)
121 gss_ctx_id_t ctx = data;
123 if (ctx == GSS_C_NO_CONTEXT)
126 GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
129 case EAPOL_idleWhile:
130 return ctx->initiatorCtx.idleWhile;
138 peerSetInt(void *data, enum eapol_int_var variable,
141 gss_ctx_id_t ctx = data;
143 if (ctx == GSS_C_NO_CONTEXT)
146 GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
149 case EAPOL_idleWhile:
150 ctx->initiatorCtx.idleWhile = value;
155 static struct wpabuf *
156 peerGetEapReqData(void *ctx)
158 gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
160 return &gssCtx->initiatorCtx.reqData;
164 peerSetConfigBlob(void *ctx GSSEAP_UNUSED,
165 struct wpa_config_blob *blob GSSEAP_UNUSED)
169 static const struct wpa_config_blob *
170 peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
171 const char *name GSSEAP_UNUSED)
177 peerNotifyPending(void *ctx GSSEAP_UNUSED)
181 static struct eapol_callbacks gssEapPolicyCallbacks = {
194 extern int wpa_debug_level;
198 peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
201 krb5_context krbContext;
202 struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
203 gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
204 gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
205 gss_cred_id_t cred = ctx->cred;
207 eapPeerConfig->identity = NULL;
208 eapPeerConfig->identity_len = 0;
209 eapPeerConfig->anonymous_identity = NULL;
210 eapPeerConfig->anonymous_identity_len = 0;
211 eapPeerConfig->password = NULL;
212 eapPeerConfig->password_len = 0;
214 GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
216 GSSEAP_KRB_INIT(&krbContext);
218 eapPeerConfig->fragment_size = 1024;
223 GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME);
225 if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
226 *minor = GSSEAP_BAD_INITIATOR_NAME;
227 return GSS_S_BAD_NAME;
231 major = gssEapDisplayName(minor, cred->name, &identity, NULL);
232 if (GSS_ERROR(major))
235 eapPeerConfig->identity = (unsigned char *)identity.value;
236 eapPeerConfig->identity_len = identity.length;
238 krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm);
240 /* anonymous_identity */
241 eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2);
242 if (eapPeerConfig->anonymous_identity == NULL) {
244 return GSS_S_FAILURE;
247 eapPeerConfig->anonymous_identity[0] = '@';
248 memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length);
249 eapPeerConfig->anonymous_identity[1 + realm.length] = '\0';
250 eapPeerConfig->anonymous_identity_len = 1 + realm.length;
253 if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) {
254 eapPeerConfig->password = (unsigned char *)cred->password.value;
255 eapPeerConfig->password_len = cred->password.length;
259 eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
260 eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
261 eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
263 if (cred->flags & CRED_FLAG_CERTIFICATE) {
264 eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value;
265 eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value;
266 eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value;
270 return GSS_S_COMPLETE;
274 peerConfigFree(OM_uint32 *minor,
277 struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
279 if (eapPeerConfig->identity != NULL) {
280 GSSEAP_FREE(eapPeerConfig->identity);
281 eapPeerConfig->identity = NULL;
282 eapPeerConfig->identity_len = 0;
285 if (eapPeerConfig->anonymous_identity != NULL) {
286 GSSEAP_FREE(eapPeerConfig->anonymous_identity);
287 eapPeerConfig->anonymous_identity = NULL;
288 eapPeerConfig->anonymous_identity_len = 0;
292 return GSS_S_COMPLETE;
296 * Mark an initiator context as ready for cryptographic operations
299 initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
302 const unsigned char *key;
306 /* XXX actually check for mutual auth */
307 if (reqFlags & GSS_C_MUTUAL_FLAG)
308 ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
311 /* Cache encryption type derived from selected mechanism OID */
312 major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
313 if (GSS_ERROR(major))
316 if (!eap_key_available(ctx->initiatorCtx.eap)) {
317 *minor = GSSEAP_KEY_UNAVAILABLE;
318 return GSS_S_UNAVAILABLE;
321 key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
323 if (keyLength < EAP_EMSK_LEN) {
324 *minor = GSSEAP_KEY_TOO_SHORT;
325 return GSS_S_UNAVAILABLE;
328 major = gssEapDeriveRfc3961Key(minor,
329 &key[EAP_EMSK_LEN / 2],
333 if (GSS_ERROR(major))
336 major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
338 if (GSS_ERROR(major))
341 major = sequenceInit(minor,
344 ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
345 ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
347 if (GSS_ERROR(major))
351 return GSS_S_COMPLETE;
355 initBegin(OM_uint32 *minor,
359 OM_uint32 reqFlags GSSEAP_UNUSED,
361 gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
364 gss_cred_id_t cred = ctx->cred;
366 GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
368 if (cred->expiryTime)
369 ctx->expiryTime = cred->expiryTime;
370 else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
373 ctx->expiryTime = time(NULL) + timeReq;
376 * The credential mutex protects its name, however we need to
377 * explicitly lock the acceptor name (unlikely as it may be
378 * that it has attributes set on it).
380 major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
381 if (GSS_ERROR(major))
384 if (target != GSS_C_NO_NAME) {
385 GSSEAP_MUTEX_LOCK(&target->mutex);
387 major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
388 if (GSS_ERROR(major)) {
389 GSSEAP_MUTEX_UNLOCK(&target->mutex);
393 GSSEAP_MUTEX_UNLOCK(&target->mutex);
396 major = gssEapCanonicalizeOid(minor,
398 OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH,
399 &ctx->mechanismUsed);
400 if (GSS_ERROR(major))
403 /* If credentials were provided, check they're usable with this mech */
404 if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
405 *minor = GSSEAP_CRED_MECH_MISMATCH;
406 return GSS_S_BAD_MECH;
410 return GSS_S_COMPLETE;
414 eapGssSmInitError(OM_uint32 *minor,
415 gss_cred_id_t cred GSSEAP_UNUSED,
416 gss_ctx_id_t ctx GSSEAP_UNUSED,
417 gss_name_t target GSSEAP_UNUSED,
418 gss_OID mech GSSEAP_UNUSED,
419 OM_uint32 reqFlags GSSEAP_UNUSED,
420 OM_uint32 timeReq GSSEAP_UNUSED,
421 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
422 gss_buffer_t inputToken,
423 gss_buffer_t outputToken GSSEAP_UNUSED,
424 OM_uint32 *smFlags GSSEAP_UNUSED)
429 if (inputToken->length < 8) {
430 *minor = GSSEAP_TOK_TRUNC;
431 return GSS_S_DEFECTIVE_TOKEN;
434 p = (unsigned char *)inputToken->value;
436 major = load_uint32_be(&p[0]);
437 *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
439 if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
440 major = GSS_S_FAILURE;
441 *minor = GSSEAP_BAD_ERROR_TOKEN;
444 GSSEAP_ASSERT(GSS_ERROR(major));
449 #ifdef GSSEAP_ENABLE_REAUTH
451 eapGssSmInitGssReauth(OM_uint32 *minor,
455 gss_OID mech GSSEAP_UNUSED,
458 gss_channel_bindings_t chanBindings,
459 gss_buffer_t inputToken,
460 gss_buffer_t outputToken,
461 OM_uint32 *smFlags GSSEAP_UNUSED)
463 OM_uint32 major, tmpMinor;
464 gss_name_t mechTarget = GSS_C_NO_NAME;
465 gss_OID actualMech = GSS_C_NO_OID;
466 OM_uint32 gssFlags, timeRec;
469 * Here we use the passed in credential handle because the resolved
470 * context credential does not currently have the reauth creds.
472 if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
473 if (!gssEapCanReauthP(cred, target, timeReq))
474 return GSS_S_CONTINUE_NEEDED;
476 ctx->flags |= CTX_FLAG_KRB_REAUTH;
477 } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
478 major = GSS_S_DEFECTIVE_TOKEN;
479 *minor = GSSEAP_WRONG_ITOK;
483 GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
485 major = gssEapMechToGlueName(minor, target, &mechTarget);
486 if (GSS_ERROR(major))
489 major = gssInitSecContext(minor,
493 (gss_OID)gss_mech_krb5,
494 reqFlags | GSS_C_MUTUAL_FLAG,
502 if (GSS_ERROR(major))
505 ctx->gssFlags = gssFlags;
507 if (major == GSS_S_COMPLETE) {
508 GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
510 major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
511 if (GSS_ERROR(major))
513 GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
515 GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
519 gssReleaseName(&tmpMinor, &mechTarget);
523 #endif /* GSSEAP_ENABLE_REAUTH */
527 eapGssSmInitVendorInfo(OM_uint32 *minor,
528 gss_cred_id_t cred GSSEAP_UNUSED,
529 gss_ctx_id_t ctx GSSEAP_UNUSED,
530 gss_name_t target GSSEAP_UNUSED,
531 gss_OID mech GSSEAP_UNUSED,
532 OM_uint32 reqFlags GSSEAP_UNUSED,
533 OM_uint32 timeReq GSSEAP_UNUSED,
534 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
535 gss_buffer_t inputToken GSSEAP_UNUSED,
536 gss_buffer_t outputToken,
537 OM_uint32 *smFlags GSSEAP_UNUSED)
541 major = makeStringBuffer(minor, "JANET(UK)", outputToken);
542 if (GSS_ERROR(major))
545 return GSS_S_CONTINUE_NEEDED;
550 eapGssSmInitAcceptorName(OM_uint32 *minor,
551 gss_cred_id_t cred GSSEAP_UNUSED,
553 gss_name_t target GSSEAP_UNUSED,
554 gss_OID mech GSSEAP_UNUSED,
555 OM_uint32 reqFlags GSSEAP_UNUSED,
556 OM_uint32 timeReq GSSEAP_UNUSED,
557 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
558 gss_buffer_t inputToken GSSEAP_UNUSED,
559 gss_buffer_t outputToken,
560 OM_uint32 *smFlags GSSEAP_UNUSED)
564 if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL &&
565 ctx->acceptorName != GSS_C_NO_NAME) {
567 /* Send desired target name to acceptor */
568 major = gssEapDisplayName(minor, ctx->acceptorName,
570 if (GSS_ERROR(major))
572 } else if (inputToken != GSS_C_NO_BUFFER &&
573 ctx->acceptorName == GSS_C_NO_NAME) {
574 /* Accept target name hint from acceptor */
575 major = gssEapImportName(minor, inputToken,
579 if (GSS_ERROR(major))
584 * Currently, other parts of the code assume that the acceptor name
585 * is available, hence this check.
587 if (ctx->acceptorName == GSS_C_NO_NAME) {
588 *minor = GSSEAP_NO_ACCEPTOR_NAME;
589 return GSS_S_FAILURE;
592 return GSS_S_CONTINUE_NEEDED;
596 eapGssSmInitIdentity(OM_uint32 *minor,
597 gss_cred_id_t cred GSSEAP_UNUSED,
599 gss_name_t target GSSEAP_UNUSED,
600 gss_OID mech GSSEAP_UNUSED,
601 OM_uint32 reqFlags GSSEAP_UNUSED,
602 OM_uint32 timeReq GSSEAP_UNUSED,
603 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
604 gss_buffer_t inputToken GSSEAP_UNUSED,
605 gss_buffer_t outputToken GSSEAP_UNUSED,
608 struct eap_config eapConfig;
610 #ifdef GSSEAP_ENABLE_REAUTH
611 if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
614 /* server didn't support reauthentication, sent EAP request */
615 gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
616 ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
617 GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
620 *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
622 GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
623 GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
625 memset(&eapConfig, 0, sizeof(eapConfig));
627 ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
628 &gssEapPolicyCallbacks,
631 if (ctx->initiatorCtx.eap == NULL) {
632 *minor = GSSEAP_PEER_SM_INIT_FAILURE;
633 return GSS_S_FAILURE;
636 ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
638 /* poke EAP state machine */
639 if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) {
640 *minor = GSSEAP_PEER_SM_STEP_FAILURE;
641 return GSS_S_FAILURE;
644 GSSEAP_SM_TRANSITION_NEXT(ctx);
648 return GSS_S_CONTINUE_NEEDED;
652 eapGssSmInitAuthenticate(OM_uint32 *minor,
653 gss_cred_id_t cred GSSEAP_UNUSED,
655 gss_name_t target GSSEAP_UNUSED,
656 gss_OID mech GSSEAP_UNUSED,
657 OM_uint32 reqFlags GSSEAP_UNUSED,
658 OM_uint32 timeReq GSSEAP_UNUSED,
659 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
660 gss_buffer_t inputToken GSSEAP_UNUSED,
661 gss_buffer_t outputToken,
666 struct wpabuf *resp = NULL;
670 GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
672 major = peerConfigInit(minor, ctx);
673 if (GSS_ERROR(major))
676 GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL);
677 GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
679 ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
681 wpabuf_set(&ctx->initiatorCtx.reqData,
682 inputToken->value, inputToken->length);
684 major = GSS_S_CONTINUE_NEEDED;
686 eap_peer_sm_step(ctx->initiatorCtx.eap);
687 if (ctx->flags & CTX_FLAG_EAP_RESP) {
688 ctx->flags &= ~(CTX_FLAG_EAP_RESP);
690 resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
691 } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
692 major = initReady(minor, ctx, reqFlags);
693 if (GSS_ERROR(major))
696 ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
697 major = GSS_S_CONTINUE_NEEDED;
698 GSSEAP_SM_TRANSITION_NEXT(ctx);
699 } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
700 major = GSS_S_DEFECTIVE_CREDENTIAL;
701 *minor = GSSEAP_PEER_AUTH_FAILURE;
703 major = GSS_S_DEFECTIVE_TOKEN;
704 *minor = GSSEAP_PEER_BAD_MESSAGE;
710 gss_buffer_desc respBuf;
712 GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
714 respBuf.length = wpabuf_len(resp);
715 respBuf.value = (void *)wpabuf_head(resp);
717 tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
718 if (GSS_ERROR(tmpMajor)) {
723 *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
726 wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
727 peerConfigFree(&tmpMinor, ctx);
733 eapGssSmInitGssFlags(OM_uint32 *minor,
734 gss_cred_id_t cred GSSEAP_UNUSED,
736 gss_name_t target GSSEAP_UNUSED,
737 gss_OID mech GSSEAP_UNUSED,
738 OM_uint32 reqFlags GSSEAP_UNUSED,
739 OM_uint32 timeReq GSSEAP_UNUSED,
740 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
741 gss_buffer_t inputToken GSSEAP_UNUSED,
742 gss_buffer_t outputToken,
743 OM_uint32 *smFlags GSSEAP_UNUSED)
745 unsigned char wireFlags[4];
746 gss_buffer_desc flagsBuf;
748 store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
750 flagsBuf.length = sizeof(wireFlags);
751 flagsBuf.value = wireFlags;
753 return duplicateBuffer(minor, &flagsBuf, outputToken);
757 eapGssSmInitGssChannelBindings(OM_uint32 *minor,
758 gss_cred_id_t cred GSSEAP_UNUSED,
760 gss_name_t target GSSEAP_UNUSED,
761 gss_OID mech GSSEAP_UNUSED,
762 OM_uint32 reqFlags GSSEAP_UNUSED,
763 OM_uint32 timeReq GSSEAP_UNUSED,
764 gss_channel_bindings_t chanBindings,
765 gss_buffer_t inputToken GSSEAP_UNUSED,
766 gss_buffer_t outputToken,
770 gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
772 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
773 buffer = chanBindings->application_data;
775 major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
776 &buffer, NULL, outputToken);
777 if (GSS_ERROR(major))
780 GSSEAP_ASSERT(outputToken->value != NULL);
783 *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
785 return GSS_S_CONTINUE_NEEDED;
789 eapGssSmInitInitiatorMIC(OM_uint32 *minor,
790 gss_cred_id_t cred GSSEAP_UNUSED,
792 gss_name_t target GSSEAP_UNUSED,
793 gss_OID mech GSSEAP_UNUSED,
794 OM_uint32 reqFlags GSSEAP_UNUSED,
795 OM_uint32 timeReq GSSEAP_UNUSED,
796 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
797 gss_buffer_t inputToken GSSEAP_UNUSED,
798 gss_buffer_t outputToken,
803 major = gssEapMakeTokenMIC(minor, ctx, outputToken);
804 if (GSS_ERROR(major))
807 GSSEAP_SM_TRANSITION_NEXT(ctx);
810 *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
812 return GSS_S_CONTINUE_NEEDED;
815 #ifdef GSSEAP_ENABLE_REAUTH
817 eapGssSmInitReauthCreds(OM_uint32 *minor,
820 gss_name_t target GSSEAP_UNUSED,
821 gss_OID mech GSSEAP_UNUSED,
822 OM_uint32 reqFlags GSSEAP_UNUSED,
823 OM_uint32 timeReq GSSEAP_UNUSED,
824 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
825 gss_buffer_t inputToken,
826 gss_buffer_t outputToken GSSEAP_UNUSED,
827 OM_uint32 *smFlags GSSEAP_UNUSED)
831 if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) {
832 major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
833 if (GSS_ERROR(major))
838 return GSS_S_CONTINUE_NEEDED;
840 #endif /* GSSEAP_ENABLE_REAUTH */
843 eapGssSmInitAcceptorMIC(OM_uint32 *minor,
844 gss_cred_id_t cred GSSEAP_UNUSED,
846 gss_name_t target GSSEAP_UNUSED,
847 gss_OID mech GSSEAP_UNUSED,
848 OM_uint32 reqFlags GSSEAP_UNUSED,
849 OM_uint32 timeReq GSSEAP_UNUSED,
850 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
851 gss_buffer_t inputToken,
852 gss_buffer_t outputToken GSSEAP_UNUSED,
853 OM_uint32 *smFlags GSSEAP_UNUSED)
857 major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
858 if (GSS_ERROR(major))
861 GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
865 return GSS_S_COMPLETE;
868 static struct gss_eap_sm eapGssInitiatorSm[] = {
870 ITOK_TYPE_CONTEXT_ERR,
872 GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
877 ITOK_TYPE_ACCEPTOR_NAME_RESP,
878 ITOK_TYPE_ACCEPTOR_NAME_REQ,
879 GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
881 eapGssSmInitAcceptorName
886 ITOK_TYPE_VENDOR_INFO,
887 GSSEAP_STATE_INITIAL,
889 eapGssSmInitVendorInfo
892 #ifdef GSSEAP_ENABLE_REAUTH
894 ITOK_TYPE_REAUTH_RESP,
895 ITOK_TYPE_REAUTH_REQ,
896 GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
898 eapGssSmInitGssReauth
904 #ifdef GSSEAP_ENABLE_REAUTH
905 GSSEAP_STATE_REAUTHENTICATE |
907 GSSEAP_STATE_INITIAL,
908 SM_ITOK_FLAG_REQUIRED,
914 GSSEAP_STATE_AUTHENTICATE,
915 SM_ITOK_FLAG_REQUIRED,
916 eapGssSmInitAuthenticate
921 GSSEAP_STATE_INITIATOR_EXTS,
927 ITOK_TYPE_GSS_CHANNEL_BINDINGS,
928 GSSEAP_STATE_INITIATOR_EXTS,
929 SM_ITOK_FLAG_REQUIRED,
930 eapGssSmInitGssChannelBindings
934 ITOK_TYPE_INITIATOR_MIC,
935 GSSEAP_STATE_INITIATOR_EXTS,
936 SM_ITOK_FLAG_REQUIRED,
937 eapGssSmInitInitiatorMIC
939 #ifdef GSSEAP_ENABLE_REAUTH
941 ITOK_TYPE_REAUTH_CREDS,
943 GSSEAP_STATE_ACCEPTOR_EXTS,
945 eapGssSmInitReauthCreds
948 /* other extensions go here */
950 ITOK_TYPE_ACCEPTOR_MIC,
952 GSSEAP_STATE_ACCEPTOR_EXTS,
953 SM_ITOK_FLAG_REQUIRED,
954 eapGssSmInitAcceptorMIC
959 gssEapInitSecContext(OM_uint32 *minor,
962 gss_name_t target_name,
966 gss_channel_bindings_t input_chan_bindings,
967 gss_buffer_t input_token,
968 gss_OID *actual_mech_type,
969 gss_buffer_t output_token,
970 OM_uint32 *ret_flags,
973 OM_uint32 major, tmpMinor;
974 int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
977 * XXX is acquiring the credential lock here necessary? The password is
978 * mutable but the contract could specify that this is not updated whilst
979 * a context is being initialized.
981 if (cred != GSS_C_NO_CREDENTIAL)
982 GSSEAP_MUTEX_LOCK(&cred->mutex);
984 if (ctx->cred == GSS_C_NO_CREDENTIAL) {
985 major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
986 if (GSS_ERROR(major))
989 GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
992 GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
994 GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
995 GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
997 if (initialContextToken) {
998 major = initBegin(minor, ctx, target_name, mech_type,
999 req_flags, time_req, input_chan_bindings);
1000 if (GSS_ERROR(major))
1004 major = gssEapSmStep(minor,
1011 input_chan_bindings,
1015 sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0]));
1016 if (GSS_ERROR(major))
1019 if (actual_mech_type != NULL) {
1022 tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type);
1023 if (GSS_ERROR(tmpMajor)) {
1029 if (ret_flags != NULL)
1030 *ret_flags = ctx->gssFlags;
1031 if (time_rec != NULL)
1032 gssEapContextTime(&tmpMinor, ctx, time_rec);
1034 GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
1037 if (cred != GSS_C_NO_CREDENTIAL)
1038 GSSEAP_MUTEX_UNLOCK(&cred->mutex);
1039 if (ctx->cred != GSS_C_NO_CREDENTIAL)
1040 GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
1045 OM_uint32 GSSAPI_CALLCONV
1046 gss_init_sec_context(OM_uint32 *minor,
1048 gss_ctx_id_t *context_handle,
1049 gss_name_t target_name,
1051 OM_uint32 req_flags,
1053 gss_channel_bindings_t input_chan_bindings,
1054 gss_buffer_t input_token,
1055 gss_OID *actual_mech_type,
1056 gss_buffer_t output_token,
1057 OM_uint32 *ret_flags,
1058 OM_uint32 *time_rec)
1060 OM_uint32 major, tmpMinor;
1061 gss_ctx_id_t ctx = *context_handle;
1065 output_token->length = 0;
1066 output_token->value = NULL;
1068 if (ctx == GSS_C_NO_CONTEXT) {
1069 if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
1070 *minor = GSSEAP_WRONG_SIZE;
1071 return GSS_S_DEFECTIVE_TOKEN;
1074 major = gssEapAllocContext(minor, &ctx);
1075 if (GSS_ERROR(major))
1078 ctx->flags |= CTX_FLAG_INITIATOR;
1080 *context_handle = ctx;
1083 GSSEAP_MUTEX_LOCK(&ctx->mutex);
1085 major = gssEapInitSecContext(minor,
1092 input_chan_bindings,
1099 GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
1101 if (GSS_ERROR(major))
1102 gssEapReleaseContext(&tmpMinor, context_handle);