9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* Re: [9fans] auth protocol questions + proposed kfs improvement
@ 2001-11-02  7:16 Russ Cox
  0 siblings, 0 replies; 4+ messages in thread
From: Russ Cox @ 2001-11-02  7:16 UTC (permalink / raw)
  To: 9fans

And there it is.  If you merge AuthAc and AuthAs, you won't
be able to tell client authenticator from server authenticator.
The usual protocol is

	1. get a ticket pair from the AS.  the ticket pair is
	identical tickets one encrypted with your key and
	one with the server key.
	2. decrypt your ticket to get a nonce key.
	3. send the other ticket to the server.
	4. you send {AuthAc, ...} encrypted with the nonce key.
	5. the server sends {AuthAs, ...} encrypted with the nonce key.

Since you trust the AS, you believe that only you and the
remote server know the nonce key (the AS forgot the key
as soon as it gave you the tickets, and since you have to
have either your key or the server key to decrypt a ticket,
only you and the server know the nonce key).

When you do #4, the server concludes that you know the nonce key
(or you know the server key, in which case why are we playing
this game?) so you must be you.

When the server does #5, you conclude by similar reasoning that
it knows the nonce key, so it must be the server you expected.

If AuthAc==AuthAs, the server can parrot back your message,
so you would no longer have reason to believe that it knows
the nonce key and thus no reason to believe its supposed identity.

Russ


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [9fans] auth protocol questions + proposed kfs improvement
  2001-11-02  7:09 Russ Cox
@ 2001-11-02 19:23 ` Mike Haertel
  0 siblings, 0 replies; 4+ messages in thread
From: Mike Haertel @ 2001-11-02 19:23 UTC (permalink / raw)
  To: 9fans

>> 1.  Is there any security reason why /dev/authcheck
>> didn't already work with AuthTs flavored tickets and AuthAc
>> flavored authenticators?
>
>Yes, /dev/authcheck was only intended to be used
>for checking the credentials presented by servers.

You'd think it would say something about that in the manual page.
Any particular reason for this restriction?  The one reason I can
think of is that it might allow J. Random User on a cpu server to
pose as eve to a remote client, since authcheck also allows you
to sign authenticators with eve's secret key.

So how about allowing authcheck to check client credentials and
sign server authenticators, but only in the case that the user
is eve?


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [9fans] auth protocol questions + proposed kfs improvement
@ 2001-11-02  7:09 Russ Cox
  2001-11-02 19:23 ` Mike Haertel
  0 siblings, 1 reply; 4+ messages in thread
From: Russ Cox @ 2001-11-02  7:09 UTC (permalink / raw)
  To: 9fans

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

Yes, /dev/authcheck was only intended to be used
for checking the credentials presented by servers.

> 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?

Both of these might only be paranoia (I'm sure presotto will
say for sure), but paranoia for its own sake isn't a bad thing.  The
distinction makes very explicit which messages are intended to be
used where.

If you don't do this, it's too easy not to be explicit enough.
The Needham and Schroeder protocol is the most commonly cited
example, but here's one closer to home.  If you diff auth(6)
between second and third edition you'll notice a slight change:
the password change ticket sent back from the AS is of type
AuthTp instead of AuthTc.  The reason is that if I could convince
a client host to talk to me instead of the real AS, I could relay all
the traffic through until I get a password change, at which point
I can convince the client host to tell me its password.

	UserProc->FakeAS: AuthPass, xxx, xxx, xxx, xxx, UIDc

	FakeAS->RealAS:   AuthTreq, xxx, UIDfakeas, xxx, UIDc, UIDc
	RealAS->FakeAS:   AuthOK, Kc{AuthTc, ..., Kn} Kfakeas{AuthTs, ..., Kn}

	FakeAS->UserProc: AuthOK, Kc{AuthTc, ..., Kn}
	UserProc->FakeAS: Kn{AuthPass, old password, new password}

The fake AS sends a ticket request, getting a pair of
similarly encrypted tickets with the same nonce key.
It can relay the Kc ticket (which it can't decrypt) to
the client, but then decrypt the Kfakeas ticket to recover
the nonce key, which lets it decrypt the password change
message.

The problem here is that the AuthTc ticket type got used
in two places for different purposes under different assumptions.
I stumbled across this while checking the protocol using
some authentication logics.  The problem with such checks,
of course, is that they don't guarantee to let you find all
the problems.  Maybe if you merged AuthTs and AuthTc and also
AuthAs and AuthAc, everything would work out.  But maybe not,
and that's the argument for being as explicit as possible.

(In this case, I think you could rederive the original type
by looking at the user ids in the message.  But maybe not always.)

Russ


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [9fans] auth protocol questions + proposed kfs improvement
@ 2001-11-02  5:43 Mike Haertel
  0 siblings, 0 replies; 4+ messages in thread
From: Mike Haertel @ 2001-11-02  5:43 UTC (permalink / raw)
  To: 9fans

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?


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2001-11-02 19:23 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-11-02  7:16 [9fans] auth protocol questions + proposed kfs improvement Russ Cox
  -- strict thread matches above, loose matches on Subject: below --
2001-11-02  7:09 Russ Cox
2001-11-02 19:23 ` Mike Haertel
2001-11-02  5:43 Mike Haertel

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).