예제 #1
0
파일: context.c 프로젝트: dezelin/maily
/* Reply part of gss_krb5_init_sec_context.  Assumes that
   context_handle is valid, and has krb5 specific structure, and that
   output_token is valid and cleared. */
static OM_uint32
init_reply (OM_uint32 * minor_status,
            const gss_cred_id_t initiator_cred_handle,
            gss_ctx_id_t * context_handle,
            const gss_name_t target_name,
            const gss_OID mech_type,
            OM_uint32 req_flags,
            OM_uint32 time_req,
            const gss_channel_bindings_t input_chan_bindings,
            const gss_buffer_t input_token,
            gss_OID * actual_mech_type,
            gss_buffer_t output_token,
            OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
    gss_ctx_id_t ctx = *context_handle;
    _gss_krb5_ctx_t k5 = ctx->krb5;
    char *data;
    size_t datalen;
    int rc;

    if (!gss_decapsulate_token (input_token, GSS_KRB5, &data, &datalen))
        return GSS_S_DEFECTIVE_TOKEN;

    if (datalen < TOK_LEN)
        return GSS_S_DEFECTIVE_TOKEN;

    if (memcmp (data, TOK_AP_REP, TOK_LEN) != 0)
        return GSS_S_DEFECTIVE_TOKEN;

    rc = shishi_ap_rep_der_set (k5->ap, data + TOK_LEN, datalen - TOK_LEN);
    if (rc != SHISHI_OK)
        return GSS_S_DEFECTIVE_TOKEN;

    rc = shishi_ap_rep_verify (k5->ap);
    if (rc != SHISHI_OK)
        return GSS_S_DEFECTIVE_TOKEN;

    rc = shishi_encapreppart_seqnumber_get (k5->sh,
                                            shishi_ap_encapreppart (k5->ap),
                                            &k5->acceptseqnr);
    if (rc != SHISHI_OK)
    {
        /* A strict 1964 implementation would return
           GSS_S_DEFECTIVE_TOKEN here.  gssapi-cfx permit absent
           sequence number, though. */
        k5->acceptseqnr = 0;
    }

    return GSS_S_COMPLETE;
}
예제 #2
0
파일: client.c 프로젝트: dezelin/maily
/* Copy token to output buffer.  On first round trip, strip context
   token header and add channel binding data. For later round trips,
   just copy the buffer.  Return GSASL_OK on success or an error
   code.  */
static int
token2output (Gsasl_session * sctx,
	      _gsasl_gs2_client_state * state,
	      const gss_buffer_t token, char **output, size_t * output_len)
{
  OM_uint32 maj_stat, min_stat;
  gss_buffer_desc bufdesc;

  if (state->step == 1)
    {
      state->step++;

      maj_stat = gss_decapsulate_token (token, state->mech_oid, &bufdesc);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_ENCAPSULATE_TOKEN_ERROR;

      *output_len = state->cb.application_data.length + bufdesc.length;
      *output = malloc (*output_len);
      if (!*output)
	{
	  gss_release_buffer (&min_stat, &bufdesc);
	  return GSASL_MALLOC_ERROR;
	}

      memcpy (*output, state->cb.application_data.value,
	      state->cb.application_data.length);
      memcpy (*output + state->cb.application_data.length,
	      bufdesc.value, bufdesc.length);

      maj_stat = gss_release_buffer (&min_stat, &bufdesc);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
    }
  else
    {
      *output_len = token->length;
      *output = malloc (*output_len);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, token->value, token->length);
    }

  return GSASL_OK;
}
예제 #3
0
static OM_uint32 GSSAPI_CALLCONV
acceptor_start
	   (OM_uint32 * minor_status,
	    gss_ctx_id_t * context_handle,
	    const gss_cred_id_t acceptor_cred_handle,
	    const gss_buffer_t input_token_buffer,
	    const gss_channel_bindings_t input_chan_bindings,
	    gss_name_t * src_name,
	    gss_OID * mech_type,
	    gss_buffer_t output_token,
	    OM_uint32 * ret_flags,
	    OM_uint32 * time_rec,
	    gss_cred_id_t *delegated_cred_handle
	   )
{
    OM_uint32 ret, junk;
    NegotiationToken nt;
    size_t nt_len;
    NegTokenInit *ni;
    int i;
    gss_buffer_desc data;
    gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
    gss_buffer_desc mech_output_token;
    gss_buffer_desc mech_buf;
    gss_OID preferred_mech_type = GSS_C_NO_OID;
    gssspnego_ctx ctx;
    int get_mic = 0;
    int first_ok = 0;

    mech_output_token.value = NULL;
    mech_output_token.length = 0;
    mech_buf.value = NULL;

    if (input_token_buffer->length == 0)
	return send_supported_mechs (minor_status, output_token);
	
    ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
    if (ret != GSS_S_COMPLETE)
	return ret;

    ctx = (gssspnego_ctx)*context_handle;

    /*
     * The GSS-API encapsulation is only present on the initial
     * context token (negTokenInit).
     */
    ret = gss_decapsulate_token (input_token_buffer,
				 GSS_SPNEGO_MECHANISM,
				 &data);
    if (ret)
	return ret;

    ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len);
    gss_release_buffer(minor_status, &data);
    if (ret) {
	*minor_status = ret;
	return GSS_S_DEFECTIVE_TOKEN;
    }
    if (nt.element != choice_NegotiationToken_negTokenInit) {
	*minor_status = 0;
	return GSS_S_DEFECTIVE_TOKEN;
    }
    ni = &nt.u.negTokenInit;

    if (ni->mechTypes.len < 1) {
	free_NegotiationToken(&nt);
	*minor_status = 0;
	return GSS_S_DEFECTIVE_TOKEN;
    }

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types);
    if (ret) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	free_NegotiationToken(&nt);
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    /*
     * First we try the opportunistic token if we have support for it,
     * don't try to verify we have credential for the token,
     * gss_accept_sec_context() will (hopefully) tell us that.
     * If that failes,
     */

    ret = select_mech(minor_status,
		      &ni->mechTypes.val[0],
		      0,
		      &preferred_mech_type);

    if (ret == 0 && ni->mechToken != NULL) {
	gss_buffer_desc ibuf;

	ibuf.length = ni->mechToken->length;
	ibuf.value = ni->mechToken->data;
	mech_input_token = &ibuf;

	if (ctx->mech_src_name != GSS_C_NO_NAME)
	    gss_release_name(&junk, &ctx->mech_src_name);
	
	ret = gss_accept_sec_context(minor_status,
				     &ctx->negotiated_ctx_id,
				     acceptor_cred_handle,
				     mech_input_token,
				     input_chan_bindings,
				     &ctx->mech_src_name,
				     &ctx->negotiated_mech_type,
				     &mech_output_token,
				     &ctx->mech_flags,
				     &ctx->mech_time_rec,
				     delegated_cred_handle);

	if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
	    ctx->preferred_mech_type = preferred_mech_type;
	    if (ret == GSS_S_COMPLETE)
		ctx->open = 1;

	    ret = acceptor_complete(minor_status,
				    ctx,
				    &get_mic,
				    &mech_buf,
				    mech_input_token,
				    &mech_output_token,
				    ni->mechListMIC,
				    output_token);
	    if (ret != GSS_S_COMPLETE)
		goto out;

	    first_ok = 1;
	} else {
	    gss_mg_collect_error(preferred_mech_type, ret, *minor_status);
	}
    }

    /*
     * If opportunistic token failed, lets try the other mechs.
     */

    if (!first_ok && ni->mechToken != NULL) {

	preferred_mech_type = GSS_C_NO_OID;

	/* Call glue layer to find first mech we support */
	for (i = 1; i < ni->mechTypes.len; ++i) {
	    ret = select_mech(minor_status,
			      &ni->mechTypes.val[i],
			      1,
			      &preferred_mech_type);
	    if (ret == 0)
		break;
	}
	if (preferred_mech_type == GSS_C_NO_OID) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegotiationToken(&nt);
	    return ret;
	}

	ctx->preferred_mech_type = preferred_mech_type;
    }

    /*
     * The initial token always have a response
     */

    ret = send_accept (minor_status,
		       ctx,
		       &mech_output_token,
		       1,
		       get_mic ? &mech_buf : NULL,
		       output_token);
    if (ret)
	goto out;

out:
    if (mech_output_token.value != NULL)
	gss_release_buffer(&junk, &mech_output_token);
    if (mech_buf.value != NULL) {
	free(mech_buf.value);
	mech_buf.value = NULL;
    }
    free_NegotiationToken(&nt);


    if (ret == GSS_S_COMPLETE) {
	if (src_name != NULL && ctx->mech_src_name != NULL) {
	    spnego_name name;

	    name = calloc(1, sizeof(*name));
	    if (name) {
		name->mech = ctx->mech_src_name;
		ctx->mech_src_name = NULL;
		*src_name = (gss_name_t)name;
	    }
	}
    }

    if (mech_type != NULL)
	*mech_type = ctx->negotiated_mech_type;
    if (ret_flags != NULL)
	*ret_flags = ctx->mech_flags;
    if (time_rec != NULL)
	*time_rec = ctx->mech_time_rec;

    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 	return ret;
    }

    _gss_spnego_internal_delete_sec_context(&junk, context_handle,
					    GSS_C_NO_BUFFER);

    return ret;
}
예제 #4
0
파일: context.c 프로젝트: dezelin/maily
/* Allows a remotely initiated security context between the
   application and a remote peer to be established, using krb5.
   Assumes context_handle is valid. */
OM_uint32
gss_krb5_accept_sec_context (OM_uint32 * minor_status,
                             gss_ctx_id_t * context_handle,
                             const gss_cred_id_t acceptor_cred_handle,
                             const gss_buffer_t input_token_buffer,
                             const gss_channel_bindings_t input_chan_bindings,
                             gss_name_t * src_name,
                             gss_OID * mech_type,
                             gss_buffer_t output_token,
                             OM_uint32 * ret_flags,
                             OM_uint32 * time_rec,
                             gss_cred_id_t * delegated_cred_handle)
{
    gss_buffer_desc data;
    char *in;
    size_t inlen;
    gss_ctx_id_t cx;
    _gss_krb5_ctx_t cxk5;
    _gss_krb5_cred_t crk5;
    int rc;

    if (minor_status)
        *minor_status = 0;

    if (ret_flags)
        *ret_flags = 0;

    if (!acceptor_cred_handle)
        /* XXX support GSS_C_NO_CREDENTIAL: acquire_cred() default server */
        return GSS_S_NO_CRED;

    if (*context_handle)
        return GSS_S_FAILURE;

    crk5 = acceptor_cred_handle->krb5;

    cx = calloc (sizeof (*cx), 1);
    if (!cx)
    {
        if (minor_status)
            *minor_status = ENOMEM;
        return GSS_S_FAILURE;
    }

    cxk5 = calloc (sizeof (*cxk5), 1);
    if (!cxk5)
    {
        free (cx);
        if (minor_status)
            *minor_status = ENOMEM;
        return GSS_S_FAILURE;
    }

    cx->mech = GSS_KRB5;
    cx->krb5 = cxk5;
    /* XXX cx->peer?? */
    *context_handle = cx;

    cxk5->sh = crk5->sh;
    cxk5->key = crk5->key;
    cxk5->acceptor = 1;

    rc = shishi_ap (cxk5->sh, &cxk5->ap);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    rc = gss_decapsulate_token (input_token_buffer, GSS_KRB5, &in, &inlen);
    if (!rc)
        return GSS_S_BAD_MIC;

    if (inlen < TOK_LEN)
        return GSS_S_BAD_MIC;

    if (memcmp (in, TOK_AP_REQ, TOK_LEN) != 0)
        return GSS_S_BAD_MIC;

    rc = shishi_ap_req_der_set (cxk5->ap, in + TOK_LEN, inlen - TOK_LEN);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    rc = shishi_ap_req_process (cxk5->ap, crk5->key);
    if (rc != SHISHI_OK)
    {
        if (minor_status)
            *minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
        return GSS_S_FAILURE;
    }

    rc = shishi_authenticator_seqnumber_get (cxk5->sh,
            shishi_ap_authenticator (cxk5->ap),
            &cxk5->initseqnr);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    rc = _gss_krb5_checksum_parse (minor_status,
                                   context_handle,
                                   input_chan_bindings);
    if (rc != GSS_S_COMPLETE)
        return GSS_S_FAILURE;

    cxk5->tkt = shishi_ap_tkt (cxk5->ap);
    cxk5->key = shishi_ap_key (cxk5->ap);

    if (shishi_apreq_mutual_required_p (crk5->sh, shishi_ap_req (cxk5->ap)))
    {
        Shishi_asn1 aprep;

        rc = shishi_ap_rep_asn1 (cxk5->ap, &aprep);
        if (rc != SHISHI_OK)
        {
            printf ("Error creating AP-REP: %s\n", shishi_strerror (rc));
            return GSS_S_FAILURE;
        }

        rc = shishi_encapreppart_seqnumber_get (cxk5->sh,
                                                shishi_ap_encapreppart (cxk5->
                                                        ap),
                                                &cxk5->acceptseqnr);
        if (rc != SHISHI_OK)
        {
            /* A strict 1964 implementation would return
               GSS_S_DEFECTIVE_TOKEN here.  gssapi-cfx permit absent
               sequence number, though. */
            cxk5->acceptseqnr = 0;
        }

        {
            char *der;
            size_t len;

            rc = shishi_asn1_to_der (crk5->sh, aprep, &der, &len);
            if (rc != SHISHI_OK)
            {
                printf ("Error der encoding aprep: %s\n", shishi_strerror (rc));
                return GSS_S_FAILURE;
            }
            data.value = der;
            data.length = len;
        }

        rc = gss_encapsulate_token_prefix (&data, TOK_AP_REP, TOK_LEN,
                                           GSS_KRB5, output_token);
        if (!rc)
            return GSS_S_FAILURE;

        if (ret_flags)
            *ret_flags = GSS_C_MUTUAL_FLAG;
    }
    else
    {
        output_token->value = NULL;
        output_token->length = 0;
    }

    if (src_name)
    {
        gss_name_t p;

        p = malloc (sizeof (*p));
        if (!p)
        {
            if (minor_status)
                *minor_status = ENOMEM;
            return GSS_S_FAILURE;
        }

        rc = shishi_encticketpart_client (cxk5->sh,
                                          shishi_tkt_encticketpart (cxk5->tkt),
                                          &p->value, &p->length);
        if (rc != SHISHI_OK)
            return GSS_S_FAILURE;

        p->type = GSS_KRB5_NT_PRINCIPAL_NAME;

        *src_name = p;
    }

    /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
       it anyway. */
    if (ret_flags)
        *ret_flags |= GSS_C_PROT_READY_FLAG;

    if (minor_status)
        *minor_status = 0;
    return GSS_S_COMPLETE;
}
static int
test_scram(const char *test_name, const char *user, const char *password)
{
    gss_name_t cname, target = GSS_C_NO_NAME;
    OM_uint32 maj_stat, min_stat;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    gss_buffer_desc cn, input, output, output2;
    int ret;
    heim_scram *scram = NULL;
    heim_scram_data in, out;
    gss_auth_identity_desc identity;


    memset(&identity, 0, sizeof(identity));

    identity.username = rk_UNCONST(user);
    identity.realm = "";
    identity.password = rk_UNCONST(password);

    cn.value = rk_UNCONST(user);
    cn.length = strlen(user);

    maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
    if (maj_stat)
	errx(1, "gss_import_name: %d", (int)maj_stat);

    maj_stat = gss_acquire_cred_ex_f(NULL,
				     cname,
				     0,
				     GSS_C_INDEFINITE,
				     GSS_SCRAM_MECHANISM,
				     GSS_C_INITIATE,
				     &identity,
				     NULL,
				     ac_complete);
    if (maj_stat)
	errx(1, "gss_acquire_cred_ex_f: %d", (int)maj_stat);

    if (client_cred == GSS_C_NO_CREDENTIAL)
	errx(1, "gss_acquire_cred_ex_f");

    cn.value = rk_UNCONST("host@localhost");
    cn.length = strlen((char *)cn.value);

    maj_stat = gss_import_name(&min_stat, &cn,
			       GSS_C_NT_HOSTBASED_SERVICE, &target);
    if (maj_stat)
	errx(1, "gss_import_name: %d", (int)maj_stat);

    maj_stat = gss_init_sec_context(&min_stat, client_cred, &ctx, 
				    target, GSS_SCRAM_MECHANISM, 
				    0, 0, NULL,
				    GSS_C_NO_BUFFER, NULL, 
				    &output, NULL, NULL); 
    if (maj_stat != GSS_S_CONTINUE_NEEDED)
	errx(1, "accept_sec_context %s %s", test_name,
	      gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));

    if (output.length == 0)
	errx(1, "output.length == 0");

    maj_stat = gss_decapsulate_token(&output, GSS_SCRAM_MECHANISM, &output2);
    if (maj_stat)
	errx(1, "decapsulate token");

    in.length = output2.length;
    in.data = output2.value;

    ret = heim_scram_server1(&in, NULL, HEIM_SCRAM_DIGEST_SHA1, &server_proc, NULL, &scram, &out);
    if (ret)
	errx(1, "heim_scram_server1");

    gss_release_buffer(&min_stat, &output);

    input.length = out.length;
    input.value = out.data;

    maj_stat = gss_init_sec_context(&min_stat, client_cred, &ctx,
				    target, GSS_SCRAM_MECHANISM,
				    0, 0, NULL,
				    &input, NULL,
				    &output, NULL, NULL);
    if (maj_stat != GSS_S_CONTINUE_NEEDED) {
	warnx("accept_sec_context v1 2 %s",
	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
	return 1;
    }

    in.length = output.length;
    in.data = output.value;

    ret = heim_scram_server2(&in, scram, &out);
    if (ret)
	errx(1, "heim_scram_server2");

    gss_release_buffer(&min_stat, &output);

    input.length = out.length;
    input.value = out.data;

    maj_stat = gss_init_sec_context(&min_stat, client_cred, &ctx, 
				    target, GSS_SCRAM_MECHANISM, 
				    0, 0, NULL,
				    &input, NULL, 
				    &output, NULL, NULL); 
    if (maj_stat != GSS_S_COMPLETE) {
	warnx("accept_sec_context v1 2 %s",
	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
	return 1;
    }

    heim_scram_free(scram);

    //gss_destroy_cred(NULL, &client_cred);

    printf("done: %s\n", test_name);

    return 0;
}