*
* A module that implements the spnego security mechanism.
* It is used to negotiate the security mechanism between
- * peers using the GSS-API.
+ * peers using the GSS-API. SPNEGO is specified in RFC 4178.
*
*/
/*
if (time_rec)
*time_rec = 0;
+ /* We will obtain a mechglue credential and wrap it in a
+ * spnego_gss_cred_id_rec structure. Allocate the wrapper. */
spcred = malloc(sizeof(spnego_gss_cred_id_rec));
if (spcred == NULL) {
*minor_status = ENOMEM;
OM_uint32 *ret_flags,
OM_uint32 *time_rec)
{
- /*
- * send_token is used to indicate in later steps
- * what type of token, if any should be sent or processed.
- * NO_TOKEN_SEND = no token should be sent
- * INIT_TOKEN_SEND = initial token will be sent
- * CONT_TOKEN_SEND = continuing tokens to be sent
- * CHECK_MIC = no token to be sent, but have a MIC to check.
- */
send_token_flag send_token = NO_TOKEN_SEND;
OM_uint32 tmpmin, ret, negState;
gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
mechtok_in = mechListMIC_out = mechListMIC_in = GSS_C_NO_BUFFER;
negState = REJECT;
+ /*
+ * This function works in three steps:
+ *
+ * 1. Perform mechanism negotiation.
+ * 2. Invoke the negotiated or optimistic mech's gss_init_sec_context
+ * function and examine the results.
+ * 3. Process or generate MICs if necessary.
+ *
+ * The three steps share responsibility for determining when the
+ * exchange is complete. If the selected mech completed in a previous
+ * call and no MIC exchange is expected, then step 1 will decide. If
+ * the selected mech completes in this call and no MIC exchange is
+ * expected, then step 2 will decide. If a MIC exchange is expected,
+ * then step 3 will decide. If an error occurs in any step, the
+ * exchange will be aborted, possibly with an error token.
+ *
+ * negState determines the state of the negotiation, and is
+ * communicated to the acceptor if a continuing token is sent.
+ * send_token is used to indicate what type of token, if any, should be
+ * generated.
+ */
+
+ /* Validate arguments. */
if (minor_status != NULL)
*minor_status = 0;
if (output_token != GSS_C_NO_BUFFER) {
if (actual_mech != NULL)
*actual_mech = GSS_C_NO_OID;
+ /* Step 1: perform mechanism negotiation. */
spcred = (spnego_gss_cred_id_t)claimant_cred_handle;
if (*context_handle == GSS_C_NO_CONTEXT) {
ret = init_ctx_new(minor_status, spcred,
goto cleanup;
}
}
+
+ /* Step 2: invoke the selected or optimistic mechanism's
+ * gss_init_sec_context function, if it didn't complete previously. */
spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
if (!spnego_ctx->mech_complete) {
ret = init_ctx_call_init(
ret_flags, time_rec,
&negState, &send_token);
}
- /* create mic/check mic */
+
+ /* Step 3: process or generate the MIC, if the negotiated mech is
+ * complete and supports MICs. */
if (!HARD_ERROR(ret) && spnego_ctx->mech_complete &&
(spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {
mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER;
+ /*
+ * This function works in three steps:
+ *
+ * 1. Perform mechanism negotiation.
+ * 2. Invoke the negotiated mech's gss_accept_sec_context function
+ * and examine the results.
+ * 3. Process or generate MICs if necessary.
+ *
+ * Step one determines whether the negotiation requires a MIC exchange,
+ * while steps two and three share responsibility for determining when
+ * the exchange is complete. If the selected mech completes in this
+ * call and no MIC exchange is expected, then step 2 will decide. If a
+ * MIC exchange is expected, then step 3 will decide. If an error
+ * occurs in any step, the exchange will be aborted, possibly with an
+ * error token.
+ *
+ * negState determines the state of the negotiation, and is
+ * communicated to the acceptor if a continuing token is sent.
+ * return_token is used to indicate what type of token, if any, should
+ * be generated.
+ */
+
+ /* Validate arguments. */
if (minor_status != NULL)
*minor_status = 0;
if (output_token != GSS_C_NO_BUFFER) {
if (input_token == GSS_C_NO_BUFFER)
return GSS_S_CALL_INACCESSIBLE_READ;
+ /* Step 1: Perform mechanism negotiation. */
sc = (spnego_gss_ctx_id_t)*context_handle;
spcred = (spnego_gss_cred_id_t)verifier_cred_handle;
if (sc == NULL || sc->internal_mech == GSS_C_NO_OID) {
+ /* Process an initial token or request for NegHints. */
if (src_name != NULL)
*src_name = GSS_C_NO_NAME;
if (mech_type != NULL)
ret = GSS_S_CONTINUE_NEEDED;
}
} else {
- /* Can set negState to ACCEPT_INCOMPLETE */
+ /* Process a response token. Can set negState to
+ * ACCEPT_INCOMPLETE. */
ret = acc_ctx_cont(minor_status, input_token,
context_handle, &mechtok_in,
&mic_in, &negState, &return_token);
goto cleanup;
ret = GSS_S_CONTINUE_NEEDED;
}
+
+ /* Step 2: invoke the negotiated mechanism's gss_accept_sec_context
+ * function. */
sc = (spnego_gss_ctx_id_t)*context_handle;
/*
* Handle mechtok_in and mic_in only if they are
} else if (negState == REQUEST_MIC) {
mechstat = GSS_S_CONTINUE_NEEDED;
}
+
+ /* Step 3: process or generate the MIC, if the negotiated mech is
+ * complete and supports MICs. */
if (!HARD_ERROR(ret) && sc->mech_complete &&
(sc->ctx_flags & GSS_C_INTEG_FLAG)) {