Beispiel #1
0
/**
 * shishi_tgs:
 * @handle: shishi handle as allocated by shishi_init().
 * @tgs: holds pointer to newly allocate Shishi_tgs structure.
 *
 * Allocate a new TGS exchange variable.
 *
 * Return value: Returns SHISHI_OK iff successful.
 **/
int
shishi_tgs (Shishi * handle, Shishi_tgs ** tgs)
{
  Shishi_tgs *ltgs;
  int res;

  *tgs = xcalloc (1, sizeof (**tgs));
  ltgs = *tgs;

  ltgs->handle = handle;

  ltgs->tgsreq = shishi_tgsreq (handle);
  if (ltgs->tgsreq == NULL)
    {
      shishi_error_printf (handle, "Could not create TGS-REQ: %s\n",
			   shishi_error (handle));
      return SHISHI_ASN1_ERROR;
    }

  ltgs->tgsrep = shishi_tgsrep (handle);
  if (ltgs->tgsreq == NULL)
    {
      shishi_error_printf (handle, "Could not create TGS-REP: %s\n",
			   shishi_error (handle));
      return SHISHI_ASN1_ERROR;
    }

  ltgs->krberror = shishi_krberror (handle);
  if (ltgs->krberror == NULL)
    {
      shishi_error_printf (handle, "Could not create KRB-ERROR: %s\n",
			   shishi_error (handle));
      return SHISHI_ASN1_ERROR;
    }

  res = shishi_ap_nosubkey (handle, &ltgs->ap);
  if (res != SHISHI_OK)
    return res;

  res = shishi_authenticator_remove_subkey
    (handle, shishi_ap_authenticator (ltgs->ap));
  if (res != SHISHI_OK)
    return res;

  res = shishi_tkt (handle, &ltgs->tkt);
  if (res != SHISHI_OK)
    return res;

  return SHISHI_OK;
}
Beispiel #2
0
/**
 * shishi_tgs_rep_process:
 * @tgs: structure that holds information about TGS exchange
 *
 * Process new TGS-REP and set ticket.  The key to decrypt the TGS-REP
 * is taken from the EncKDCRepPart of the TGS tgticket.
 *
 * Return value: Returns SHISHI_OK iff successful.
 **/
int
shishi_tgs_rep_process (Shishi_tgs * tgs)
{
  Shishi_asn1 kdcreppart, ticket;
  int res;

  if (VERBOSE (tgs->handle))
    printf ("Processing TGS-REQ and TGS-REP...\n");

  res = shishi_tgs_process (tgs->handle, tgs->tgsreq, tgs->tgsrep,
			    shishi_ap_authenticator (tgs->ap),
			    shishi_tkt_enckdcreppart (tgs->tgtkt),
			    &kdcreppart);
  if (res != SHISHI_OK)
    {
      shishi_error_printf (tgs->handle, "Could not process TGS: %s",
			   shishi_strerror (res));
      return res;
    }

  if (VERBOSE (tgs->handle))
    printf ("Got EncKDCRepPart...\n");

  if (VERBOSEASN1 (tgs->handle))
    shishi_enckdcreppart_print (tgs->handle, stdout, kdcreppart);

  res = shishi_kdcrep_get_ticket (tgs->handle, tgs->tgsrep, &ticket);
  if (res != SHISHI_OK)
    {
      shishi_error_printf (tgs->handle,
			   "Could not extract ticket from TGS-REP: %s",
			   shishi_strerror (res));
      return res;
    }

  if (VERBOSE (tgs->handle))
    printf ("Got Ticket...\n");

  if (VERBOSEASN1 (tgs->handle))
    shishi_ticket_print (tgs->handle, stdout, ticket);

  /* XXX */
  tgs->tkt = shishi_tkt2 (tgs->handle, ticket, kdcreppart, tgs->tgsrep);

  return SHISHI_OK;
}
Beispiel #3
0
/* shishi authentication */
int
auth (Shishi * h, int verbose, const char *cname, const char *sname, int sock,
      char *cmd, char *port, Shishi_key ** enckey, Shishi_key * deckey)
{
  Shishi_ap *ap;
  Shishi_tkt *tkt;
  Shishi_tkts_hint hint;

  int rc;
  char *out;
  int outlen;
  int krb5len, msglen;
  char auth;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5sendclient[] = "KCMDV0.2";
  /* to store error msg sent by server */
  char errormsg[101];
  char cksumdata[101];

  /* size of KRB5 auth message */
  krb5len = strlen (krb5sendauth) + 1;
  msglen = htonl (krb5len);
  safewrite (sock, &msglen, sizeof (int));
  /* KRB5 authentication message */
  safewrite (sock, krb5sendauth, krb5len);
  /* size of client message */
  krb5len = strlen (krb5sendclient) + 1;
  msglen = htonl (krb5len);
  safewrite (sock, &msglen, sizeof (int));
  /* KRB5 client message */
  safewrite (sock, krb5sendclient, krb5len);

  /* get answer from server 0 = ok, 1 = error with message */
  read (sock, &auth, 1);
  if (auth)
    {
      read (sock, errormsg, 100);
      errormsg[100] = '\0';

      printf ("Error during server authentication : %s\n", errormsg);
      return 1;
    }

  if (verbose)
    {
      printf ("Client: %s\n", cname);
      printf ("Server: %s\n", sname);
    }

  /* Get a ticket for the server. */

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

  hint.client = (char *) cname;
  hint.server = (char *) sname;

  tkt = shishi_tkts_get (shishi_tkts_default (h), &hint);
  if (!tkt)
    {
      printf ("cannot find ticket for \"%s\"\n", sname);
      return 1;
    }

  if (verbose)
    shishi_tkt_pretty_print (tkt, stderr);

  /* Create Authentication context */

  rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED);
  if (rc != SHISHI_OK)
    {
      printf ("cannot create authentication context\n");
      return 1;
    }


  /* checksum = port: terminal name */

  snprintf (cksumdata, 100, "%s:%s%s", port, cmd, cname);

  /* add checksum to authenticator */

  shishi_ap_authenticator_cksumdata_set (ap, cksumdata, strlen (cksumdata));
  /* To be compatible with MIT rlogind */
  shishi_ap_authenticator_cksumtype_set (ap, SHISHI_RSA_MD5);

  /* create der encoded AP-REQ */

  rc = shishi_ap_req_der (ap, &out, &outlen);
  if (rc != SHISHI_OK)
    {
      printf ("cannot build authentication request: %s\n",
	      shishi_strerror (rc));

      return 1;
    }

  if (verbose)
    shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));

  /* extract subkey if present from ap exchange for secure connection */

  shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey);

  /* send size of AP-REQ to the server */

  msglen = htonl (outlen);
  safewrite (sock, (char *) &msglen, sizeof (int));

  /* send AP-REQ to the server */

  safewrite (sock, out, outlen);

  /* read a respond from server - what ? */

  read (sock, &auth, sizeof (int));

  /* For mutual authentication, wait for server reply. */

  if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap)))
    {
      if (verbose)
	printf ("Waiting for server to authenticate itself...\n");

      /* read size of the AP-REP */

      read (sock, (char *) &outlen, sizeof (int));

      /* read AP-REP */
      outlen = ntohl (outlen);
      outlen = read (sock, out, outlen);

      rc = shishi_ap_rep_verify_der (ap, out, outlen);
      if (rc == SHISHI_OK)
	{
	  if (verbose)
	    printf ("AP-REP verification OK...\n");
	}
      else
	{
	  if (rc == SHISHI_APREP_VERIFY_FAILED)
	    printf ("AP-REP verification failed...\n");
	  else
	    printf ("AP-REP verification error: %s\n", shishi_strerror (rc));
	  return 1;
	}

      /* The server is authenticated. */
      if (verbose)
	printf ("Server authenticated.\n");
    }

  /* We are now authenticated. */
  if (verbose)
    printf ("User authenticated.\n");

  return AUTH_OK;

}
Beispiel #4
0
static Shishi_ap *
auth (Shishi * h, int verbose, const char *cname, const char *sname)
{
  Shishi_ap *ap;
  Shishi_tkt *tkt;
  Shishi_tkts_hint hint;
  int rc;

  printf ("Client: %s\n", cname);
  printf ("Server: %s\n", sname);

  /* Get a ticket for the server. */

  memset (&hint, 0, sizeof (hint));
  hint.client = (char *) cname;
  hint.server = (char *) sname;
  tkt = shishi_tkts_get (shishi_tkts_default (h), &hint);
  if (!tkt)
    {
      printf ("cannot find ticket for \"%s\"\n", sname);
      return NULL;
    }

  if (verbose)
    shishi_tkt_pretty_print (tkt, stderr);

  /* Create Authentication context */

  rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED);
  if (rc != SHISHI_OK)
    {
      printf ("cannot create authentication context\n");
      return NULL;
    }

  /* Build Authentication request */

  rc = shishi_ap_req_build (ap);
  if (rc != SHISHI_OK)
    {
      printf ("cannot build authentication request: %s\n",
	      shishi_strerror (rc));
      return NULL;
    }

  if (verbose)
    shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));

  /* Authentication ourself to server */

  shishi_apreq_print (h, stdout, shishi_ap_req (ap));
  /* Note: to get the binary blob to send, use:
   *
   * char *out; int outlen;
   * ...
   * rc = shishi_ap_req_der (ap, &out, &outlen);
   * ...
   * write(fd, out, outlen);
   */

  /* For mutual authentication, wait for server reply. */

  if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap)))
    {
      Shishi_asn1 aprep;

      printf ("Waiting for server to authenticate itself...\n");

      rc = shishi_aprep_parse (h, stdin, &aprep);
      if (rc != SHISHI_OK)
	{
	  printf ("Cannot parse AP-REP from server: %s\n",
		  shishi_strerror (rc));
	  return NULL;
	}

      rc = shishi_ap_rep_verify_asn1 (ap, aprep);
      if (rc == SHISHI_OK)
	printf ("AP-REP verification OK...\n");
      else
	{
	  if (rc == SHISHI_APREP_VERIFY_FAILED)
	    printf ("AP-REP verification failed...\n");
	  else
	    printf ("AP-REP verification error: %s\n", shishi_strerror (rc));
	  return NULL;
	}

      /* The server is authenticated. */
      printf ("Server authenticated.\n");
    }

  /* We are now authenticated. */
  printf ("User authenticated.\n");

  return ap;
}
Beispiel #5
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;
}
Beispiel #6
0
/* Request 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_request (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 *cksum, *der;
    size_t cksumlen;
    int rc;
    OM_uint32 maj_stat;
    gss_buffer_desc tmp;
    Shishi_tkts_hint hint;

    /* Get service ticket. */
    maj_stat = gss_krb5_canonicalize_name (minor_status, target_name,
                                           GSS_C_NO_OID, &k5->peerptr);
    if (GSS_ERROR (maj_stat))
        return maj_stat;

    memset (&hint, 0, sizeof (hint));
    hint.server = k5->peerptr->value;
    hint.endtime = time_req;

    k5->tkt = shishi_tkts_get (shishi_tkts_default (k5->sh), &hint);
    if (!k5->tkt)
    {
        if (minor_status)
            *minor_status = GSS_KRB5_S_KG_CCACHE_NOMATCH;
        return GSS_S_NO_CRED;
    }

    /* Create Authenticator checksum field. */
    maj_stat = _gss_krb5_checksum_pack (minor_status, initiator_cred_handle,
                                        context_handle,
                                        input_chan_bindings, req_flags,
                                        &cksum, &cksumlen);
    if (GSS_ERROR (maj_stat))
        return maj_stat;

    /* Create AP-REQ in output_token. */
    rc = shishi_ap_tktoptionsraw (k5->sh, &k5->ap, k5->tkt,
                                  SHISHI_APOPTIONS_MUTUAL_REQUIRED,
                                  0x8003, cksum, cksumlen);
    free (cksum);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

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

    rc = shishi_ap_req_der (k5->ap, &der, &tmp.length);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    tmp.value = der;

    rc = gss_encapsulate_token_prefix (&tmp, TOK_AP_REQ, TOK_LEN,
                                       GSS_KRB5, output_token);
    free (der);
    if (!rc)
        return GSS_S_FAILURE;

    if (req_flags & GSS_C_MUTUAL_FLAG)
        return GSS_S_CONTINUE_NEEDED;

    return GSS_S_COMPLETE;
}
Beispiel #7
0
/* 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;
}
Beispiel #8
0
/* authentication, server side */
int
get_auth (int infd, krb5_context *ctx, krb5_auth_context *actx,
	  krb5_keyblock **key, const char **err_msg,
	  int *protoversion, int *cksumtype,
	  char **cksum, size_t *cksumlen, char *srvname)
{
  char *out;
  size_t outlen;
  char *buf;
  int buflen;
  int len;
  int rc;
  int error;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5kcmd1[] = "KCMDV0.1";
  char krb5kcmd2[] = "KCMDV0.2";
  char *servername, *server = NULL, *realm = NULL;

  *err_msg = NULL;
  /* Get key for the server. */

# if 0
  /*
   * XXX: Taken straight from the version for libshishi.
   * XXX: No adaptions yet.
   */
  rc = shishi_init_server (handle);
  if (rc != SHISHI_OK)
    return rc;

  if (srvname && *srvname)
    {
      rc = shishi_parse_name (*handle, srvname, &server, &realm);
      if (rc != SHISHI_OK)
	{
	  *err_msg = shishi_strerror (rc);
	  return rc;
	}
    }

  if (server && *server)
    {
      char *p;

      servername = malloc (sizeof (SERVICE) + strlen (server) + 2);
      if (!servername)
	{
	  *err_msg = "Not enough memory";
	  return SHISHI_TOO_SMALL_BUFFER;
	}

      p = strchr (server, '/');
      if (p && (p != server))
	sprintf (servername, "%s", server);	/* Non-empty prefix.  */
      else
	sprintf (servername, "%s/%s", SERVICE,
		 server + (p ? 1 : 0));	/* Remove initial slash.  */
    }
  else
    servername = shishi_server_for_local_service (*handle, SERVICE);

  if (realm && *realm)
    shishi_realm_default_set (*handle, realm);

  free (server);
  free (realm);

  /* Enable use of `~/.k5login'.  */
  if (shishi_check_version ("1.0.2"))	/* Faulty in version 1.0.1.  */
    {
      rc = shishi_cfg_authorizationtype_set (*handle, "k5login basic");
      if (rc != SHISHI_OK)
	{
	  *err_msg = shishi_error (*handle);
	  return rc;
	}
    }

  key = shishi_hostkeys_for_serverrealm (*handle, servername,
					 shishi_realm_default (*handle));
  free (servername);
  if (!key)
    {
      *err_msg = shishi_error (*handle);
      return SHISHI_INVALID_KEY;
    }

  /* Read Kerberos 5 sendauth message */
  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading message size";
      return SHISHI_IO_ERROR;
    }

  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return SHISHI_TOO_SMALL_BUFFER;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading authentication message";
      return SHISHI_IO_ERROR;
    }

  len = strlen (krb5sendauth);
  rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen);
  if (rc)
    {
      *err_msg = "Invalid authentication type";
      /* Authentication type is wrong.  */
      write (infd, "\001", 1);
      return SHISHI_VERIFY_FAILED;
    }

  free (buf);

  /* Read protocol version */
  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading protocol message size";
      return SHISHI_IO_ERROR;
    }
  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return SHISHI_TOO_SMALL_BUFFER;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading protocol message";
      return SHISHI_IO_ERROR;
    }

  len = strlen (krb5kcmd1);
  rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen);
  if (rc)
    {
      len = strlen (krb5kcmd2);
      rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen);
      if (rc)
	{
	  *err_msg = "Protocol version not supported";
	  /* Protocol version is wrong.  */
	  write (infd, "\002", 1);
	  return SHISHI_VERIFY_FAILED;
	}
      *protoversion = 2;
    }
  else
    *protoversion = 1;

  free (buf);

  /* Authentication type is ok */

  write (infd, "\0", 1);

  /* Read Authentication request from client */

  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading authentication request size";
      return SHISHI_IO_ERROR;
    }

  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return SHISHI_TOO_SMALL_BUFFER;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading authentication request";
      return SHISHI_IO_ERROR;
    }

  /* Create Authentication context */

  rc = shishi_ap_nosubkey (*handle, ap);
  if (rc != SHISHI_OK)
    return rc;

  /* Store request in context */

  rc = shishi_ap_req_der_set (*ap, buf, buflen);
  if (rc != SHISHI_OK)
    return rc;

  free (buf);

  /* Process authentication request */

  rc = shishi_ap_req_process (*ap, key);
  if (rc != SHISHI_OK)
    return rc;

# ifdef ENCRYPTION

  /* extract subkey if present from ap exchange for secure connection */
  if (*protoversion == 2)
    {
      *enckey = NULL;
      shishi_authenticator_get_subkey (*handle,
				       shishi_ap_authenticator (*ap), enckey);
    }

# endif

  /* Get authenticator checksum */
  rc = shishi_authenticator_cksum (*handle,
				   shishi_ap_authenticator (*ap),
				   cksumtype, cksum, cksumlen);
  if (rc != SHISHI_OK)
    return rc;

  /* User is authenticated.  */
  error = 0;
  write (infd, &error, sizeof (int));

  /* Authenticate ourself to client, if requested.  */

  if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap)))
    {
      int len;

      rc = shishi_ap_rep_der (*ap, &out, &outlen);
      if (rc != SHISHI_OK)
	return rc;

      len = outlen;
      len = htonl (len);
      rc = write (infd, &len, sizeof (len));
      if (rc != sizeof (int))
	{
	  *err_msg = "Error sending AP-REP";
	  free (out);
	  return SHISHI_IO_ERROR;
	}

      rc = write (infd, out, ntohl (len));
      if (rc != (int) ntohl (len))
	{
	  *err_msg = "Error sending AP-REP";
	  free (out);
	  return SHISHI_IO_ERROR;
	}

      free (out);

      /* We are authenticated to client */
    }

# ifdef ENCRYPTION
  if (*protoversion == 1)
    {
      Shishi_tkt *tkt;

      tkt = shishi_ap_tkt (*ap);
      if (tkt == NULL)
	{
	  *err_msg = "Could not get tkt from AP-REQ";
	  return SHISHI_INVALID_TICKET;
	}

      rc = shishi_encticketpart_get_key (*handle,
					 shishi_tkt_encticketpart (tkt),
					 enckey);
      if (rc != SHISHI_OK)
	return rc;
    }
# endif /* ENCRYPTION */

  return 0;
# else
  return -1;
# endif
}
Beispiel #9
0
static Shishi_ap *
auth (Shishi * h, int verbose, const char *cname, const char *sname)
{
  Shishi_key *key;
  Shishi_ap *ap;
  Shishi_asn1 apreq;
  char *buf;
  size_t buflen;
  int rc;

  printf ("Client: %s\n", cname);
  printf ("Server: %s\n", sname);

  /* Get key for the server. */

  key = shishi_hostkeys_for_server (h, sname);
  if (!key)
    {
      printf ("could not find key: %s\n", shishi_error (h));
      return NULL;
    }

  if (verbose)
    shishi_key_print (h, stderr, key);

  /* Read Authentication request from client */

  printf ("Waiting for client to authenticate itself...\n");

  rc = shishi_apreq_parse (h, stdin, &apreq);
  if (rc != SHISHI_OK)
    {
      printf ("could not read AP-REQ: %s\n", shishi_strerror (rc));
      return NULL;
    }

  /* Create Authentication context */

  rc = shishi_ap (h, &ap);
  if (rc != SHISHI_OK)
    {
      printf ("Could not create AP: %s\n", shishi_strerror (rc));
      return NULL;
    }

  /* Store request in context */

  shishi_ap_req_set (ap, apreq);

  /* Process authentication request */

  rc = shishi_ap_req_process (ap, key);
  if (rc != SHISHI_OK)
    {
      printf ("Could not process AP-REQ: %s\n", shishi_strerror (rc));
      return NULL;
    }

  if (verbose)
    shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));

  rc = shishi_authenticator_client (h, shishi_ap_authenticator (ap),
				    &buf, &buflen);
  printf ("Client name (from authenticator): %.*s\n", (int) buflen, buf);
  free (buf);

  rc = shishi_encticketpart_clientrealm
    (h, shishi_tkt_encticketpart (shishi_ap_tkt (ap)), &buf, &buflen);
  printf ("Client name (from encticketpart): %.*s\n", (int) buflen, buf);
  free (buf);

  rc = shishi_ticket_server (h, shishi_tkt_ticket (shishi_ap_tkt (ap)),
			     &buf, &buflen);
  printf ("Server name (from ticket): %.*s\n", (int) buflen, buf);
  free (buf);

  /* User is authenticated. */

  printf ("User authenticated.\n");

  /* Authenticate ourself to client, if request */

  if (shishi_apreq_mutual_required_p (h, apreq))
    {
      Shishi_asn1 aprep;

      printf ("Mutual authentication required.\n");

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

      if (verbose)
	shishi_encapreppart_print (h, stderr, shishi_ap_encapreppart (ap));

      shishi_aprep_print (h, stdout, aprep);

      /* We are authenticated to client */
    }

  return ap;
}
Beispiel #10
0
int
get_auth (int infd, Shishi ** handle, Shishi_ap ** ap,
	  Shishi_key ** enckey, const char **err_msg, int *protoversion,
	  int *cksumtype, char **cksum, int *cksumlen)
{
  Shishi_key *key;
  char *out;
  int outlen;
  char *buf;
  int buflen;
  int len;
  int rc;
  int i;
  int error;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5kcmd1[] = "KCMDV0.1";
  char krb5kcmd2[] = "KCMDV0.2";
  int auth_correct = 0;
  char *servername;

  *err_msg = NULL;
  /* Get key for the server. */

  if (!shishi_check_version (SHISHI_VERSION))
    {
      *err_msg =
	"shishi_check_version() failed: header file incompatible with shared library.";
      return 1;
    }

  rc = shishi_init_server (handle);
  if (rc != SHISHI_OK)
    return rc;

  servername = shishi_server_for_local_service (*handle, SERVICE);

  key = shishi_hostkeys_for_server (*handle, servername);
  if (!key)
    {
      *err_msg = shishi_error (*handle);
      return 1;
    }

  /* Read Kerberos 5 sendauth message */
  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading message size";
      return 1;
    }

  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return 1;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading authentication message";
      return 1;
    }

  len = strlen (krb5sendauth);
  rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen);
  if (rc)
    {
      *err_msg = "Invalid authentication type";
      return 1;
    }

  free (buf);

  /* Read protocol version */
  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading protocol message size";
      return 1;
    }
  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return 1;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading protocol message";
      return 1;
    }

  len = strlen (krb5kcmd1);
  rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen);
  if (rc)
    {
      len = strlen (krb5kcmd2);
      rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen);
      if (rc)
	{
	  *err_msg = "Protocol version not supported";
	  return 1;
	}
      *protoversion = 2;
    }
  else
    *protoversion = 1;

  free (buf);

  /* Authentication type is ok */

  write (infd, "\0", 1);

  /* Read Authentication request from client */

  rc = read (infd, &len, sizeof (int));
  if (rc != sizeof (int))
    {
      *err_msg = "Error reading authentication request size";
      return 1;
    }

  buflen = ntohl (len);
  buf = malloc (buflen);
  if (!buf)
    {
      *err_msg = "Not enough memory";
      return 1;
    }

  rc = read (infd, buf, buflen);
  if (rc != buflen)
    {
      *err_msg = "Error reading authentication request";
      return 1;
    }

  /* Create Authentication context */

  rc = shishi_ap_nosubkey (*handle, ap);
  if (rc != SHISHI_OK)
    return rc;

  /* Store request in context */

  shishi_ap_req_der_set (*ap, buf, buflen);
  if (rc != SHISHI_OK)
    return rc;

  free (buf);

  /* Process authentication request */

  rc = shishi_ap_req_process (*ap, key);
  if (rc != SHISHI_OK)
    return rc;

# ifdef ENCRYPTION

  /* extract subkey if present from ap exchange for secure connection */
  if (*protoversion == 2)
    {
      *enckey = NULL;
      shishi_authenticator_get_subkey (*handle,
				       shishi_ap_authenticator (*ap), enckey);
    }

# endif

  /* Get authenticator checksum */
  rc = shishi_authenticator_cksum (*handle,
				   shishi_ap_authenticator (*ap),
				   cksumtype, cksum, cksumlen);
  if (rc != SHISHI_OK)
    return rc;

  /* User is authenticated. */
  error = 0;
  write (infd, &error, sizeof (int));

  /* Authenticate ourself to client, if request */

  if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap)))
    {
      rc = shishi_ap_rep_der (*ap, &out, &outlen);
      if (rc != SHISHI_OK)
	return rc;

      outlen = htonl (outlen);
      rc = write (infd, &outlen, sizeof (int));
      if (rc != sizeof (int))
	{
	  *err_msg = "Error sending AP-REP";
	  free (out);
	  return 1;
	}

      rc = write (infd, out, ntohl (outlen));
      if (rc != ntohl (outlen))
	{
	  *err_msg = "Error sending AP-REP";
	  free (out);
	  return 1;
	}

      free (out);

      /* We are authenticated to client */
    }

# ifdef ENCRYPTION
  if (*protoversion == 1)
    {
      Shishi_tkt *tkt;

      tkt = shishi_ap_tkt (*ap);
      if (tkt == NULL)
	{
	  *err_msg = "Could not get tkt from AP-REQ";
	  return 1;
	}

      rc = shishi_encticketpart_get_key (*handle,
					 shishi_tkt_encticketpart (tkt),
					 enckey);
      if (rc != SHISHI_OK)
	return rc;
    }
# endif

  return SHISHI_OK;
}