Example #1
0
int
_gsasl_kerberos_v5_client_step (Gsasl_session * sctx,
				void *mech_data,
				const char *input,
				size_t input_len,
				char *output, size_t * output_len)
{
  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
  Gsasl_client_callback_authentication_id cb_authentication_id;
  Gsasl_client_callback_authorization_id cb_authorization_id;
  Gsasl_client_callback_qop cb_qop;
  Gsasl_client_callback_realm cb_realm;
  Gsasl_client_callback_password cb_password;
  Gsasl_client_callback_service cb_service;
  Gsasl_client_callback_maxbuf cb_maxbuf;
  Gsasl_ctx *ctx;
  int res;
  int len;

  ctx = gsasl_client_ctx_get (sctx);
  if (ctx == NULL)
    return GSASL_CANNOT_GET_CTX;

  /* These are optional */
  cb_realm = gsasl_client_callback_realm_get (ctx);
  cb_service = gsasl_client_callback_service_get (ctx);
  cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
  cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
  cb_qop = gsasl_client_callback_qop_get (ctx);
  cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);

  /* Only optionally needed in infrastructure mode */
  cb_password = gsasl_client_callback_password_get (ctx);
  if (cb_password == NULL)
    return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;

  /* I think we really need this one */
  cb_service = gsasl_client_callback_service_get (ctx);
  if (cb_service == NULL)
    return GSASL_NEED_CLIENT_SERVICE_CALLBACK;

  switch (state->step)
    {
    case STEP_FIRST:
      if (input == NULL)
	{
	  *output_len = 0;
	  return GSASL_NEEDS_MORE;
	}

      if (input_len != SERVER_HELLO_LEN)
	return GSASL_MECHANISM_PARSE_ERROR;

      memcpy (state->serverhello, input, input_len);

      {
	unsigned char serverbitmap;

	memcpy (&serverbitmap, input, BITMAP_LEN);
	state->serverqops = 0;
	if (serverbitmap & GSASL_QOP_AUTH)
	  state->serverqops |= GSASL_QOP_AUTH;
	if (serverbitmap & GSASL_QOP_AUTH_INT)
	  state->serverqops |= GSASL_QOP_AUTH_INT;
	if (serverbitmap & GSASL_QOP_AUTH_CONF)
	  state->serverqops |= GSASL_QOP_AUTH_CONF;
	if (serverbitmap & MUTUAL)
	  state->servermutual = 1;
      }
      memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
      state->servermaxbuf = ntohl (state->servermaxbuf);

      if (cb_qop)
	state->clientqop = cb_qop (sctx, state->serverqops);

      if (!(state->serverqops & state->clientqop &
	    (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF)))
	return GSASL_AUTHENTICATION_ERROR;

      /* XXX for now we require server authentication */
      if (!state->servermutual)
	return GSASL_AUTHENTICATION_ERROR;

      /* Decide policy here: non-infrastructure, infrastructure or proxy.
       *
       * A callback to decide should be added, but without the default
       * should be:
       *
       * IF shishi_tktset_get_for_server() THEN
       *    INFRASTRUCTURE MODE
       * ELSE IF shishi_realm_for_server(server) THEN
       *    PROXY INFRASTRUCTURE (then fallback to NIM?)
       * ELSE
       *    NON-INFRASTRUCTURE MODE
       */
      state->step = STEP_NONINFRA_SEND_APREQ;	/* only NIM for now.. */
      /* fall through */

    case STEP_NONINFRA_SEND_ASREQ:
      res = shishi_as (state->sh, &state->as);
      if (res)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      if (cb_authentication_id)	/* Shishi defaults to one otherwise */
	{
	  len = *output_len - 1;
	  res = cb_authentication_id (sctx, output, &len);
	  if (res != GSASL_OK)
	    return res;
	  output[len] = '\0';

	  res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as),
					 SHISHI_NT_UNKNOWN, output);
	  if (res != GSASL_OK)
	    return res;
	}

      if (cb_realm)
	{
	  len = *output_len - 1;
	  res = cb_realm (sctx, output, &len);
	  if (res != GSASL_OK)
	    return res;
	}
      else
	len = 0;

      output[len] = '\0';
      res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as),
				     output);
      if (res != GSASL_OK)
	return res;

      if (cb_service)
	{
	  char *sname[3];
	  size_t servicelen = 0;
	  size_t hostnamelen = 0;

	  res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen,
			    /* XXX support servicename a'la DIGEST-MD5 too? */
			    NULL, NULL);
	  if (res != GSASL_OK)
	    return res;

	  if (*output_len < servicelen + 1 + hostnamelen + 1)
	    return GSASL_TOO_SMALL_BUFFER;

	  sname[0] = &output[0];
	  sname[1] = &output[servicelen + 2];
	  sname[2] = NULL;

	  res = cb_service (sctx, sname[0], &servicelen,
			    sname[1], &hostnamelen, NULL, NULL);
	  if (res != GSASL_OK)
	    return res;

	  sname[0][servicelen] = '\0';
	  sname[1][hostnamelen] = '\0';

	  res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as),
					 SHISHI_NT_UNKNOWN, sname);
	  if (res != GSASL_OK)
	    return res;
	}

      /* XXX query application for encryption types and set the etype
         field?  Already configured by shishi though... */

      res = shishi_a2d (state->sh, shishi_as_req (state->as),
			output, output_len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      state->step = STEP_NONINFRA_WAIT_ASREP;

      res = GSASL_NEEDS_MORE;
      break;

    case STEP_NONINFRA_WAIT_ASREP:
      if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK)
	return GSASL_MECHANISM_PARSE_ERROR;

      /* XXX? password stored in callee's output buffer */
      len = *output_len - 1;
      res = cb_password (sctx, output, &len);
      if (res != GSASL_OK && res != GSASL_NEEDS_MORE)
	return res;
      output[len] = '\0';

      res = shishi_as_rep_process (state->as, NULL, output);
      if (res != SHISHI_OK)
	return GSASL_AUTHENTICATION_ERROR;

      state->step = STEP_NONINFRA_SEND_APREQ;
      /* fall through */

    case STEP_NONINFRA_SEND_APREQ:
      if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
	return GSASL_TOO_SMALL_BUFFER;

      if (!(state->clientqop & ~GSASL_QOP_AUTH))
	state->clientmaxbuf = 0;
      else if (cb_maxbuf)
	state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf);
      else
	state->clientmaxbuf = MAXBUF_DEFAULT;

      /* XXX for now we require server authentication */
      output[0] = state->clientqop | MUTUAL;
      {
	uint32_t tmp;

	tmp = ntohl (state->clientmaxbuf);
	memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN);
      }
      memcpy (&output[CLIENT_HELLO_LEN], state->serverhello,
	      SERVER_HELLO_LEN);

      if (cb_authorization_id)
	{
	  len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
	  res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN +
						   SERVER_HELLO_LEN], &len);
	}
      else
	len = 0;

      len += CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
      res = shishi_ap_tktoptionsdata (state->sh,
				      &state->ap,
				      shishi_as_tkt (state->as),
				      SHISHI_APOPTIONS_MUTUAL_REQUIRED,
				      output, len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      res = shishi_authenticator_add_authorizationdata
	(state->sh, shishi_ap_authenticator (state->ap), -1, output, len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      /* XXX set realm in AP-REQ and Authenticator */

      res = shishi_ap_req_der (state->ap, output, output_len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      state->step = STEP_NONINFRA_WAIT_APREP;

      res = GSASL_NEEDS_MORE;
      break;

    case STEP_NONINFRA_WAIT_APREP:
      if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK)
	return GSASL_MECHANISM_PARSE_ERROR;

      res = shishi_ap_rep_verify (state->ap);
      if (res != SHISHI_OK)
	return GSASL_AUTHENTICATION_ERROR;

      state->step = STEP_SUCCESS;

      /* XXX support AP session keys */
      state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as));

      *output_len = 0;
      res = GSASL_OK;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
Example #2
0
void
test (Shishi * handle)
{
  Shishi_asn1 a;
  char *p, *buf, *buf2;
  int res;
  size_t n, m;
  int32_t t;
  uint32_t s;

  /* shishi_authenticator */
  a = shishi_authenticator (handle);
  if (debug)
    printf ("shishi_authenticator () => `%p'.\n", a);
  if (a)
    success ("shishi_authenticator() OK\n");
  else
    fail ("shishi_authenticator() failed\n");

  if (debug)
    shishi_authenticator_print (handle, stdout, a);

  res = shishi_authenticator_remove_subkey (handle, a);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_remove_subkey() OK\n");
  else
    fail ("shishi_authenticator_remove_subkey() failed\n");

  /* shishi_authenticator_seqnumber_get */
  res = shishi_authenticator_seqnumber_get (handle, a, &s);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_seqnumber_get() OK\n");
  else
    fail ("shishi_authenticator_seqnumber_get() failed\n");

  /* shishi_authenticator_seqnumber_set */
  res = shishi_authenticator_seqnumber_set (handle, a, 42);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_seqnumber_set() OK\n");
  else
    fail ("shishi_authenticator_seqnumber_set() failed\n");

  /* shishi_authenticator_seqnumber_get */
  res = shishi_authenticator_seqnumber_get (handle, a, &s);
  if (res == SHISHI_OK && s == 42)
    success ("shishi_authenticator_seqnumber_get() OK\n");
  else
    fail ("shishi_authenticator_seqnumber_get() failed\n");

  /* shishi_authenticator_seqnumber_remove */
  res = shishi_authenticator_seqnumber_remove (handle, a);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_seqnumber_remove() OK\n");
  else
    fail ("shishi_authenticator_seqnumber_remove() failed\n");

  /* shishi_authenticator_set_crealm */
  res = shishi_authenticator_set_crealm (handle, a, "foo");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_set_crealm() OK\n");
  else
    fail ("shishi_authenticator_set_crealm() failed\n");

  /* shishi_authenticator_client_set */
  res = shishi_authenticator_client_set (handle, a, "foo/bar/baz");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_client_set() OK\n");
  else
    fail ("shishi_authenticator_client_set() failed\n");

  /* shishi_authenticator_client */
  res = shishi_authenticator_client (handle, a, &buf, &n);
  if (debug)
    escapeprint (buf, n);
  if (res == SHISHI_OK &&
      n == strlen ("foo/bar/baz") && memcmp (buf, "foo/bar/baz", n) == 0)
    success ("shishi_authenticator_client() OK\n");
  else
    fail ("shishi_authenticator_client() failed\n");
  if (res == SHISHI_OK)
    free (buf);

  /* shishi_authenticator_client_set */
  res = shishi_authenticator_client_set (handle, a, "foo");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_client_set() OK\n");
  else
    fail ("shishi_authenticator_client_set() failed\n");

  /* shishi_authenticator_client */
  res = shishi_authenticator_client (handle, a, &buf, &n);
  if (debug)
    escapeprint (buf, n);
  if (res == SHISHI_OK && n == strlen ("foo") && memcmp (buf, "foo", n) == 0)
    success ("shishi_authenticator_client() OK\n");
  else
    fail ("shishi_authenticator_client() failed\n");
  if (res == SHISHI_OK)
    free (buf);

  /* shishi_authenticator_set_crealm */
  res = shishi_authenticator_set_crealm (handle, a, "bar");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_set_crealm() OK\n");
  else
    fail ("shishi_authenticator_set_crealm() failed\n");

  /* shishi_authenticator_clientrealm */
  res = shishi_authenticator_clientrealm (handle, a, &buf, &n);
  if (debug)
    escapeprint (buf, n);
  if (res == SHISHI_OK &&
      n == strlen ("foo@bar") && memcmp (buf, "foo@bar", n) == 0)
    success ("shishi_authenticator_clientrealm() OK\n");
  else
    fail ("shishi_authenticator_clientrealm() failed\n");
  if (res == SHISHI_OK)
    free (buf);

  /* shishi_authenticator_add_authorizationdata */
  res = shishi_authenticator_add_authorizationdata (handle, a, 42, "baz", 3);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_add_authorizationdata() OK\n");
  else
    fail ("shishi_authenticator_add_authorizationdata() failed\n");

  /* shishi_authenticator_authorizationdata */
  res = shishi_authenticator_authorizationdata (handle, a, &t, &buf, &m, 1);
  if (debug)
    escapeprint (buf, m);
  if (res == SHISHI_OK && t == 42 && m == 3 && memcmp (buf, "baz", 3) == 0)
    success ("shishi_authenticator_authorizationdata() OK\n");
  else
    fail ("shishi_authenticator_authorizationdata() failed\n");
  if (res == SHISHI_OK)
    free (buf);

  /* shishi_authenticator_authorizationdata */
  res = shishi_authenticator_authorizationdata (handle, a, &t, &buf, &m, 2);
  if (res == SHISHI_OK)
    free (buf);
  if (res == SHISHI_OUT_OF_RANGE)
    success ("shishi_authenticator_authorizationdata() OK\n");
  else
    fail ("shishi_authenticator_authorizationdata() failed\n");

  /* shishi_authenticator_remove_cksum */
  res = shishi_authenticator_remove_cksum (handle, a);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_remove_cksum() OK\n");
  else
    fail ("shishi_authenticator_remove_cksum() failed\n");

  /* shishi_asn1_to_der */
  res = shishi_asn1_to_der (handle, a, &buf, &n);
  if (res == SHISHI_OK)
    success ("shishi_asn1_to_der() OK\n");
  else
    n = 0, fail ("shishi_asn1_to_der() failed\n");

  /* shishi_authenticator_to_file */
  res = shishi_authenticator_to_file (handle, a, SHISHI_FILETYPE_TEXT,
				      "authenticator.tmp");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_to_file() OK\n");
  else
    fail ("shishi_authenticator_to_file() failed\n");

  /* shishi_asn1_done */
  shishi_asn1_done (handle, a);
  success ("shishi_asn1_done() OK\n");

  a = NULL;

  /* shishi_authenticator_from_file */
  res = shishi_authenticator_from_file (handle, &a, SHISHI_FILETYPE_TEXT,
					"authenticator.tmp");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_from_file() OK\n");
  else
    fail ("shishi_authenticator_from_file() failed\n");

  if (debug)
    {
      /* shishi_authenticator_print */
      res = shishi_authenticator_print (handle, stdout, a);
      if (res == SHISHI_OK)
	success ("shishi_authenticator_print() OK\n");
      else
	fail ("shishi_authenticator_print() failed\n");
    }

  /* shishi_asn1_to_der */
  res = shishi_asn1_to_der (handle, a, &buf2, &m);
  if (res == SHISHI_OK)
    success ("shishi_asn1_to_der() OK\n");
  else
    n = 0, fail ("shishi_asn1_to_der() failed\n");

  /* Compare DER encodings of authenticators */
  if (n > 0 && m > 0 && n == m && memcmp (buf, buf2, n) == 0)
    success ("DER comparison OK\n");
  else
    fail ("DER comparison failed\n");

  free (buf);
  free (buf2);

  /* shishi_authenticator_cusec_set */
  res = shishi_authenticator_cusec_set (handle, a, 4711);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_cusec_set() OK\n");
  else
    fail ("shishi_authenticator_cusec_set() failed\n");

  /* shishi_authenticator_cusec_get */
  res = shishi_authenticator_cusec_get (handle, a, &s);
  if (debug)
    printf ("shishi_authenticator_cusec_get () => `%d'.\n", t);
  if (res == SHISHI_OK && s == 4711)
    success ("shishi_authenticator_cusec_get() OK\n");
  else
    fail ("shishi_authenticator_cusec_get() failed\n");

  /* shishi_authenticator_ctime_set */
  res = shishi_authenticator_ctime_set (handle, a, "19700101011831Z");
  if (res == SHISHI_OK)
    success ("shishi_authenticator_ctime_set() OK\n");
  else
    fail ("shishi_authenticator_ctime_set() failed\n");

  /* shishi_authenticator_ctime */
  res = shishi_authenticator_ctime (handle, a, &p);
  if (debug)
    escapeprint (p, strlen (p));
  if (res == SHISHI_OK && memcmp (p, "19700101011831Z", 15) == 0)
    success ("shishi_authenticator_ctime() OK\n");
  else
    fail ("shishi_authenticator_ctime() failed\n");
  if (res == SHISHI_OK)
    free (p);

  /* shishi_asn1_to_der */
  res = shishi_asn1_to_der (handle, a, &buf, &n);
  if (res == SHISHI_OK)
    success ("shishi_asn1_to_der() OK\n");
  else
    n = 0, fail ("shishi_asn1_to_der() failed\n");
  if (debug)
    {
      shishi_authenticator_print (handle, stdout, a);
      hexprint (buf, n);
      puts ("");
      hexprint (authenticator, sizeof (authenticator));
      puts ("");
    }
  if (n == sizeof (authenticator) &&
      n == AUTHENTICATOR_LEN && memcmp (authenticator, buf, n) == 0)
    success ("DER comparison OK\n");
  else
    fail ("DER comparison failed\n");

  free (buf);

  /* shishi_authenticator_clear_authorizationdata */
  res = shishi_authenticator_clear_authorizationdata (handle, a);
  if (res == SHISHI_OK)
    success ("shishi_authenticator_clear_authorizationdata() OK\n");
  else
    fail ("shishi_authenticator_clear_authorizationdata() failed\n");

  /* shishi_asn1_to_der */
  res = shishi_asn1_to_der (handle, a, &buf, &n);
  if (res == SHISHI_OK)
    success ("shishi_asn1_to_der() OK\n");
  else
    n = 0, fail ("shishi_asn1_to_der() failed\n");
  if (debug)
    {
      shishi_authenticator_print (handle, stdout, a);
      hexprint (buf, n);
      puts ("");
      hexprint (authenticator2, sizeof (authenticator2));
      puts ("");
    }
  if (n == sizeof (authenticator2) &&
      n == AUTHENTICATOR2_LEN && memcmp (authenticator2, buf, n) == 0)
    success ("DER comparison OK\n");
  else
    fail ("DER comparison failed\n");

  free (buf);

  /* unlink */
  res = unlink ("authenticator.tmp");
  if (res == 0)
    success ("unlink() OK\n");
  else
    fail ("unlink() failed\n");

  /* shishi_asn1_done */
  shishi_asn1_done (handle, a);
  success ("shishi_asn1_done() OK\n");
}