9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: Mike Haertel <mike@ducky.net>
To: 9fans@cse.psu.edu
Subject: [9fans] auth protocol questions + proposed kfs improvement
Date: Thu,  1 Nov 2001 21:43:46 -0800	[thread overview]
Message-ID: <200111020543.fA25hkG02351@ducky.net> (raw)

What is the reason for the distinction between AuthTs and AuthTc
tickets, and AuthAs and AuthAc authenticators?  This caused me
some grief in a recent project...

I wanted to modify kfs so that "listen il!*!17008" would work
on terminals as well as cpu servers, so that I could use the
local file system on my laptop as the boot file system for
the bitsy.

The problem, I found, is that the code in kfs relies on being
able to read /dev/key, and uses the key so obtained to verify
authentication protocol tickets by hand.  But reading /dev/key
is only allowed on cpu servers (presumably it's disallowed on
terminals to prevent trojans from having access to your password).

So, I wanted to modify kfs to use /dev/authcheck to verify
the authentication protocol, rather than relying on being able
to read /dev/key.

Here's the new version of authorize() for /sys/src/cmd/disk/kfs/auth.c.
(The text of this email continues beyond the code...)

int
authorize(Chan *cp, Fcall *in, Fcall *ou)
{
	Ticket t;
	Authenticator a;
	char authbuf[TICKETLEN + AUTHENTLEN + CHALLEN + 4];
	int fd, try;
	ulong bit;

	if (cp == cons.srvchan)               /* local channel already safe */
		return 1;

	if(noauth || wstatallow)		/* set to allow entry during boot */
		return 1;

	if(strcmp(in->uname, "none") == 0)
		return allownone || cp->auth;

	if(in->type == Toattach)
		return 0;

	fd = open("#c/authcheck", ORDWR);
	if (fd < 0) {
		print("can't open #c/authcheck\n");
		return 0;
	}
	memcpy(authbuf, in->ticket, TICKETLEN);
	memcpy(authbuf + TICKETLEN, in->auth, AUTHENTLEN);
	memcpy(authbuf + TICKETLEN + AUTHENTLEN, cp->chal, CHALLEN);
	/*
	 *  the id must be in a valid range.  the range is specified by a
	 *  lower bount (idoffset) and a bit vector (idvec) where a
	 *  bit set to 1 means unusable
	 */
	lock(&cp->idlock);
	for (try = cp->idoffset; try < cp->idoffset + 16; ++try) {
		authbuf[TICKETLEN + AUTHENTLEN + CHALLEN + 0] = try;
		authbuf[TICKETLEN + AUTHENTLEN + CHALLEN + 1] = try >> 8;
		authbuf[TICKETLEN + AUTHENTLEN + CHALLEN + 2] = try >> 16;
		authbuf[TICKETLEN + AUTHENTLEN + CHALLEN + 3] = try >> 24;
		if (write(fd, authbuf, sizeof authbuf) == sizeof authbuf)
			break;
	}
	if (try == cp->idoffset + 16) {
		unlock(&cp->idlock);
		close(fd);
print("authcheck failed\n");
		return 0;
	}
	bit = 1UL << (try - cp->idoffset);
	if (cp->idvec & bit) {
		unlock(&cp->idlock);
print("id %d reused (replay attack?)\n", try);
		close(fd);
		return 0;
	}
	cp->idvec |= bit;
	/* normalize the vector */
	while(cp->idvec&0xffff0001){
		cp->idvec >>= 1;
		cp->idoffset++;
	}
	unlock(&cp->idlock);

	/* ticket name and attach name must match */
	if (read(fd, authbuf, TICKETLEN) != TICKETLEN) {
		close(fd);
print("can't read decrypted ticket\n");
		return 0;
	}
	close(fd);
	convM2T(authbuf, &t, nil);
	if(memcmp(in->uname, t.cuid, sizeof(in->uname)) != 0){
print("names don't match\n");
		return 0;
	}

	/* copy translated name into input record */
	memmove(in->uname, t.suid, sizeof(in->uname));

	/* craft a reply */
	a.num = AuthAs;
	memmove(a.chal, cp->rchal, CHALLEN);
	a.id = try;
	convA2M(&a, ou->rauth, t.key);

	cp->auth = 1;
	return 1;
}

Unfortunately, what I discovered is this doesn't work.
The reason it doesn't work is that /dev/authcheck only
works with AuthTc flavored tickets, and AuthAs flavored
authenticators.

So I replaced authcheck() in /sys/src/9/port/auth.c with
the following code.
(email *still* continues after this code...)

long
authcheck(Chan *c, char *a, int n)
{
	Crypt *cp;
	char *chal;
	ulong id;

	if(n != TICKETLEN+AUTHENTLEN && n != TICKETLEN+AUTHENTLEN+CHALLEN+4)
		error(Ebadarg);
	if(c->aux == 0)
		c->aux = newcrypt();
	cp = c->aux;

	memmove(cp->tbuf, a, TICKETLEN);
	convM2T(cp->tbuf, &cp->t, evekey);
	if (cp->t.num == AuthTc) {
		if(strcmp(up->user, cp->t.cuid))
			error(cp->t.cuid);
	} else if (cp->t.num != AuthTs) {
		error(Ebadarg);
	}

	memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
	convM2A(cp->tbuf, &cp->a, cp->t.key);
	if(n == TICKETLEN+AUTHENTLEN+CHALLEN+4){
		uchar *p = (uchar *)&a[TICKETLEN+AUTHENTLEN+CHALLEN];
		id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
		chal = &a[TICKETLEN+AUTHENTLEN];
	}else{
		id = 0;
		chal = cp->t.chal;
	}

	if(cp->t.num == AuthTc && cp->a.num != AuthAs
	 || cp->t.num == AuthTs && cp->a.num != AuthAc
	 || memcmp(chal, cp->a.chal, CHALLEN) || cp->a.id != id)
		error(Eperm);

	return n;
}

Now, /dev/authcheck works either with (AuthTc,AuthAs) or
(AuthTs,AuthAc) flavored ticket+authenticator pairs.

So, a couple of questions:

1.  Is there any security reason why /dev/authcheck
didn't already work with AuthTs flavored tickets and AuthAc
flavored authenticators?

2.  What is the reason for strcmp(up->user, cp->t.cuid)?

3.  Repeating my original question, is there a security reason
for the distinction between AuthTs and AuthTc flavored tickets,
and the distinction between AuthAc and AuthAs flavored authenticators?


             reply	other threads:[~2001-11-02  5:43 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-11-02  5:43 Mike Haertel [this message]
2001-11-02  7:09 Russ Cox
2001-11-02 19:23 ` Mike Haertel
2001-11-02  7:16 Russ Cox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200111020543.fA25hkG02351@ducky.net \
    --to=mike@ducky.net \
    --cc=9fans@cse.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).