auth: release dp9ik implementation and reentrant factotum

This commit is contained in:
cinap_lenrek 2016-01-06 03:09:00 +01:00
parent e064752dd4
commit 2dae1ed53a
44 changed files with 2034 additions and 732 deletions

View file

@ -20,16 +20,27 @@ enum
AERRLEN= 64, /* errstr max size in previous proto */ AERRLEN= 64, /* errstr max size in previous proto */
DOMLEN= 48, /* authentication domain name length */ DOMLEN= 48, /* authentication domain name length */
DESKEYLEN= 7, /* encrypt/decrypt des key length */ DESKEYLEN= 7, /* encrypt/decrypt des key length */
AESKEYLEN= 16, AESKEYLEN= 16, /* encrypt/decrypt aes key length */
CHALLEN= 8, /* plan9 sk1 challenge length */ CHALLEN= 8, /* plan9 sk1 challenge length */
NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
CONFIGLEN= 14, CONFIGLEN= 14,
SECRETLEN= 32, /* secret max size */ SECRETLEN= 32, /* secret max size */
NONCELEN= 32,
KEYDBOFF= 8, /* bytes of random data at key file's start */ KEYDBOFF= 8, /* bytes of random data at key file's start */
OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* old key file entry length */ OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* old key file entry length */
KEYDBLEN= OKEYDBLEN+SECRETLEN, /* key file entry length */ KEYDBLEN= OKEYDBLEN+SECRETLEN, /* key file entry length */
OMD5LEN= 16, OMD5LEN= 16,
/* AuthPAK constants */
PAKKEYLEN= 32,
PAKSLEN= (448+7)/8, /* ed448 scalar */
PAKPLEN= 4*PAKSLEN, /* point in extended format X,Y,Z,T */
PAKHASHLEN= 2*PAKPLEN, /* hashed points PM,PN */
PAKXLEN= PAKSLEN, /* random scalar secret key */
PAKYLEN= PAKSLEN, /* decaf encoded public key */
}; };
/* encryption numberings (anti-replay) */ /* encryption numberings (anti-replay) */
@ -48,8 +59,7 @@ enum
AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */ AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
AuthHttp=13, /* http domain login */ AuthHttp=13, /* http domain login */
AuthVNC=14, /* VNC server login (deprecated) */ AuthVNC=14, /* VNC server login (deprecated) */
AuthPAK=19, /* authenticated diffie hellman key agreement */
AuthTs=64, /* ticket encrypted with server's key */ AuthTs=64, /* ticket encrypted with server's key */
AuthTc, /* ticket encrypted with client's key */ AuthTc, /* ticket encrypted with client's key */
AuthAs, /* server generated authenticator */ AuthAs, /* server generated authenticator */
@ -75,17 +85,19 @@ struct Ticket
char chal[CHALLEN]; /* server challenge */ char chal[CHALLEN]; /* server challenge */
char cuid[ANAMELEN]; /* uid on client */ char cuid[ANAMELEN]; /* uid on client */
char suid[ANAMELEN]; /* uid on server */ char suid[ANAMELEN]; /* uid on server */
char key[DESKEYLEN]; /* nonce DES key */ uchar key[NONCELEN]; /* nonce key */
char form; /* (not transmitted) format (0 = des, 1 = ccpoly) */
}; };
#define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1) #define MAXTICKETLEN (12+CHALLEN+2*ANAMELEN+NONCELEN+16)
struct Authenticator struct Authenticator
{ {
char num; /* replay protection */ char num; /* replay protection */
char chal[CHALLEN]; char chal[CHALLEN]; /* server/client challenge */
ulong id; /* authenticator id, ++'d with each auth */ uchar rand[NONCELEN]; /* server/client nonce */
}; };
#define AUTHENTLEN (CHALLEN+4+1) #define MAXAUTHENTLEN (12+CHALLEN+NONCELEN+16)
struct Passwordreq struct Passwordreq
{ {
@ -95,7 +107,7 @@ struct Passwordreq
char changesecret; char changesecret;
char secret[SECRETLEN]; /* new secret */ char secret[SECRETLEN]; /* new secret */
}; };
#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN) #define MAXPASSREQLEN (12+2*ANAMELEN+1+SECRETLEN+16)
struct OChapreply struct OChapreply
{ {
@ -115,8 +127,10 @@ struct OMSchapreply
struct Authkey struct Authkey
{ {
char des[DESKEYLEN]; char des[DESKEYLEN]; /* DES key from password */
uchar aes[AESKEYLEN]; uchar aes[AESKEYLEN]; /* AES key from password */
uchar pakkey[PAKKEYLEN]; /* shared key from AuthPAK exchange (see authpak_finish()) */
uchar pakhash[PAKHASHLEN]; /* secret hash from AES key and user name (see authpak_hash()) */
}; };
/* /*
@ -132,10 +146,13 @@ extern int convPR2M(Passwordreq*, char*, int, Ticket*);
extern int convM2PR(char*, int, Passwordreq*, Ticket*); extern int convM2PR(char*, int, Passwordreq*, Ticket*);
/* /*
* convert ascii password to DES key * convert ascii password to auth key
*/ */
extern void passtokey(Authkey*, char*); extern void passtokey(Authkey*, char*);
extern void passtodeskey(char key[DESKEYLEN], char *p);
extern void passtoaeskey(uchar key[AESKEYLEN], char *p);
/* /*
* Nvram interface * Nvram interface
*/ */
@ -179,7 +196,23 @@ extern int authdial(char *netroot, char *authdom);
/* /*
* exchange messages with auth server * exchange messages with auth server
*/ */
extern int _asgetpakkey(int, Ticketreq*, Authkey*);
extern int _asgetticket(int, Ticketreq*, char*, int); extern int _asgetticket(int, Ticketreq*, char*, int);
extern int _asrequest(int, Ticketreq*); extern int _asrequest(int, Ticketreq*);
extern int _asgetresp(int, Ticket*, Authenticator*, Authkey *); extern int _asgetresp(int, Ticket*, Authenticator*, Authkey *);
extern int _asrdresp(int, char*, int); extern int _asrdresp(int, char*, int);
/*
* AuthPAK protocol
*/
typedef struct PAKpriv PAKpriv;
struct PAKpriv
{
int isclient;
uchar x[PAKXLEN];
uchar y[PAKYLEN];
};
extern void authpak_hash(Authkey *k, char *u);
extern void authpak_new(PAKpriv *p, Authkey *k, uchar y[PAKYLEN], int isclient);
extern int authpak_finish(PAKpriv *p, Authkey *k, uchar y[PAKYLEN]);

View file

@ -1,6 +1,6 @@
.TH AUTHSRV 6 .TH AUTHSRV 6
.SH NAME .SH NAME
authsrv, p9any, p9sk1, p9sk2 \- authentication protocols authsrv, p9any, p9sk1, dp9ik \- authentication protocols
.SH DESCRIPTION .SH DESCRIPTION
This manual page describes This manual page describes
the protocols used to authorize connections, confirm the identities the protocols used to authorize connections, confirm the identities
@ -14,8 +14,9 @@ The network database
holds for each public machine, such as a CPU server or holds for each public machine, such as a CPU server or
file server, the name of the authentication server that machine uses. file server, the name of the authentication server that machine uses.
.PP .PP
Each machine contains three values important to authentication; a 56-bit DES Each machine contains four values important to authentication; a 56-bit DES
key, a 28-byte authentication ID, and a 48-byte authentication domain name. key, a 128-bit AES key, a 28-byte authentication ID, and a 48-byte authentication
domain name.
The ID is a user name and identifies who is currently responsible for the The ID is a user name and identifies who is currently responsible for the
kernel running on that machine. kernel running on that machine.
The domain name identifies the machines across which the ID is valid. The domain name identifies the machines across which the ID is valid.
@ -29,7 +30,7 @@ The password is converted using
.I passtokey .I passtokey
(see (see
.IR authsrv (2)) .IR authsrv (2))
into a 56-bit DES key and saved in memory. into a 56-bit DES and 128-bit AES keys and saved in memory.
The authentication domain is set to the null string. The authentication domain is set to the null string.
If possible, If possible,
.I factotum .I factotum
@ -60,7 +61,7 @@ client's host ID's key
a nonce key created for a ticket a nonce key created for a ticket
.RB ( key ) .RB ( key )
.TP .TP
.IR K { m } .I K{m}
message message
.I m .I m
encrypted with key encrypted with key
@ -91,6 +92,24 @@ client's ID
client's desired ID on server client's desired ID on server
.RB ( uid , .RB ( uid ,
.BR suid ) .BR suid )
.TP
.I YAc
client \(-> AS DH public key
.TP
.I YBc
AS \(-> client DH public key
.TP
.I YAs
server \(-> AS DH public key
.TP
.I YBs
AS \(-> server DH public key
.TP
.I RNc
client's 32-byte random string
.TP
.I RNs
server's 32-byte random string
.PD .PD
.PP .PP
The parenthesized names are the ones used in the The parenthesized names are the ones used in the
@ -112,8 +131,9 @@ The message type constants
.IR AuthChap , .IR AuthChap ,
.IR AuthMSchap , .IR AuthMSchap ,
.IR AuthCram , .IR AuthCram ,
.IR AuthVNC ,
and and
.IR AuthVNC .IR AuthPAK
.RB ( type ) .RB ( type )
are defined in are defined in
.BR <authsrv.h> , .BR <authsrv.h> ,
@ -142,7 +162,6 @@ The protocol to obtain a ticket pair is:
.IR CHs , .IR CHs ,
.IR IDc , .IR IDc ,
.IR IDr .IR IDr
.sp -\n(PDu
.TP .TP
.IR A \(-> C .IR A \(-> C
.IR AuthOK , .IR AuthOK ,
@ -265,16 +284,254 @@ proving to the client that it also knows
.I Kn .I Kn
and therefore and therefore
.I Ks . .I Ks .
.PD .SS "Password authenticated key exchange"
Initially, the server and client keys
.I Ks
and
.I Kc
where equivalent to the password derived 56-bit DES keys, which
made the encrypted tickets subject to offline dictionary attacks
and provides a too small key space against brute force attacks
on current hardware.
.PP .PP
.I P9sk2 The
is an older variant of .I AuthPAK
protocol is used to establish new 256-bit random keys with the
AS for
.I Ks
and
.I Kc
before each ticket request on the connection.
.PP
The protocol is based on SPAKE2EE, where a hash of the user's secret
is used to encypt the public keys of a Elliptic-Curve Diffie-Hellman
key exchange. The user's
.I ID
and 128-bit AES key is hashed and mapped (using Elligator2)
into two curve points
.I PM
and
.IR PN ,
called the
.IR pakhash .
Both sides generate a random number
.IR xa / xb
and make the public keys
.IR YA / YB
as:
.IR YA = xa*G+PM ,
.IR YB = xb*G+PN .
After the public keys have been exchanged, each side calculates the
shared secret as:
.IR Z = xa*(YB-PN) = xb*(YA-PM) .
The shared secret
.I Z
is then hashed with the transmitted public keys
.IR YA | YB
producing the 256-bit
.IR pakkey .
.PP
The
.I pakkey
is then used in place of
.I Ks
and
.I Kc
to authenticate and encrypt tickets from the AS using
Chacha20/Poly1305 AEAD for the next following
request made on the connection.
.PP
The protocol (for
.IR AuthTreq )
to establish keys
.I Ks
and
.I Kc
with the AS for
.I IDs
and
.I IDc
is:
.TP
.IR C \(-> A
.IR AuthPAK ,
.IR IDs ,
.IR DN ,
.IR CHs ,
.IR IDc ,
.IR IDr ,
.IR YAs ,
.I YAc
.TP
.IR A \(-> C
.IR AuthOK ,
.IR YBs ,
.I YBc
.PP
The protocol (for
.IR AuthApop ,
.IR AuthChap ...)
to establish a single server key
.I Ks
for
.IR IDs :
.TP
.IR C \(-> A
.IR AuthPAK ,
.IR \- ,
.IR DN ,
.IR CHs ,
.IR IDs ,
.IR IDc ,
.I YAs
.TP
.IR A \(-> C
.IR AuthOK ,
.I YBs
.PP
The protocol (for
.IR AuthPass )
to establish a single client key
.I Kc
for
.IR IDc :
.TP
.IR C \(-> A
.IR AuthPAK ,
.IR \- ,
.IR \- ,
.IR CHc ,
.IR \- ,
.IR IDc ,
.I YAc
.TP
.IR A \(-> C
.IR AuthOK ,
.I YBc
.SS "Dp9ik"
The
.I dp9ik
protocol is an extended version of
.I p9sk1 .I p9sk1
used only when connecting to pre-9P2000 remote that adds the random strings
execution services. .I RNc
It omits the first message and last and
messages and therefore does not .I RNs
authenticate the server to the client. in the
.I authenticator
messages for the session key derivation and uses the
password authenticated key exchange as described above
to derive the ticket encryption keys
.I Ks
and
.IR Kc :
.TP
.IR C \(-> S
.I CHc
.br
The client starts by sending a random challenge to the server.
.TP
.IR S \(-> C
.IR AuthPAK ,
.IR IDs ,
.IR DN ,
.IR CHs ,
.IR \- ,
.IR \- ,
.IR YAs
.br
The server generates a new public key
.I YAs
and replies with a
.I AuthPAK
request giving its
.I IDs
and authentication domain
.I DNs
along with its own random challenge
.I CHs
and its public key
.IR YAs .
.TP
.IR C \(-> S
.IR YBs ,
.IR Ks { AuthTs ,
.IR CHs ,
.IR IDc ,
.IR IDr ,
.IR Kn },
.IR Kn { AuthAc ,
.IR CHs ,
.IR RNc }
.br
The client generates its own public key
.I YAc
and adds it along with
.I IDc
and
.I IDr
to the
.I AuthPAK
request and obtains the public keys
.I YBs
and
.I YBc
from the AS response. At this point, client and AS
have completed ther authenticated key exchange and
derive
.I Kc
as described above.
Then the client requests a ticket pair using the same
message but with
.I AuthPAK
type changed to
.IR AuthTreq .
It decrypts his ticket with
.I Kc
extracting the shared secret
.IR Kn .
The client relays the server's
.I YBs
and ticket along with an
.IR authenticator ,
the
.I AuthAc
message.
The server finishes his authenticated key exchange
using
.I YBs
and derives
.I Ks
to decrypt his ticket to extract the shared secret
.IR Kn .
When the decryption of the clients authenticator using
.I Kn
is successfull then this proves to the server that the
client knows
.I Kn
and is therefore allowed to authenticate as
.IR IDr .
The random string
.I RNc
is used in the derivation of the session secret.
.TP
.IR S \(-> C
.IR Kn { AuthAs ,
.IR CHc ,
.IR RNs }
.br
The server replies with its own authenticator,
proving to the client that it also knows
.I Kn
and contributes its random string
.IR RNs
for the session secret.
.PP
The 2048-bit session secret is derived with a PRF hashing the
concatenated random strings
.IR RNc | RNs
with the the shared secret key
.IR Kn .
.SS "P9any .SS "P9any
.I P9any .I P9any
is the standard Plan 9 authentication protocol. is the standard Plan 9 authentication protocol.
@ -288,12 +545,10 @@ The negotiation protocol is:
.IB proto@authdom .IB proto@authdom
.IB proto@authdom .IB proto@authdom
.I ... .I ...
.sp -\n(PDu
.TP .TP
.IR C \(-> S .IR C \(-> S
.I proto .I proto
.I dom .I dom
.sp -\n(PDu
.TP .TP
.IR S \(-> C .IR S \(-> C
.B OK .B OK
@ -349,10 +604,10 @@ The protocol is:
.TP .TP
.IR C \(-> A .IR C \(-> A
.IR AuthPass , .IR AuthPass ,
.IR IDc , .IR \- ,
.IR DN , .IR \- ,
.IR CHc , .IR CHc ,
.IR IDc , .IR \- ,
.IR IDc .IR IDc
.br .br
The client sends a password change ticket request. The client sends a password change ticket request.
@ -471,39 +726,34 @@ message is expected, a
.I AuthErr .I AuthErr
message may be substituted. message may be substituted.
.de Ok .de Ok
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.IR AuthOK , .IR AuthOK ,
.IR Ks { \\$1 , .IR Ks { AuthTs ,
.IR IDs ,
.IR DN ,
.IR CHs , .IR CHs ,
.IR IDs , .IR IDc ,
.IR IDc , .IR IDc ,
.IR Kn }, .IR Kn },
.IR Kn { AuthTs , .IR Kn { AuthAc ,
.IR CHs } .IR CHs }
.. ..
.PP .PP
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR AuthChal , .IR AuthChal ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR IDs , .IR IDs ,
.IR IDc .IR IDc
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.IR AuthOK , .IR AuthOK ,
.IR challenge .IR challenge
.sp -\n(PDu
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR response .IR response
.Ok AuthChal .Ok
.IP .IP
This protocol allows the use of This protocol allows the use of
handheld authenticators such as SecureNet handheld authenticators such as SecureNet
@ -562,28 +812,26 @@ Users not listed are assumed to have the
same id in both places. same id in both places.
.TP .TP
.IR S \(-> A .IR S \(-> A
AuthApop , .IR AuthApop ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR \- , .IR IDs ,
.IR \- .IR \-
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.IR AuthOKvar , .IR AuthOKvar ,
.IR challenge .IR challenge
.sp -\n(PDu
.TP .TP
.IR S \(-> A .IR S \(-> A
AuthApop , .IR AuthApop ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR IDc , .IR IDs ,
.IR IDc ; .IR IDc ;
hexadecimal MD5 checksum hexadecimal MD5 checksum
.Ok AuthApop .Ok
.IP .IP
This protocol implements APOP authentication This protocol implements APOP authentication
(see (see
@ -616,22 +864,20 @@ in
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR AuthChap , .IR AuthChap ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR \- , .IR IDs ,
.IR \- .IR \-
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.I challenge .I challenge
.sp -\n(PDu
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR pktid , .IR pktid ,
.IR IDc , .IR IDc ,
.IR response .IR response
.Ok AuthChap .Ok
.IP .IP
This protocol implements CHAP authentication This protocol implements CHAP authentication
(see (see
@ -648,22 +894,20 @@ in
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR AuthMSchap , .IR AuthMSchap ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR \- , .IR IDs ,
.IR \- .IR \-
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.I challenge .I challenge
.sp -\n(PDu
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR IDc , .IR IDc ,
.IR lm-response , .IR lm-response ,
.IR nt-response .IR nt-response
.Ok AuthMschap .Ok
.IP .IP
This protocol implements Microsoft's MS-CHAP This protocol implements Microsoft's MS-CHAP
authentication authentication
@ -682,17 +926,15 @@ in
.TP .TP
.IR S \(-> A .IR S \(-> A
.IR AuthVNC , .IR AuthVNC ,
.IR IDs , .IR \- ,
.IR DN , .IR DN ,
.IR CHs , .IR CHs ,
.IR IDs , .IR IDs ,
.IR IDc .IR IDc
.sp -\n(PDu
.TP .TP
.IR A \(-> S .IR A \(-> S
.IR AuthOKvar , .IR AuthOKvar ,
.I challenge .I challenge
.sp -\n(PDu
.TP .TP
.IR S \(-> A .IR S \(-> A
.I response .I response

View file

@ -53,6 +53,7 @@ int netcheck(void*, long, char*);
char* netdecimal(char*); char* netdecimal(char*);
char* netresp(char*, long, char*); char* netresp(char*, long, char*);
char* okpasswd(char*); char* okpasswd(char*);
void private(void);
int querybio(char*, char*, Acctbio*); int querybio(char*, char*, Acctbio*);
void rdbio(char*, char*, Acctbio*); void rdbio(char*, char*, Acctbio*);
int readarg(int, char*, int); int readarg(int, char*, int);

View file

@ -8,11 +8,21 @@
#include <authsrv.h> #include <authsrv.h>
#include "authcmdlib.h" #include "authcmdlib.h"
int debug;
Ndb *db; Ndb *db;
char raddr[128]; char raddr[128];
uchar zeros[16]; uchar zeros[16];
typedef struct Keyslot Keyslot;
struct Keyslot
{
Authkey;
char id[ANAMELEN];
};
Keyslot hkey, akey, ukey;
uchar keyseed[SHA2_256dlen];
char ticketform;
/* Microsoft auth constants */ /* Microsoft auth constants */
enum { enum {
MShashlen = 16, MShashlen = 16,
@ -20,25 +30,26 @@ enum {
MSresplen = 24, MSresplen = 24,
}; };
int ticketrequest(Ticketreq*); void pak(Ticketreq*);
void ticketrequest(Ticketreq*);
void challengebox(Ticketreq*); void challengebox(Ticketreq*);
void changepasswd(Ticketreq*); void changepasswd(Ticketreq*);
void apop(Ticketreq*, int); void apop(Ticketreq*, int);
void chap(Ticketreq*); void chap(Ticketreq*);
void mschap(Ticketreq*); void mschap(Ticketreq*);
void http(Ticketreq*);
void vnc(Ticketreq*); void vnc(Ticketreq*);
int speaksfor(char*, char*); int speaksfor(char*, char*);
void replyerror(char*, ...); void replyerror(char*, ...);
void getraddr(char*); void getraddr(char*);
void mkkey(Authkey*); void initkeyseed(void);
void mkkey(Keyslot*);
void mkticket(Ticketreq*, Ticket*); void mkticket(Ticketreq*, Ticket*);
void nthash(uchar hash[MShashlen], char *passwd); void nthash(uchar hash[MShashlen], char *passwd);
void lmhash(uchar hash[MShashlen], char *passwd); void lmhash(uchar hash[MShashlen], char *passwd);
void ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom); void ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom);
void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]); void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
void desencrypt(uchar data[8], uchar key[7]); void desencrypt(uchar data[8], uchar key[7]);
int tickauthreply(Ticketreq*, Authkey*); void tickauthreply(Ticketreq*, Authkey*);
void safecpy(char*, char*, int); void safecpy(char*, char*, int);
void void
@ -49,8 +60,9 @@ main(int argc, char *argv[])
int n; int n;
ARGBEGIN{ ARGBEGIN{
case 'd': case 'N':
debug++; ticketform = 1;
break;
}ARGEND }ARGEND
strcpy(raddr, "unknown"); strcpy(raddr, "unknown");
@ -59,6 +71,9 @@ main(int argc, char *argv[])
alarm(10*60*1000); /* kill a connection after 10 minutes */ alarm(10*60*1000); /* kill a connection after 10 minutes */
private();
initkeyseed();
db = ndbopen("/lib/ndb/auth"); db = ndbopen("/lib/ndb/auth");
if(db == 0) if(db == 0)
syslog(0, AUTHLOG, "no /lib/ndb/auth"); syslog(0, AUTHLOG, "no /lib/ndb/auth");
@ -89,46 +104,112 @@ main(int argc, char *argv[])
case AuthCram: case AuthCram:
apop(&tr, AuthCram); apop(&tr, AuthCram);
break; break;
case AuthHttp:
http(&tr);
break;
case AuthVNC: case AuthVNC:
vnc(&tr); vnc(&tr);
break; break;
case AuthPAK:
pak(&tr);
continue;
default: default:
syslog(0, AUTHLOG, "unknown ticket request type: %d", tr.type); syslog(0, AUTHLOG, "unknown ticket request type: %d", tr.type);
exits(0); exits(0);
} }
/* invalidate pak keys */
akey.id[0] = 0;
hkey.id[0] = 0;
ukey.id[0] = 0;
} }
/* not reached */ /* not reached */
} }
void
pak1(char *u, Keyslot *k)
{
uchar y[PAKYLEN];
PAKpriv p;
safecpy(k->id, u, sizeof(k->id));
if(!findkey(KEYDB, k->id, k) || tsmemcmp(k->aes, zeros, AESKEYLEN) == 0) {
/* make one up so caller doesn't know it was wrong */
mkkey(k);
authpak_hash(k, k->id);
}
authpak_new(&p, k, y, 0);
if(write(1, y, PAKYLEN) != PAKYLEN)
exits(0);
if(readn(0, y, PAKYLEN) != PAKYLEN)
exits(0);
if(authpak_finish(&p, k, y))
exits(0);
}
void
pak(Ticketreq *tr)
{
static uchar ok[1] = {AuthOK};
if(write(1, ok, 1) != 1)
exits(0);
/* invalidate pak keys */
akey.id[0] = 0;
hkey.id[0] = 0;
ukey.id[0] = 0;
if(tr->hostid[0]) {
if(tr->authid[0])
pak1(tr->authid, &akey);
pak1(tr->hostid, &hkey);
} else if(tr->uid[0]) {
pak1(tr->uid, &ukey);
}
ticketform = 1;
}
int int
getkey(char *u, Keyslot *k)
{
/* empty user id is an error */
if(*u == 0)
exits(0);
if(k == &hkey && strcmp(u, k->id) == 0)
return 1;
if(k == &akey && strcmp(u, k->id) == 0)
return 1;
if(k == &ukey && strcmp(u, k->id) == 0)
return 1;
if(ticketform != 0)
exits(0);
return findkey(KEYDB, u, k);
}
void
ticketrequest(Ticketreq *tr) ticketrequest(Ticketreq *tr)
{ {
Authkey akey, hkey; char tbuf[2*MAXTICKETLEN+1];
char tbuf[2*TICKETLEN+1];
Ticket t; Ticket t;
int n; int n;
if(!findkey(KEYDB, tr->authid, &akey)){ if(tr->uid[0] == 0)
exits(0);
if(!getkey(tr->authid, &akey)){
/* make one up so caller doesn't know it was wrong */ /* make one up so caller doesn't know it was wrong */
mkkey(&akey); mkkey(&akey);
if(debug) syslog(0, AUTHLOG, "tr-fail authid %s", tr->authid);
syslog(0, AUTHLOG, "tr-fail authid %s", raddr);
} }
if(!findkey(KEYDB, tr->hostid, &hkey)){ if(!getkey(tr->hostid, &hkey)){
/* make one up so caller doesn't know it was wrong */ /* make one up so caller doesn't know it was wrong */
mkkey(&hkey); mkkey(&hkey);
if(debug)
syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr); syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr);
} }
mkticket(tr, &t); mkticket(tr, &t);
if(!speaksfor(tr->hostid, tr->uid)){ if(!speaksfor(tr->hostid, tr->uid)){
mkkey(&akey); mkkey(&akey);
mkkey(&hkey); mkkey(&hkey);
if(debug)
syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for", syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
tr->uid, tr->hostid, raddr, tr->uid, tr->authid); tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
} }
@ -138,44 +219,34 @@ ticketrequest(Ticketreq *tr)
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &hkey); n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &hkey);
t.num = AuthTs; t.num = AuthTs;
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &akey); n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &akey);
if(write(1, tbuf, n) < 0){ if(write(1, tbuf, n) != n)
if(debug)
syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup",
tr->uid, tr->hostid, raddr);
exits(0); exits(0);
}
if(debug)
syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s",
tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
return 0; syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s", tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
} }
void void
challengebox(Ticketreq *tr) challengebox(Ticketreq *tr)
{ {
char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], buf[NETCHLEN+1];
char *key, *netkey, *err;
long chal; long chal;
char *key, *netkey;
Authkey hkey;
char kbuf[DESKEYLEN], nkbuf[DESKEYLEN];
char buf[NETCHLEN+1];
char *err;
if(tr->uid[0] == 0)
exits(0);
key = finddeskey(KEYDB, tr->uid, kbuf); key = finddeskey(KEYDB, tr->uid, kbuf);
netkey = finddeskey(NETKEYDB, tr->uid, nkbuf); netkey = finddeskey(NETKEYDB, tr->uid, nkbuf);
if(key == nil && netkey == nil){ if(key == nil && netkey == nil){
/* make one up so caller doesn't know it was wrong */ /* make one up so caller doesn't know it was wrong */
genrandom((uchar*)nkbuf, DESKEYLEN); genrandom((uchar*)nkbuf, DESKEYLEN);
netkey = nkbuf; netkey = nkbuf;
if(debug)
syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr); syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr);
} }
if(!findkey(KEYDB, tr->hostid, &hkey)){
if(!getkey(tr->hostid, &hkey)){
/* make one up so caller doesn't know it was wrong */ /* make one up so caller doesn't know it was wrong */
mkkey(&hkey); mkkey(&hkey);
if(debug) syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid, tr->uid, raddr);
syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid,
tr->uid, raddr);
} }
/* /*
@ -185,18 +256,15 @@ challengebox(Ticketreq *tr)
buf[0] = AuthOK; buf[0] = AuthOK;
chal = nfastrand(MAXNETCHAL); chal = nfastrand(MAXNETCHAL);
sprint(buf+1, "%lud", chal); sprint(buf+1, "%lud", chal);
if(write(1, buf, NETCHLEN+1) < 0) if(write(1, buf, NETCHLEN+1) != NETCHLEN+1)
exits(0); exits(0);
if(readn(0, buf, NETCHLEN) < 0) if(readn(0, buf, NETCHLEN) != NETCHLEN)
exits(0); exits(0);
if(!(key != nil && netcheck(key, chal, buf)) if(!(key != nil && netcheck(key, chal, buf))
&& !(netkey != nil && netcheck(netkey, chal, buf)) && !(netkey != nil && netcheck(netkey, chal, buf))
&& (err = secureidcheck(tr->uid, buf)) != nil){ && (err = secureidcheck(tr->uid, buf)) != nil){
replyerror("cr-fail %s %s %s", err, tr->uid, raddr); replyerror("cr-fail %s %s %s", err, tr->uid, raddr);
logfail(tr->uid); logfail(tr->uid);
if(debug)
syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp",
tr->uid, tr->hostid, raddr);
return; return;
} }
succeed(tr->uid); succeed(tr->uid);
@ -204,33 +272,24 @@ challengebox(Ticketreq *tr)
/* /*
* reply with ticket & authenticator * reply with ticket & authenticator
*/ */
if(tickauthreply(tr, &hkey) < 0){ tickauthreply(tr, &hkey);
if(debug)
syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup",
tr->uid, tr->hostid, raddr);
exits(0);
}
if(debug) syslog(0, AUTHLOG, "cr-ok %s@%s(%s)", tr->uid, tr->hostid, raddr);
syslog(0, AUTHLOG, "cr-ok %s@%s(%s)",
tr->uid, tr->hostid, raddr);
} }
void void
changepasswd(Ticketreq *tr) changepasswd(Ticketreq *tr)
{ {
Ticket t; char tbuf[MAXTICKETLEN+1], prbuf[MAXPASSREQLEN], *err;
char tbuf[TICKETLEN+1];
char prbuf[PASSREQLEN];
Passwordreq pr; Passwordreq pr;
Authkey okey, nkey; Authkey nkey;
char *err; Ticket t;
int n; int n, m;
if(!findkey(KEYDB, tr->uid, &okey)){ if(!getkey(tr->uid, &ukey)){
/* make one up so caller doesn't know it was wrong */ /* make one up so caller doesn't know it was wrong */
mkkey(&okey); mkkey(&ukey);
syslog(0, AUTHLOG, "cp-fail uid %s", raddr); syslog(0, AUTHLOG, "cp-fail uid %s@%s", tr->uid, raddr);
} }
/* send back a ticket with a new key */ /* send back a ticket with a new key */
@ -238,25 +297,30 @@ changepasswd(Ticketreq *tr)
t.num = AuthTp; t.num = AuthTp;
n = 0; n = 0;
tbuf[n++] = AuthOK; tbuf[n++] = AuthOK;
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &okey); n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &ukey);
if(write(1, tbuf, n) != n) if(write(1, tbuf, n) != n)
exits(0); exits(0);
/* loop trying passwords out */ /* loop trying passwords out */
for(;;){ for(;;){
n = readn(0, prbuf, sizeof(prbuf)); for(n=0; (m = convM2PR(prbuf, n, &pr, &t)) <= 0; n += m){
if(n <= 0 || convM2PR(prbuf, n, &pr, &t) <= 0) m = -m;
if(m <= n || m > sizeof(prbuf))
exits(0); exits(0);
m -= n;
if(readn(0, prbuf+n, m) != m)
exits(0);
}
if(pr.num != AuthPass){ if(pr.num != AuthPass){
replyerror("protocol botch1: %s", raddr); replyerror("protocol botch1: %s", raddr);
exits(0); exits(0);
} }
passtokey(&nkey, pr.old); passtokey(&nkey, pr.old);
if(memcmp(nkey.des, okey.des, DESKEYLEN) != 0){ if(tsmemcmp(ukey.des, nkey.des, DESKEYLEN) != 0){
replyerror("protocol botch2: %s", raddr); replyerror("protocol botch2: %s", raddr);
continue; continue;
} }
if(memcmp(okey.aes, zeros, AESKEYLEN) != 0 && memcmp(okey.aes, nkey.aes, AESKEYLEN) != 0){ if(tsmemcmp(ukey.aes, zeros, AESKEYLEN) != 0 && tsmemcmp(ukey.aes, nkey.aes, AESKEYLEN) != 0){
replyerror("protocol botch3: %s", raddr); replyerror("protocol botch3: %s", raddr);
continue; continue;
} }
@ -276,56 +340,15 @@ changepasswd(Ticketreq *tr)
replyerror("can't write key %s", raddr); replyerror("can't write key %s", raddr);
continue; continue;
} }
memmove(ukey.des, nkey.des, DESKEYLEN);
memmove(ukey.aes, nkey.aes, AESKEYLEN);
break; break;
} }
succeed(tr->uid);
prbuf[0] = AuthOK; prbuf[0] = AuthOK;
write(1, prbuf, 1); if(write(1, prbuf, 1) != 1)
succeed(tr->uid); exits(0);
return;
}
void
http(Ticketreq *tr)
{
Ticket t;
char tbuf[TICKETLEN+1];
Authkey key;
char *p;
Biobuf *b;
int n;
/* use plan9 key when there is any */
if(!findkey(KEYDB, tr->uid, &key))
mkkey(&key);
n = strlen(tr->uid);
b = Bopen("/sys/lib/httppasswords", OREAD);
if(b != nil){
for(;;){
p = Brdline(b, '\n');
if(p == nil)
break;
p[Blinelen(b)-1] = 0;
if(strncmp(p, tr->uid, n) == 0)
if(p[n] == ' ' || p[n] == '\t'){
p += n;
while(*p == ' ' || *p == '\t')
p++;
passtokey(&key, p);
}
}
Bterm(b);
}
/* send back a ticket encrypted with the key */
mkticket(tr, &t);
genrandom((uchar*)t.chal, CHALLEN);
t.num = AuthHr;
n = 0;
tbuf[n++] = AuthOK;
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &key);
write(1, tbuf, n);
} }
static char* static char*
@ -371,7 +394,6 @@ apop(Ticketreq *tr, int type)
{ {
int challen, i, n, tries; int challen, i, n, tries;
char *secret, *p; char *secret, *p;
Authkey hkey;
Ticketreq treq; Ticketreq treq;
DigestState *s; DigestState *s;
char sbuf[SECRETLEN]; char sbuf[SECRETLEN];
@ -402,7 +424,7 @@ apop(Ticketreq *tr, int type)
if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0) if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)
exits(0); exits(0);
tr = &treq; tr = &treq;
if(tr->type != type) if(tr->type != type || tr->uid[0] == 0)
exits(0); exits(0);
/* /*
@ -417,11 +439,11 @@ apop(Ticketreq *tr, int type)
* lookup * lookup
*/ */
secret = findsecret(KEYDB, tr->uid, sbuf); secret = findsecret(KEYDB, tr->uid, sbuf);
if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){ if(!getkey(tr->hostid, &hkey) || secret == nil){
replyerror("apop-fail bad response %s", raddr); replyerror("apop-fail bad response %s", raddr);
logfail(tr->uid); logfail(tr->uid);
if(tries > 5) if(tries > 5)
return; exits(0);
continue; continue;
} }
@ -436,11 +458,11 @@ apop(Ticketreq *tr, int type)
s = md5((uchar*)chal, challen, 0, 0); s = md5((uchar*)chal, challen, 0, 0);
md5((uchar*)secret, strlen(secret), digest, s); md5((uchar*)secret, strlen(secret), digest, s);
} }
if(memcmp(digest, resp, MD5dlen) != 0){ if(tsmemcmp(digest, resp, MD5dlen) != 0){
replyerror("apop-fail bad response %s", raddr); replyerror("apop-fail bad response %s", raddr);
logfail(tr->uid); logfail(tr->uid);
if(tries > 5) if(tries > 5)
return; exits(0);
continue; continue;
} }
break; break;
@ -451,16 +473,13 @@ apop(Ticketreq *tr, int type)
/* /*
* reply with ticket & authenticator * reply with ticket & authenticator
*/ */
if(tickauthreply(tr, &hkey) < 0) tickauthreply(tr, &hkey);
exits(0);
if(debug){
if(type == AuthCram) if(type == AuthCram)
syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr); syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);
else else
syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr); syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);
} }
}
enum { enum {
VNCchallen= 16, VNCchallen= 16,
@ -489,14 +508,16 @@ uchar swizzletab[256] = {
void void
vnc(Ticketreq *tr) vnc(Ticketreq *tr)
{ {
char *secret;
Authkey hkey;
uchar chal[VNCchallen+6]; uchar chal[VNCchallen+6];
uchar reply[VNCchallen]; uchar reply[VNCchallen];
char sbuf[SECRETLEN]; char sbuf[SECRETLEN];
char *secret;
DESstate s; DESstate s;
int i; int i;
if(tr->uid[0] == 0)
exits(0);
/* /*
* Create a challenge and send it. * Create a challenge and send it.
*/ */
@ -504,35 +525,33 @@ vnc(Ticketreq *tr)
chal[0] = AuthOKvar; chal[0] = AuthOKvar;
sprint((char*)chal+1, "%-5d", VNCchallen); sprint((char*)chal+1, "%-5d", VNCchallen);
if(write(1, chal, sizeof(chal)) != sizeof(chal)) if(write(1, chal, sizeof(chal)) != sizeof(chal))
return; exits(0);
/* /*
* lookup keys (and swizzle bits) * lookup keys (and swizzle bits)
*/ */
memset(sbuf, 0, sizeof(sbuf)); memset(sbuf, 0, sizeof(sbuf));
secret = findsecret(KEYDB, tr->uid, sbuf); secret = findsecret(KEYDB, tr->uid, sbuf);
if(secret == nil){ if(!getkey(tr->hostid, &hkey) || secret == nil){
mkkey(&hkey);
genrandom((uchar*)sbuf, sizeof(sbuf)); genrandom((uchar*)sbuf, sizeof(sbuf));
secret = sbuf; secret = sbuf;
} }
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++)
secret[i] = swizzletab[(uchar)secret[i]]; secret[i] = swizzletab[(uchar)secret[i]];
if(!findkey(KEYDB, tr->hostid, &hkey))
mkkey(&hkey);
/* /*
* get response * get response
*/ */
if(readn(0, reply, sizeof(reply)) != sizeof(reply)) if(readn(0, reply, sizeof(reply)) != sizeof(reply))
return; exits(0);
/* /*
* decrypt response and compare * decrypt response and compare
*/ */
setupDESstate(&s, (uchar*)secret, nil); setupDESstate(&s, (uchar*)secret, nil);
desECBdecrypt(reply, sizeof(reply), &s); desECBdecrypt(reply, sizeof(reply), &s);
if(memcmp(reply, chal+6, VNCchallen) != 0){ if(tsmemcmp(reply, chal+6, VNCchallen) != 0){
replyerror("vnc-fail bad response %s", raddr); replyerror("vnc-fail bad response %s", raddr);
logfail(tr->uid); logfail(tr->uid);
return; return;
@ -542,10 +561,8 @@ vnc(Ticketreq *tr)
/* /*
* reply with ticket & authenticator * reply with ticket & authenticator
*/ */
if(tickauthreply(tr, &hkey) < 0) tickauthreply(tr, &hkey);
exits(0);
if(debug)
syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr); syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr);
} }
@ -553,7 +570,6 @@ void
chap(Ticketreq *tr) chap(Ticketreq *tr)
{ {
char *secret; char *secret;
Authkey hkey;
DigestState *s; DigestState *s;
char sbuf[SECRETLEN]; char sbuf[SECRETLEN];
uchar digest[MD5dlen]; uchar digest[MD5dlen];
@ -564,7 +580,8 @@ chap(Ticketreq *tr)
* Create a challenge and send it. * Create a challenge and send it.
*/ */
genrandom((uchar*)chal, sizeof(chal)); genrandom((uchar*)chal, sizeof(chal));
write(1, chal, sizeof(chal)); if(write(1, chal, sizeof(chal)) != sizeof(chal))
exits(0);
/* /*
* get chap reply * get chap reply
@ -572,15 +589,17 @@ chap(Ticketreq *tr)
if(readn(0, &reply, sizeof(reply)) < 0) if(readn(0, &reply, sizeof(reply)) < 0)
exits(0); exits(0);
safecpy(tr->uid, reply.uid, sizeof(tr->uid)); safecpy(tr->uid, reply.uid, sizeof(tr->uid));
if(tr->uid[0] == 0)
exits(0);
/* /*
* lookup * lookup
*/ */
secret = findsecret(KEYDB, tr->uid, sbuf); secret = findsecret(KEYDB, tr->uid, sbuf);
if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){ if(!getkey(tr->hostid, &hkey) || secret == nil){
replyerror("chap-fail bad response %s", raddr); replyerror("chap-fail bad response %s", raddr);
logfail(tr->uid); logfail(tr->uid);
exits(0); return;
} }
/* /*
@ -590,10 +609,10 @@ chap(Ticketreq *tr)
md5((uchar*)secret, strlen(secret), 0, s); md5((uchar*)secret, strlen(secret), 0, s);
md5((uchar*)chal, sizeof(chal), digest, s); md5((uchar*)chal, sizeof(chal), digest, s);
if(memcmp(digest, reply.resp, MD5dlen) != 0){ if(tsmemcmp(digest, reply.resp, MD5dlen) != 0){
replyerror("chap-fail bad response %s", raddr); replyerror("chap-fail bad response %s", raddr);
logfail(tr->uid); logfail(tr->uid);
exits(0); return;
} }
succeed(tr->uid); succeed(tr->uid);
@ -601,25 +620,11 @@ chap(Ticketreq *tr)
/* /*
* reply with ticket & authenticator * reply with ticket & authenticator
*/ */
if(tickauthreply(tr, &hkey) < 0) tickauthreply(tr, &hkey);
exits(0);
if(debug)
syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr); syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr);
} }
void
printresp(uchar resp[MSresplen])
{
char buf[200], *p;
int i;
p = buf;
for(i=0; i<MSresplen; i++)
p += sprint(p, "%.2ux ", resp[i]);
syslog(0, AUTHLOG, "resp = %s", buf);
}
enum { enum {
MsvAvEOL = 0, MsvAvEOL = 0,
MsvAvNbComputerName, MsvAvNbComputerName,
@ -666,7 +671,6 @@ void
mschap(Ticketreq *tr) mschap(Ticketreq *tr)
{ {
char *secret; char *secret;
Authkey hkey;
char sbuf[SECRETLEN], windom[128]; char sbuf[SECRETLEN], windom[128];
uchar chal[CHALLEN], ntblob[1024]; uchar chal[CHALLEN], ntblob[1024];
uchar hash[MShashlen]; uchar hash[MShashlen];
@ -681,7 +685,8 @@ mschap(Ticketreq *tr)
* Create a challenge and send it. * Create a challenge and send it.
*/ */
genrandom(chal, sizeof(chal)); genrandom(chal, sizeof(chal));
write(1, chal, sizeof(chal)); if(write(1, chal, sizeof(chal)) != sizeof(chal))
exits(0);
/* /*
* get chap reply * get chap reply
@ -734,15 +739,17 @@ mschap(Ticketreq *tr)
} }
safecpy(tr->uid, reply.uid, sizeof(tr->uid)); safecpy(tr->uid, reply.uid, sizeof(tr->uid));
if(tr->uid[0] == 0)
exits(0);
/* /*
* lookup * lookup
*/ */
secret = findsecret(KEYDB, tr->uid, sbuf); secret = findsecret(KEYDB, tr->uid, sbuf);
if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){ if(!getkey(tr->hostid, &hkey) || secret == nil){
replyerror("mschap-fail bad response %s/%s(%s)", replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
tr->uid, tr->hostid, raddr);
logfail(tr->uid); logfail(tr->uid);
exits(0); return;
} }
if(ntbloblen > 0){ if(ntbloblen > 0){
@ -756,14 +763,14 @@ mschap(Ticketreq *tr)
*/ */
s = hmac_md5(chal, 8, hash, MShashlen, nil, nil); s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
hmac_md5((uchar*)reply.LMresp+16, 8, hash, MShashlen, resp, s); hmac_md5((uchar*)reply.LMresp+16, 8, hash, MShashlen, resp, s);
lmok = memcmp(resp, reply.LMresp, 16) == 0; lmok = tsmemcmp(resp, reply.LMresp, 16) == 0;
/* /*
* NtResponse = Cat(HMAC_MD5(NtHash, Cat(SC, NtBlob)), NtBlob) * NtResponse = Cat(HMAC_MD5(NtHash, Cat(SC, NtBlob)), NtBlob)
*/ */
s = hmac_md5(chal, 8, hash, MShashlen, nil, nil); s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
hmac_md5(ntblob, ntbloblen, hash, MShashlen, resp, s); hmac_md5(ntblob, ntbloblen, hash, MShashlen, resp, s);
ntok = memcmp(resp, reply.NTresp, 16) == 0; ntok = tsmemcmp(resp, reply.NTresp, 16) == 0;
if(lmok || ntok || windom[0] == '\0') if(lmok || ntok || windom[0] == '\0')
break; break;
@ -774,11 +781,11 @@ mschap(Ticketreq *tr)
} else { } else {
lmhash(hash, secret); lmhash(hash, secret);
mschalresp(resp, hash, chal); mschalresp(resp, hash, chal);
lmok = memcmp(resp, reply.LMresp, MSresplen) == 0; lmok = tsmemcmp(resp, reply.LMresp, MSresplen) == 0;
nthash(hash, secret); nthash(hash, secret);
mschalresp(resp, hash, chal); mschalresp(resp, hash, chal);
ntok = memcmp(resp, reply.NTresp, MSresplen) == 0; ntok = tsmemcmp(resp, reply.NTresp, MSresplen) == 0;
dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0; dupe = tsmemcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
} }
/* /*
@ -795,10 +802,9 @@ mschap(Ticketreq *tr)
* windows clients don't seem to use the feature. * windows clients don't seem to use the feature.
*/ */
if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){ if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){
replyerror("mschap-fail bad response %s/%s(%s) %d,%d,%d", replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
tr->uid, tr->hostid, raddr, dupe, lmok, ntok);
logfail(tr->uid); logfail(tr->uid);
exits(0); return;
} }
succeed(tr->uid); succeed(tr->uid);
@ -806,11 +812,9 @@ mschap(Ticketreq *tr)
/* /*
* reply with ticket & authenticator * reply with ticket & authenticator
*/ */
if(tickauthreply(tr, &hkey) < 0) tickauthreply(tr, &hkey);
exits(0);
if(debug) syslog(0, AUTHLOG, "mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
replyerror("mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
nthash(hash, secret); nthash(hash, secret);
md4(hash, 16, hash2, 0); md4(hash, 16, hash2, 0);
@ -818,7 +822,7 @@ mschap(Ticketreq *tr)
sha1(hash2, 16, 0, s); sha1(hash2, 16, 0, s);
sha1(chal, 8, digest, s); sha1(chal, 8, digest, s);
if(write(1, digest, 16) < 0) if(write(1, digest, 16) != 16)
exits(0); exits(0);
} }
@ -997,10 +1001,35 @@ getraddr(char *dir)
} }
void void
mkkey(Authkey *k) initkeyseed(void)
{ {
genrandom((uchar*)k->des, DESKEYLEN); static char info[] = "PRF key for generation of dummy user keys";
genrandom((uchar*)k->aes, AESKEYLEN); char k[DESKEYLEN], *u;
u = getuser();
if(!finddeskey(KEYDB, u, k)){
syslog(0, AUTHLOG, "user %s not in keydb", u);
exits(0);
}
hmac_sha2_256((uchar*)info, sizeof(info)-1, (uchar*)k, sizeof(k), keyseed, nil);
memset(k, 0, sizeof(k));
}
void
mkkey(Keyslot *k)
{
uchar h[SHA2_256dlen];
Authkey *a = k;
genrandom((uchar*)a, sizeof(Authkey));
/*
* the DES key has to be constant for a user in each response,
* so we make one up pseudo randomly from a keyseed and user name.
*/
hmac_sha2_256((uchar*)k->id, strlen(k->id), keyseed, sizeof(keyseed), h, nil);
memmove(a->des, h, DESKEYLEN);
memset(h, 0, sizeof(h));
} }
void void
@ -1008,35 +1037,35 @@ mkticket(Ticketreq *tr, Ticket *t)
{ {
memset(t, 0, sizeof(Ticket)); memset(t, 0, sizeof(Ticket));
memmove(t->chal, tr->chal, CHALLEN); memmove(t->chal, tr->chal, CHALLEN);
safecpy(t->cuid, tr->uid, sizeof(t->cuid)); safecpy(t->cuid, tr->uid, ANAMELEN);
safecpy(t->suid, tr->uid, sizeof(t->suid)); safecpy(t->suid, tr->uid, ANAMELEN);
genrandom((uchar*)t->key, DESKEYLEN); genrandom(t->key, NONCELEN);
t->form = ticketform;
} }
/* /*
* reply with ticket and authenticator * reply with ticket and authenticator
*/ */
int void
tickauthreply(Ticketreq *tr, Authkey *hkey) tickauthreply(Ticketreq *tr, Authkey *key)
{ {
Ticket t; Ticket t;
Authenticator a; Authenticator a;
char buf[TICKETLEN+AUTHENTLEN+1]; char buf[MAXTICKETLEN+MAXAUTHENTLEN+1];
int n; int n;
mkticket(tr, &t); mkticket(tr, &t);
t.num = AuthTs; t.num = AuthTs;
n = 0; n = 0;
buf[n++] = AuthOK; buf[n++] = AuthOK;
n += convT2M(&t, buf+n, sizeof(buf)-n, hkey); n += convT2M(&t, buf+n, sizeof(buf)-n, key);
memset(&a, 0, sizeof(a)); memset(&a, 0, sizeof(a));
memmove(a.chal, t.chal, CHALLEN); memmove(a.chal, t.chal, CHALLEN);
genrandom(a.rand, NONCELEN);
a.num = AuthAc; a.num = AuthAc;
a.id = 0;
n += convA2M(&a, buf+n, sizeof(buf)-n, &t); n += convA2M(&a, buf+n, sizeof(buf)-n, &t);
if(write(1, buf, n) != n) if(write(1, buf, n) != n)
return -1; exits(0);
return 0;
} }
void void

View file

@ -43,6 +43,8 @@ main(int argc, char *argv[])
usage(); usage();
file = argv[0]; file = argv[0];
private();
/* get original key */ /* get original key */
if(usepass){ if(usepass){
print("enter password file is encoded with\n"); print("enter password file is encoded with\n");

View file

@ -116,8 +116,8 @@ readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
} }
} }
void authdialfutz(char*, char*); void authdialfutz(char*, char*, char*);
void authfutz(char*, char*); void authfutz(char*, char*, char*);
/* scan factotum for p9sk1 keys; check them */ /* scan factotum for p9sk1 keys; check them */
void void
@ -143,7 +143,7 @@ debugfactotumkeys(void)
a = _parseattr(s+4); a = _parseattr(s+4);
free(s); free(s);
proto = _strfindattr(a, "proto"); proto = _strfindattr(a, "proto");
if(proto==nil || strcmp(proto, "p9sk1")!=0) if(proto==nil || (strcmp(proto, "p9sk1")!=0 && strcmp(proto, "dp9ik")!=0))
continue; continue;
dom = _strfindattr(a, "dom"); dom = _strfindattr(a, "dom");
if(dom == nil){ if(dom == nil){
@ -157,17 +157,17 @@ debugfactotumkeys(void)
_freeattr(a); _freeattr(a);
continue; continue;
} }
print("p9sk1 key: %A\n", a); print("key: %A\n", a);
found = 1; found = 1;
authdialfutz(dom, user); authdialfutz(dom, user, proto);
_freeattr(a); _freeattr(a);
} }
if(!found) if(!found)
print("no p9sk1 keys found in factotum\n"); print("no p9sk1/dp9ik keys found in factotum\n");
} }
void void
authdialfutz(char *dom, char *user) authdialfutz(char *dom, char *user, char *proto)
{ {
int fd; int fd;
char *server; char *server;
@ -177,7 +177,7 @@ authdialfutz(char *dom, char *user)
if(fd >= 0){ if(fd >= 0){
print("\tsuccessfully dialed auth server\n"); print("\tsuccessfully dialed auth server\n");
close(fd); close(fd);
authfutz(dom, user); authfutz(dom, user, proto);
return; return;
} }
print("\tcannot dial auth server: %r\n"); print("\tcannot dial auth server: %r\n");
@ -205,11 +205,44 @@ authdialfutz(char *dom, char *user)
print("\tdial %s failed: %r\n", addr); print("\tdial %s failed: %r\n", addr);
} }
int
getpakkeys(int fd, Ticketreq *tr, Authkey *akey, Authkey *hkey)
{
uchar y[PAKYLEN];
PAKpriv p;
int ret, type;
ret = -1;
type = tr->type;
tr->type = AuthPAK;
if(_asrequest(fd, tr) < 0 || _asrdresp(fd, (char*)y, 0) < 0)
goto out;
authpak_hash(akey, tr->authid);
authpak_new(&p, akey, y, 1);
if(write(fd, y, PAKYLEN) != PAKYLEN
|| readn(fd, y, PAKYLEN) != PAKYLEN
|| authpak_finish(&p, akey, y))
goto out;
authpak_hash(hkey, tr->hostid);
authpak_new(&p, hkey, y, 1);
if(write(fd, y, PAKYLEN) != PAKYLEN
|| readn(fd, y, PAKYLEN) != PAKYLEN
|| authpak_finish(&p, hkey, y))
goto out;
ret = 0;
out:
tr->type = type;
return ret;
}
void void
authfutz(char *dom, char *user) authfutz(char *dom, char *user, char *proto)
{ {
int fd, nobootes, n, m; int fd, nobootes, n, m;
char pw[128], prompt[128], tbuf[2*TICKETLEN]; char pw[128], prompt[128], tbuf[2*MAXTICKETLEN];
Authkey key, booteskey; Authkey key, booteskey;
Ticket t; Ticket t;
Ticketreq tr; Ticketreq tr;
@ -219,6 +252,7 @@ authfutz(char *dom, char *user)
if(pw[0] == '\0') if(pw[0] == '\0')
return; return;
passtokey(&key, pw); passtokey(&key, pw);
booteskey = key;
fd = authdial(nil, dom); fd = authdial(nil, dom);
if(fd < 0){ if(fd < 0){
@ -234,6 +268,13 @@ authfutz(char *dom, char *user)
strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user); strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
strecpy(tr.uid, tr.uid+sizeof tr.uid, user); strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
memset(tr.chal, 0xAA, sizeof tr.chal); memset(tr.chal, 0xAA, sizeof tr.chal);
if(strcmp(proto, "dp9ik") == 0 && getpakkeys(fd, &tr, &booteskey, &key) < 0){
print("\tgetpakkeys failed: %r\n");
close(fd);
return;
}
if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){ if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){
print("\t_asgetticket failed: %r\n"); print("\t_asgetticket failed: %r\n");
close(fd); close(fd);
@ -252,7 +293,7 @@ authfutz(char *dom, char *user)
return; return;
} }
convM2T(tbuf+m, n-m, &t, &key); convM2T(tbuf+m, n-m, &t, &booteskey);
if(t.num != AuthTs){ if(t.num != AuthTs){
print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num); print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
print("\tauth server and you do not agree on key for %s@%s\n", user, dom); print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
@ -269,9 +310,24 @@ authfutz(char *dom, char *user)
/* try ticket request using bootes key */ /* try ticket request using bootes key */
snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom); snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
readcons(prompt, "glenda", 0, tr.authid, sizeof tr.authid); readcons(prompt, "glenda", 0, tr.authid, sizeof tr.authid);
if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){ snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
readcons(prompt, nil, 1, pw, sizeof pw);
if(pw[0] == '\0'){
nobootes=1;
goto Nobootes;
}
nobootes = 0;
passtokey(&booteskey, pw);
if(strcmp(proto, "dp9ik") == 0 && getpakkeys(fd, &tr, &booteskey, &key) < 0){
print("\tgetpakkeys failed: %r\n");
close(fd); close(fd);
return;
}
if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){
print("\t_asgetticket failed: %r\n"); print("\t_asgetticket failed: %r\n");
close(fd);
return; return;
} }
m = convM2T(tbuf, n, &t, &key); m = convM2T(tbuf, n, &t, &key);
@ -287,15 +343,6 @@ authfutz(char *dom, char *user)
return; return;
} }
snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
readcons(prompt, nil, 1, pw, sizeof pw);
if(pw[0] == '\0'){
nobootes=1;
goto Nobootes;
}
nobootes = 0;
passtokey(&booteskey, pw);
convM2T(tbuf+m, n-m, &t, &booteskey); convM2T(tbuf+m, n-m, &t, &booteskey);
if(t.num != AuthTs){ if(t.num != AuthTs){
print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num); print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
@ -321,7 +368,6 @@ Nobootes:;
* auth server (assumes running cpu service) * auth server (assumes running cpu service)
* to test that bootes key is right over there * to test that bootes key is right over there
*/ */
} }
void void

View file

@ -20,6 +20,7 @@ struct State
int asfd; int asfd;
int astype; int astype;
Key *key; Key *key;
Authkey k;
Ticket t; Ticket t;
Ticketreq tr; Ticketreq tr;
char chal[128]; char chal[128];
@ -213,29 +214,23 @@ dochal(State *s)
s->asfd = -1; s->asfd = -1;
/* send request to authentication server and get challenge */
/* send request to authentication server and get challenge */ /* send request to authentication server and get challenge */
if((dom = _strfindattr(s->key->attr, "dom")) == nil if((dom = _strfindattr(s->key->attr, "dom")) == nil
|| (user = _strfindattr(s->key->attr, "user")) == nil){ || (user = _strfindattr(s->key->attr, "user")) == nil){
werrstr("apop/dochal cannot happen"); werrstr("apop/dochal cannot happen");
goto err; goto err;
} }
memmove(&s->k, s->key->priv, sizeof(Authkey));
s->asfd = _authdial(nil, dom);
/* could generate our own challenge on error here */
if(s->asfd < 0)
goto err;
memset(&s->tr, 0, sizeof(s->tr)); memset(&s->tr, 0, sizeof(s->tr));
safecpy(s->tr.authdom, dom, sizeof s->tr.authdom); safecpy(s->tr.authdom, dom, sizeof s->tr.authdom);
safecpy(s->tr.hostid, user, sizeof(s->tr.hostid)); safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
s->tr.type = s->astype; s->tr.type = s->astype;
alarm(30*1000);
if(_asrequest(s->asfd, &s->tr) < 0){ s->asfd = _authreq(&s->tr, &s->k);
alarm(0); if(s->asfd < 0)
goto err; goto err;
} alarm(30*1000);
n = _asrdresp(s->asfd, s->chal, sizeof s->chal); n = _asrdresp(s->asfd, s->chal, sizeof s->chal);
alarm(0); alarm(0);
if(n <= 5) if(n <= 5)
@ -272,7 +267,7 @@ doreply(State *s, char *user, char *response)
alarm(0); alarm(0);
goto err; goto err;
} }
n = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv); n = _asgetresp(s->asfd, &s->t, &a, &s->k);
alarm(0); alarm(0);
if(n < 0){ if(n < 0){
/* leave connection open so we can try again */ /* leave connection open so we can try again */
@ -282,7 +277,7 @@ doreply(State *s, char *user, char *response)
s->asfd = -1; s->asfd = -1;
if(s->t.num != AuthTs if(s->t.num != AuthTs
|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){ || tsmemcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
if(s->key->successes == 0) if(s->key->successes == 0)
disablekey(s->key); disablekey(s->key);
werrstr(Easproto); werrstr(Easproto);
@ -290,8 +285,7 @@ doreply(State *s, char *user, char *response)
} }
s->key->successes++; s->key->successes++;
if(a.num != AuthAc if(a.num != AuthAc
|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0 || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0){
|| a.id != 0){
werrstr(Easproto); werrstr(Easproto);
goto err; goto err;
} }

View file

@ -41,6 +41,7 @@ struct State
int astype; int astype;
int asfd; int asfd;
Key *key; Key *key;
Authkey k;
Ticket t; Ticket t;
Ticketreq tr; Ticketreq tr;
char chal[ChapChallen]; char chal[ChapChallen];
@ -309,19 +310,18 @@ dochal(State *s)
werrstr("chap/dochal cannot happen"); werrstr("chap/dochal cannot happen");
goto err; goto err;
} }
s->asfd = _authdial(nil, dom); memmove(&s->k, s->key->priv, sizeof(Authkey));
if(s->asfd < 0)
goto err;
memset(&s->tr, 0, sizeof(s->tr)); memset(&s->tr, 0, sizeof(s->tr));
safecpy(s->tr.authdom, dom, sizeof(s->tr.authdom)); safecpy(s->tr.authdom, dom, sizeof(s->tr.authdom));
safecpy(s->tr.hostid, user, sizeof(s->tr.hostid)); safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
s->tr.type = s->astype; s->tr.type = s->astype;
alarm(30*1000);
if(_asrequest(s->asfd, &s->tr) < 0){ s->asfd = _authreq(&s->tr, &s->k);
alarm(0); if(s->asfd < 0)
goto err; goto err;
}
alarm(30*1000);
n = readn(s->asfd, s->chal, sizeof s->chal); n = readn(s->asfd, s->chal, sizeof s->chal);
alarm(0); alarm(0);
if(n != sizeof s->chal) if(n != sizeof s->chal)
@ -347,7 +347,7 @@ doreply(State *s, uchar *reply, int nreply)
alarm(0); alarm(0);
goto err; goto err;
} }
n = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv); n = _asgetresp(s->asfd, &s->t, &a, &s->k);
if(n < 0){ if(n < 0){
alarm(0); alarm(0);
/* leave connection open so we can try again */ /* leave connection open so we can try again */
@ -361,7 +361,7 @@ doreply(State *s, uchar *reply, int nreply)
s->asfd = -1; s->asfd = -1;
if(s->t.num != AuthTs if(s->t.num != AuthTs
|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){ || tsmemcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
if(s->key->successes == 0) if(s->key->successes == 0)
disablekey(s->key); disablekey(s->key);
werrstr(Easproto); werrstr(Easproto);
@ -369,8 +369,7 @@ doreply(State *s, uchar *reply, int nreply)
} }
s->key->successes++; s->key->successes++;
if(a.num != AuthAc if(a.num != AuthAc
|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0 || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0){
|| a.id != 0){
werrstr(Easproto); werrstr(Easproto);
return -1; return -1;
} }

View file

@ -16,16 +16,19 @@ confirmflush(Req *r)
{ {
Req **l; Req **l;
qlock(&confbuf);
for(l=&cusewait; *l; l=&(*l)->aux){ for(l=&cusewait; *l; l=&(*l)->aux){
if(*l == r){ if(*l == r){
*l = r->aux; *l = r->aux;
if(r->aux == nil) if(r->aux == nil)
cuselast = l; cuselast = l;
r->aux = nil; r->aux = nil;
qunlock(&confbuf);
respond(r, "interrupted"); respond(r, "interrupted");
return; return;
} }
} }
qunlock(&confbuf);
logbufflush(&confbuf, r); logbufflush(&confbuf, r);
} }
@ -43,7 +46,7 @@ hastag(Fsstate *fss, int tag, int *tagoff)
} }
int int
confirmwrite(char *s) confirmwrite(Srv *srv, char *s)
{ {
char *t, *ans; char *t, *ans;
int allow, tagoff; int allow, tagoff;
@ -54,15 +57,18 @@ confirmwrite(char *s)
a = _parseattr(s); a = _parseattr(s);
if(a == nil){ if(a == nil){
_freeattr(a);
werrstr("empty write"); werrstr("empty write");
return -1; return -1;
} }
if((t = _strfindattr(a, "tag")) == nil){ if((t = _strfindattr(a, "tag")) == nil){
_freeattr(a);
werrstr("no tag"); werrstr("no tag");
return -1; return -1;
} }
tag = strtoul(t, 0, 0); tag = strtoul(t, 0, 0);
if((ans = _strfindattr(a, "answer")) == nil){ if((ans = _strfindattr(a, "answer")) == nil){
_freeattr(a);
werrstr("no answer"); werrstr("no answer");
return -1; return -1;
} }
@ -71,14 +77,18 @@ confirmwrite(char *s)
else if(strcmp(ans, "no") == 0) else if(strcmp(ans, "no") == 0)
allow = 0; allow = 0;
else{ else{
_freeattr(a);
werrstr("bad answer"); werrstr("bad answer");
return -1; return -1;
} }
r = nil; _freeattr(a);
srvrelease(srv);
qlock(&confbuf);
fss = nil;
tagoff = -1; tagoff = -1;
for(l=&cusewait; *l; l=&(*l)->aux){ for(l=&cusewait; (r = *l) != nil; l=&(*l)->aux){
r = *l; fss = r->fid->aux;
if(hastag(r->fid->aux, tag, &tagoff)){ if(hastag(fss, tag, &tagoff)){
*l = r->aux; *l = r->aux;
if(r->aux == nil) if(r->aux == nil)
cuselast = l; cuselast = l;
@ -86,13 +96,17 @@ confirmwrite(char *s)
break; break;
} }
} }
qunlock(&confbuf);
if(r == nil || tagoff == -1){ if(r == nil || tagoff == -1){
srvacquire(srv);
werrstr("tag not found"); werrstr("tag not found");
return -1; return -1;
} }
fss = r->fid->aux; qlock(fss);
fss->conf[tagoff].canuse = allow; fss->conf[tagoff].canuse = allow;
rpcread(r); rpcread(r);
qunlock(fss);
srvacquire(srv);
return 0; return 0;
} }
@ -118,9 +132,11 @@ confirmqueue(Req *r, Fsstate *fss)
respond(r, "no confirmations to wait for (bug)"); respond(r, "no confirmations to wait for (bug)");
return; return;
} }
*cuselast = r; qlock(&confbuf);
r->aux = nil; r->aux = nil;
*cuselast = r;
cuselast = &r->aux; cuselast = &r->aux;
qunlock(&confbuf);
} }
/* Yes, I am unhappy that the code below is a copy of the code above. */ /* Yes, I am unhappy that the code below is a copy of the code above. */
@ -140,38 +156,45 @@ needkeyflush(Req *r)
{ {
Req **l; Req **l;
qlock(&needkeybuf);
for(l=&needwait; *l; l=&(*l)->aux){ for(l=&needwait; *l; l=&(*l)->aux){
if(*l == r){ if(*l == r){
*l = r->aux; *l = r->aux;
if(r->aux == nil) if(r->aux == nil)
needlast = l; needlast = l;
r->aux = nil; r->aux = nil;
qunlock(&needkeybuf);
respond(r, "interrupted"); respond(r, "interrupted");
return; return;
} }
} }
qunlock(&needkeybuf);
logbufflush(&needkeybuf, r); logbufflush(&needkeybuf, r);
} }
int int
needkeywrite(char *s) needkeywrite(Srv *srv, char *s)
{ {
char *t; char *t;
ulong tag; ulong tag;
Attr *a; Attr *a;
Req *r, **l; Req *r, **l;
Fsstate *fss;
a = _parseattr(s); a = _parseattr(s);
if(a == nil){ if(a == nil){
_freeattr(a);
werrstr("empty write"); werrstr("empty write");
return -1; return -1;
} }
if((t = _strfindattr(a, "tag")) == nil){ if((t = _strfindattr(a, "tag")) == nil){
_freeattr(a);
werrstr("no tag"); werrstr("no tag");
return -1; return -1;
} }
tag = strtoul(t, 0, 0); tag = strtoul(t, 0, 0);
r = nil; r = nil;
qlock(&needkeybuf);
for(l=&needwait; *l; l=&(*l)->aux){ for(l=&needwait; *l; l=&(*l)->aux){
r = *l; r = *l;
if(r->tag == tag){ if(r->tag == tag){
@ -182,15 +205,23 @@ needkeywrite(char *s)
break; break;
} }
} }
qunlock(&needkeybuf);
if(r == nil){ if(r == nil){
_freeattr(a);
werrstr("tag not found"); werrstr("tag not found");
return -1; return -1;
} }
fss = r->fid->aux;
srvrelease(srv);
qlock(fss);
if(s = _strfindattr(a, "error")){ if(s = _strfindattr(a, "error")){
werrstr("%s", s); werrstr("%s", s);
retrpc(r, RpcErrstr, (Fsstate*)r->fid->aux); retrpc(r, RpcErrstr, fss);
}else }else
rpcread(r); rpcread(r);
_freeattr(a);
qunlock(fss);
srvacquire(srv);
return 0; return 0;
} }
@ -204,9 +235,13 @@ needkeyqueue(Req *r, Fsstate *fss)
snprint(msg, sizeof msg, "needkey tag=%lud %s", r->tag, fss->keyinfo); snprint(msg, sizeof msg, "needkey tag=%lud %s", r->tag, fss->keyinfo);
logbufappend(&needkeybuf, msg); logbufappend(&needkeybuf, msg);
*needlast = r;
qlock(&needkeybuf);
r->aux = nil; r->aux = nil;
*needlast = r;
needlast = &r->aux; needlast = &r->aux;
qunlock(&needkeybuf);
return 0; return 0;
} }

View file

@ -45,6 +45,7 @@ typedef struct State State;
struct Fsstate struct Fsstate
{ {
QLock;
char *sysuser; /* user according to system */ char *sysuser; /* user according to system */
/* keylist, protolist */ /* keylist, protolist */
@ -76,7 +77,8 @@ struct Fsstate
struct Key struct Key
{ {
int ref; Ref;
Attr *attr; Attr *attr;
Attr *privattr; /* private attributes, like *data */ Attr *privattr; /* private attributes, like *data */
Proto *proto; Proto *proto;
@ -97,12 +99,16 @@ struct Keyinfo /* for findkey */
struct Keyring struct Keyring
{ {
QLock;
Key **key; Key **key;
int nkey; int nkey;
}; };
struct Logbuf struct Logbuf
{ {
QLock;
Req *wait; Req *wait;
Req **waitlast; Req **waitlast;
int rp; int rp;
@ -133,11 +139,11 @@ extern char Etoolarge[];
/* confirm.c */ /* confirm.c */
void confirmread(Req*); void confirmread(Req*);
void confirmflush(Req*); void confirmflush(Req*);
int confirmwrite(char*); int confirmwrite(Srv*, char*);
void confirmqueue(Req*, Fsstate*); void confirmqueue(Req*, Fsstate*);
void needkeyread(Req*); void needkeyread(Req*);
void needkeyflush(Req*); void needkeyflush(Req*);
int needkeywrite(char*); int needkeywrite(Srv*, char*);
int needkeyqueue(Req*, Fsstate*); int needkeyqueue(Req*, Fsstate*);
/* fs.c */ /* fs.c */
@ -162,12 +168,7 @@ void logread(Req*);
void logflush(Req*); void logflush(Req*);
void logbufflush(Logbuf*, Req*); void logbufflush(Logbuf*, Req*);
void logbufread(Logbuf*, Req*); void logbufread(Logbuf*, Req*);
void logbufproc(Logbuf*);
void logbufappend(Logbuf*, char*); void logbufappend(Logbuf*, char*);
void needkeyread(Req*);
void needkeyflush(Req*);
int needkeywrite(char*);
int needkeyqueue(Req*, Fsstate*);
/* rpc.c */ /* rpc.c */
int ctlwrite(char*, int); int ctlwrite(char*, int);
@ -185,7 +186,8 @@ void retrpc(Req*, int, Fsstate*);
#pragma varargck argpos findkey 3 #pragma varargck argpos findkey 3
#pragma varargck argpos setattr 2 #pragma varargck argpos setattr 2
int _authdial(char*, char*); int _authdial(char*);
int _authreq(Ticketreq *, Authkey *);
void askuser(char*); void askuser(char*);
int attrnamefmt(Fmt *fmt); int attrnamefmt(Fmt *fmt);
int canusekey(Fsstate*, Key*); int canusekey(Fsstate*, Key*);
@ -199,7 +201,7 @@ Keyinfo* mkkeyinfo(Keyinfo*, Fsstate*, Attr*);
int findkey(Key**, Keyinfo*, char*, ...); int findkey(Key**, Keyinfo*, char*, ...);
int findp9authkey(Key**, Fsstate*); int findp9authkey(Key**, Fsstate*);
Proto *findproto(char*); Proto *findproto(char*);
char *getnvramkey(int); int getnvramkey(int);
void initcap(void); void initcap(void);
int isclient(char*); int isclient(char*);
int matchattr(Attr*, Attr*, Attr*); int matchattr(Attr*, Attr*, Attr*);
@ -221,7 +223,7 @@ void writehostowner(char*);
/* protocols */ /* protocols */
extern Proto apop, cram; /* apop.c */ extern Proto apop, cram; /* apop.c */
extern Proto p9any, p9sk1, p9sk2; /* p9sk.c */ extern Proto p9any, p9sk1, dp9ik; /* p9sk.c */
extern Proto chap, mschap, mschapv2, mschap2; /* chap.c */ extern Proto chap, mschap, mschapv2, mschap2; /* chap.c */
extern Proto p9cr, vnc; /* p9cr.c */ extern Proto p9cr, vnc; /* p9cr.c */
extern Proto pass; /* pass.c */ extern Proto pass; /* pass.c */
@ -231,4 +233,3 @@ extern Proto wep; /* wep.c */
extern Proto httpdigest; /* httpdigest.c */ extern Proto httpdigest; /* httpdigest.c */
extern Proto ecdsa; /* ecdsa.c */ extern Proto ecdsa; /* ecdsa.c */
extern Proto wpapsk; /* wpapsk.c */ extern Proto wpapsk; /* wpapsk.c */

View file

@ -36,7 +36,7 @@ prototab[] =
&p9any, &p9any,
&p9cr, &p9cr,
&p9sk1, &p9sk1,
&p9sk2, &dp9ik,
&pass, &pass,
/* &srs, */ /* &srs, */
&rsa, &rsa,
@ -148,15 +148,8 @@ main(int argc, char **argv)
} }
if(sflag){ if(sflag){
s = getnvramkey(kflag ? NVwrite : NVwriteonerr); if(getnvramkey(kflag ? NVwrite : NVwriteonerr) < 0)
if(s == nil)
fprint(2, "factotum warning: cannot read nvram: %r\n"); fprint(2, "factotum warning: cannot read nvram: %r\n");
else if(ctlwrite(s, 0) < 0)
fprint(2, "factotum warning: cannot add nvram key: %r\n");
if (s != nil) {
memset(s, 0, strlen(s));
free(s);
}
} else if(uflag) } else if(uflag)
promptforhostowner(); promptforhostowner();
owner = getuser(); owner = getuser();
@ -418,9 +411,11 @@ fsdestroyfid(Fid *fid)
fss = fid->aux; fss = fid->aux;
if(fss == nil) if(fss == nil)
return; return;
qlock(fss);
if(fss->ps) if(fss->ps)
(*fss->proto->close)(fss); (*fss->proto->close)(fss);
_freeattr(fss->attr); _freeattr(fss->attr);
qunlock(fss);
free(fss); free(fss);
} }
@ -452,14 +447,14 @@ keylist(int i, char *a, uint n, Fsstate *fss)
int wb; int wb;
Keyinfo ki; Keyinfo ki;
Key *k; Key *k;
static char zero[Nearend];
k = nil; k = nil;
mkkeyinfo(&ki, fss, nil); mkkeyinfo(&ki, fss, nil);
ki.attr = nil; ki.attr = nil;
ki.noconf = 1;
ki.skip = i; ki.skip = i;
ki.usedisabled = 1; ki.usedisabled = 1;
if(findkey(&k, &ki, "") != RpcOk) if(findkey(&k, &ki, nil) != RpcOk)
return 0; return 0;
memset(a + n - Nearend, 0, Nearend); memset(a + n - Nearend, 0, Nearend);
@ -488,6 +483,24 @@ protolist(int i, char *a, uint n, Fsstate *fss)
return n; return n;
} }
static void
fsrpcio(Req *r)
{
Fsstate *fss;
Srv *srv;
fss = r->fid->aux;
srv = r->srv;
srvrelease(srv);
qlock(fss);
if(r->ifcall.type == Tread)
rpcread(r);
else
rpcwrite(r);
qunlock(fss);
srvacquire(srv);
}
static void static void
fsread(Req *r) fsread(Req *r)
{ {
@ -507,7 +520,7 @@ fsread(Req *r)
respond(r, nil); respond(r, nil);
break; break;
case Qrpc: case Qrpc:
rpcread(r); fsrpcio(r);
break; break;
case Qneedkey: case Qneedkey:
needkeyread(r); needkeyread(r);
@ -540,7 +553,7 @@ fswrite(Req *r)
respond(r, "bug in fswrite"); respond(r, "bug in fswrite");
break; break;
case Qrpc: case Qrpc:
rpcwrite(r); fsrpcio(r);
break; break;
case Qneedkey: case Qneedkey:
case Qconfirm: case Qconfirm:
@ -552,10 +565,10 @@ fswrite(Req *r)
default: default:
abort(); abort();
case Qneedkey: case Qneedkey:
ret = needkeywrite(s); ret = needkeywrite(r->srv, s);
break; break;
case Qconfirm: case Qconfirm:
ret = confirmwrite(s); ret = confirmwrite(r->srv, s);
break; break;
case Qctl: case Qctl:
ret = ctlwrite(s, 0); ret = ctlwrite(s, 0);

View file

@ -1,6 +1,6 @@
#include "dat.h" #include "dat.h"
void static void
logbufproc(Logbuf *lb) logbufproc(Logbuf *lb)
{ {
char *s; char *s;
@ -43,12 +43,14 @@ logbufproc(Logbuf *lb)
void void
logbufread(Logbuf *lb, Req *r) logbufread(Logbuf *lb, Req *r)
{ {
qlock(lb);
if(lb->waitlast == nil) if(lb->waitlast == nil)
lb->waitlast = &lb->wait; lb->waitlast = &lb->wait;
*(lb->waitlast) = r; *(lb->waitlast) = r;
lb->waitlast = &r->aux; lb->waitlast = &r->aux;
r->aux = nil; r->aux = nil;
logbufproc(lb); logbufproc(lb);
qunlock(lb);
} }
void void
@ -56,6 +58,7 @@ logbufflush(Logbuf *lb, Req *r)
{ {
Req **l; Req **l;
qlock(lb);
for(l=&lb->wait; *l; l=&(*l)->aux){ for(l=&lb->wait; *l; l=&(*l)->aux){
if(*l == r){ if(*l == r){
*l = r->aux; *l = r->aux;
@ -66,6 +69,7 @@ logbufflush(Logbuf *lb, Req *r)
break; break;
} }
} }
qunlock(lb);
} }
void void
@ -74,12 +78,14 @@ logbufappend(Logbuf *lb, char *buf)
if(debug) if(debug)
fprint(2, "%s\n", buf); fprint(2, "%s\n", buf);
qlock(lb);
if(lb->msg[lb->wp]) if(lb->msg[lb->wp])
free(lb->msg[lb->wp]); free(lb->msg[lb->wp]);
lb->msg[lb->wp] = estrdup9p(buf); lb->msg[lb->wp] = estrdup9p(buf);
if(++lb->wp == nelem(lb->msg)) if(++lb->wp == nelem(lb->msg))
lb->wp = 0; lb->wp = 0;
logbufproc(lb); logbufproc(lb);
qunlock(lb);
} }
Logbuf logbuf; Logbuf logbuf;

View file

@ -13,7 +13,8 @@
#include "dat.h" #include "dat.h"
static Proto *negotiable[] = { static Proto *negotiable[] = {
&p9sk1, &p9sk1, /* has to be first because of drawterm bug */
&dp9ik,
}; };
struct State struct State
@ -98,6 +99,7 @@ setupfss(Fsstate *fss, State *s, Key *k)
fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name); fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name);
fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom")); fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom"));
s->subfss.attr = fss->attr; s->subfss.attr = fss->attr;
s->subfss.proto = s->subproto;
s->subfss.phase = Notstarted; s->subfss.phase = Notstarted;
s->subfss.sysuser = fss->sysuser; s->subfss.sysuser = fss->sysuser;
s->subfss.seqnum = fss->seqnum; s->subfss.seqnum = fss->seqnum;
@ -229,8 +231,8 @@ getdom(char *p)
return p+1; return p+1;
} }
static Proto* static int
findneg(char *name) findprotox(char *name)
{ {
int i, len; int i, len;
char *p; char *p;
@ -239,13 +241,27 @@ findneg(char *name)
len = p-name; len = p-name;
else else
len = strlen(name); len = strlen(name);
for(i=0; i<nelem(negotiable); i++) for(i=0; i<nelem(negotiable); i++)
if(strncmp(negotiable[i]->name, name, len) == 0 && negotiable[i]->name[len] == 0) if(strncmp(negotiable[i]->name, name, len) == 0 && negotiable[i]->name[len] == 0)
return negotiable[i]; return i;
return -1;
}
static Proto*
findneg(char *name)
{
int x = findprotox(name);
if(x >= 0)
return negotiable[x];
return nil; return nil;
} }
static int
protopref(void *a, void *b)
{
return findprotox(*(char**)b) - findprotox(*(char**)a);
}
static int static int
p9anywrite(Fsstate *fss, void *va, uint n) p9anywrite(Fsstate *fss, void *va, uint n)
{ {
@ -274,7 +290,11 @@ p9anywrite(Fsstate *fss, void *va, uint n)
free(a); free(a);
return failure(fss, "unknown version of p9any"); return failure(fss, "unknown version of p9any");
} }
if(--m > 0)
memmove(token, token+1, m*sizeof(token[0]));
} }
/* put prefered protocols first */
qsort(token, m, sizeof(token[0]), protopref);
/* /*
* look for a key * look for a key
@ -285,7 +305,7 @@ p9anywrite(Fsstate *fss, void *va, uint n)
k = nil; k = nil;
p = nil; p = nil;
dom = nil; dom = nil;
for(i=(s->version==1?0:1); i<m; i++){ for(i=0; i<m; i++){
p = findneg(token[i]); p = findneg(token[i]);
if(p == nil) if(p == nil)
continue; continue;

View file

@ -24,6 +24,7 @@ struct State
Key *key; Key *key;
int astype; int astype;
int asfd; int asfd;
Authkey k;
Ticket t; Ticket t;
Ticketreq tr; Ticketreq tr;
char chal[Maxchal]; char chal[Maxchal];
@ -165,18 +166,14 @@ p9crread(Fsstate *fss, void *va, uint *n)
static int static int
p9response(Fsstate *fss, State *s) p9response(Fsstate *fss, State *s)
{ {
Authkey key; Authkey *akey;
uchar buf[8]; uchar buf[8];
ulong chal; ulong chal;
char *pw;
pw = _strfindattr(s->key->privattr, "!password");
if(pw == nil)
return failure(fss, "vncresponse cannot happen");
passtokey(&key, pw);
memset(buf, 0, 8); memset(buf, 0, 8);
sprint((char*)buf, "%d", atoi(s->chal)); sprint((char*)buf, "%d", atoi(s->chal));
if(encrypt(key.des, buf, 8) < 0) akey = (Authkey*)s->key->priv;
if(encrypt(akey->des, buf, 8) < 0)
return failure(fss, "can't encrypt response"); return failure(fss, "can't encrypt response");
chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3]; chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal); s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal);
@ -287,7 +284,7 @@ p9crwrite(Fsstate *fss, void *va, uint n)
return failure(fss, Easproto); return failure(fss, Easproto);
} }
/* get ticket plus authenticator from auth server */ /* get ticket plus authenticator from auth server */
ret = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv); ret = _asgetresp(s->asfd, &s->t, &a, &s->k);
alarm(0); alarm(0);
if(ret < 0) if(ret < 0)
@ -295,15 +292,14 @@ p9crwrite(Fsstate *fss, void *va, uint n)
/* check ticket */ /* check ticket */
if(s->t.num != AuthTs if(s->t.num != AuthTs
|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){ || tsmemcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
if (s->key->successes == 0) if (s->key->successes == 0)
disablekey(s->key); disablekey(s->key);
return failure(fss, Easproto); return failure(fss, Easproto);
} }
s->key->successes++; s->key->successes++;
if(a.num != AuthAc if(a.num != AuthAc
|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0 || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0)
|| a.id != 0)
return failure(fss, Easproto); return failure(fss, Easproto);
fss->haveai = 1; fss->haveai = 1;
@ -321,19 +317,16 @@ getchal(State *s, Fsstate *fss)
{ {
int n; int n;
memmove(&s->k, s->key->priv, sizeof(Authkey));
safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof(s->tr.hostid)); safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof(s->tr.hostid));
safecpy(s->tr.authdom, _strfindattr(s->key->attr, "dom"), sizeof(s->tr.authdom)); safecpy(s->tr.authdom, _strfindattr(s->key->attr, "dom"), sizeof(s->tr.authdom));
s->tr.type = s->astype; s->tr.type = s->astype;
/* get challenge from auth server */ s->asfd = _authreq(&s->tr, &s->k);
s->asfd = _authdial(nil, _strfindattr(s->key->attr, "dom"));
if(s->asfd < 0) if(s->asfd < 0)
return failure(fss, Easproto); return failure(fss, Easproto);
alarm(30*1000); alarm(30*1000);
if(_asrequest(s->asfd, &s->tr) < 0){
alarm(0);
return failure(fss, Easproto);
}
n = _asrdresp(s->asfd, s->chal, s->challen); n = _asrdresp(s->asfd, s->chal, s->challen);
alarm(0); alarm(0);
if(n <= 0){ if(n <= 0){

View file

@ -1,30 +1,38 @@
/* /*
* p9sk1, p9sk2 - Plan 9 secret (private) key authentication. * p9sk1, dp9ik - Plan 9 secret (private) key authentication.
* p9sk2 is an incomplete flawed variant of p9sk1. * dp9ik uses AuthPAK diffie hellman key exchange with the
* auth server to protect the password derived key from offline
* dictionary attacks.
* *
* Client protocol: * Client protocol:
* write challenge[challen] (p9sk1 only) * write challenge[challen]
* read tickreq[tickreqlen] * read pakreq[ticketreqlen + pakylen] (dp9ik only)
* write ticket[ticketlen] * write paky[pakylen]
* read authenticator[authentlen] * read tickreq[tickreqlen] (p9sk1 only)
* write ticket + authenticator
* read authenticator
* *
* Server protocol: * Server protocol:
* read challenge[challen] (p9sk1 only) * read challenge[challen]
* write tickreq[tickreqlen] * write pakreq[ticketreqlen + pakylen] (dp9ik only)
* read ticket[ticketlen] * read paky[pakylen]
* write authenticator[authentlen] * write tickreq[tickreqlen] (p9sk1 only)
* read ticket + authenticator
* write authenticator
*/ */
#include "dat.h" #include "dat.h"
struct State struct State
{ {
int vers;
Key *key; Key *key;
Ticket t; Ticket t;
Ticketreq tr; Ticketreq tr;
Authkey k;
PAKpriv p;
char cchal[CHALLEN]; char cchal[CHALLEN];
char tbuf[TICKETLEN+AUTHENTLEN]; uchar y[PAKYLEN], rand[2*NONCELEN];
char tbuf[MAXTICKETLEN + MAXAUTHENTLEN];
int tbuflen; int tbuflen;
uchar *secret; uchar *secret;
int speakfor; int speakfor;
@ -34,13 +42,17 @@ enum
{ {
/* client phases */ /* client phases */
CHaveChal, CHaveChal,
CNeedTreq, CNeedPAKreq, /* dp9ik only */
CHavePAKy,
CNeedTreq, /* p9sk1 only */
CHaveTicket, CHaveTicket,
CNeedAuth, CNeedAuth,
/* server phases */ /* server phases */
SNeedChal, SNeedChal,
SHaveTreq, SHavePAKreq, /* dp9ik only */
SNeedPAKy,
SHaveTreq, /* p9sk1 only */
SNeedTicket, SNeedTicket,
SHaveAuth, SHaveAuth,
@ -50,17 +62,21 @@ enum
static char *phasenames[Maxphase] = static char *phasenames[Maxphase] =
{ {
[CHaveChal] "CHaveChal", [CHaveChal] "CHaveChal",
[CNeedPAKreq] "CNeedPAKreq",
[CHavePAKy] "CHavePAKy",
[CNeedTreq] "CNeedTreq", [CNeedTreq] "CNeedTreq",
[CHaveTicket] "CHaveTicket", [CHaveTicket] "CHaveTicket",
[CNeedAuth] "CNeedAuth", [CNeedAuth] "CNeedAuth",
[SNeedChal] "SNeedChal", [SNeedChal] "SNeedChal",
[SHavePAKreq] "SHavePAKreq",
[SNeedPAKy] "SNeedPAKy",
[SHaveTreq] "SHaveTreq", [SHaveTreq] "SHaveTreq",
[SNeedTicket] "SNeedTicket", [SNeedTicket] "SNeedTicket",
[SHaveAuth] "SHaveAuth", [SHaveAuth] "SHaveAuth",
}; };
static int gettickets(State*, Ticketreq *, char*, int); static int gettickets(State*, Ticketreq*, uchar*, char*, int);
static int static int
p9skinit(Proto *p, Fsstate *fss) p9skinit(Proto *p, Fsstate *fss)
@ -78,25 +94,13 @@ p9skinit(Proto *p, Fsstate *fss)
fss = fss; fss = fss;
fss->phasename = phasenames; fss->phasename = phasenames;
fss->maxphase = Maxphase; fss->maxphase = Maxphase;
if(p == &p9sk1) fss->proto = p;
s->vers = 1;
else if(p == &p9sk2)
s->vers = 2;
else
abort();
if(iscli){ if(iscli){
switch(s->vers){
case 1:
fss->phase = CHaveChal; fss->phase = CHaveChal;
genrandom((uchar*)s->cchal, CHALLEN); genrandom((uchar*)s->cchal, CHALLEN);
break;
case 2:
fss->phase = CNeedTreq;
break;
}
}else{ }else{
s->tr.type = AuthTreq; s->tr.type = AuthTreq;
attr = setattr(_copyattr(fss->attr), "proto=p9sk1"); attr = setattr(_copyattr(fss->attr), "proto=%q", p->name);
mkkeyinfo(&ki, fss, attr); mkkeyinfo(&ki, fss, attr);
ki.user = nil; ki.user = nil;
ret = findkey(&k, &ki, "user? dom?"); ret = findkey(&k, &ki, "user? dom?");
@ -108,16 +112,9 @@ p9skinit(Proto *p, Fsstate *fss)
safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid)); safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid));
safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom)); safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom));
s->key = k; s->key = k;
memmove(&s->k, k->priv, sizeof(Authkey));
genrandom((uchar*)s->tr.chal, sizeof s->tr.chal); genrandom((uchar*)s->tr.chal, sizeof s->tr.chal);
switch(s->vers){
case 1:
fss->phase = SNeedChal; fss->phase = SNeedChal;
break;
case 2:
fss->phase = SHaveTreq;
memmove(s->cchal, s->tr.chal, CHALLEN);
break;
}
} }
s->tbuflen = 0; s->tbuflen = 0;
s->secret = nil; s->secret = nil;
@ -125,6 +122,39 @@ p9skinit(Proto *p, Fsstate *fss)
return RpcOk; return RpcOk;
} }
static int
establish(Fsstate *fss)
{
AuthInfo *ai;
State *s;
s = fss->ps;
ai = &fss->ai;
ai->cuid = s->t.cuid;
ai->suid = s->t.suid;
if(fss->proto == &dp9ik){
static char info[] = "Plan 9 session secret";
ai->nsecret = 256;
ai->secret = emalloc(ai->nsecret);
hkdf_x( s->rand, 2*NONCELEN,
(uchar*)info, sizeof(info)-1,
s->t.key, NONCELEN,
ai->secret, ai->nsecret,
hmac_sha2_256, SHA2_256dlen);
} else {
ai->nsecret = 8;
ai->secret = emalloc(ai->nsecret);
des56to64((uchar*)s->t.key, ai->secret);
}
s->secret = ai->secret;
fss->haveai = 1;
fss->phase = Established;
return RpcOk;
}
static int static int
p9skread(Fsstate *fss, void *a, uint *n) p9skread(Fsstate *fss, void *a, uint *n)
{ {
@ -142,13 +172,37 @@ p9skread(Fsstate *fss, void *a, uint *n)
return toosmall(fss, m); return toosmall(fss, m);
*n = m; *n = m;
memmove(a, s->cchal, m); memmove(a, s->cchal, m);
if(fss->proto == &dp9ik)
fss->phase = CNeedPAKreq;
else
fss->phase = CNeedTreq; fss->phase = CNeedTreq;
return RpcOk; return RpcOk;
case SHavePAKreq:
m = TICKREQLEN + PAKYLEN;
if(*n < m)
return toosmall(fss, m);
s->tr.type = AuthPAK;
*n = convTR2M(&s->tr, a, *n);
authpak_new(&s->p, &s->k, (uchar*)a + *n, 1);
*n += PAKYLEN;
fss->phase = SNeedPAKy;
return RpcOk;
case CHavePAKy:
m = PAKYLEN;
if(*n < m)
return toosmall(fss, m);
*n = m;
memmove(a, s->y, m);
fss->phase = CHaveTicket;
return RpcOk;
case SHaveTreq: case SHaveTreq:
m = TICKREQLEN; m = TICKREQLEN;
if(*n < m) if(*n < m)
return toosmall(fss, m); return toosmall(fss, m);
s->tr.type = AuthTreq;
*n = convTR2M(&s->tr, a, *n); *n = convTR2M(&s->tr, a, *n);
fss->phase = SNeedTicket; fss->phase = SNeedTicket;
return RpcOk; return RpcOk;
@ -168,15 +222,7 @@ p9skread(Fsstate *fss, void *a, uint *n)
return toosmall(fss, m); return toosmall(fss, m);
*n = m; *n = m;
memmove(a, s->tbuf, m); memmove(a, s->tbuf, m);
fss->ai.cuid = s->t.cuid; return establish(fss);
fss->ai.suid = s->t.suid;
s->secret = emalloc(8);
des56to64((uchar*)s->t.key, s->secret);
fss->ai.secret = s->secret;
fss->ai.nsecret = 8;
fss->haveai = 1;
fss->phase = Established;
return RpcOk;
} }
} }
@ -184,12 +230,12 @@ static int
p9skwrite(Fsstate *fss, void *a, uint n) p9skwrite(Fsstate *fss, void *a, uint n)
{ {
int m, ret, sret; int m, ret, sret;
char tbuf[2*TICKETLEN], *user; char tbuf[2*PAKYLEN+2*MAXTICKETLEN], *user;
Attr *attr; Attr *attr;
Authenticator auth;
State *s; State *s;
Key *srvkey; Key *srvkey;
Keyinfo ki; Keyinfo ki;
Authenticator auth;
s = fss->ps; s = fss->ps;
switch(fss->phase){ switch(fss->phase){
@ -201,24 +247,32 @@ p9skwrite(Fsstate *fss, void *a, uint n)
if(n < m) if(n < m)
return toosmall(fss, m); return toosmall(fss, m);
memmove(s->cchal, a, m); memmove(s->cchal, a, m);
if(fss->proto == &dp9ik)
fss->phase = SHavePAKreq;
else
fss->phase = SHaveTreq; fss->phase = SHaveTreq;
return RpcOk; return RpcOk;
case CNeedPAKreq:
m = TICKREQLEN+PAKYLEN;
if(n < m)
return toosmall(fss, m);
case CNeedTreq: case CNeedTreq:
m = convM2TR(a, n, &s->tr); m = TICKREQLEN;
if(m <= 0) if(n < m)
return toosmall(fss, -m); return toosmall(fss, m);
/* remember server's chal */ m = convM2TR(a, n, &s->tr);
if(s->vers == 2) if(m <= 0 || s->tr.type != (fss->phase==CNeedPAKreq ? AuthPAK : AuthTreq))
memmove(s->cchal, s->tr.chal, CHALLEN); return failure(fss, Easproto);
if(s->key != nil) if(s->key != nil)
closekey(s->key); closekey(s->key);
attr = _delattr(_delattr(_copyattr(fss->attr), "role"), "user"); attr = _delattr(_delattr(_copyattr(fss->attr), "role"), "user");
attr = setattr(attr, "proto=p9sk1"); attr = setattr(attr, "proto=%q", fss->proto->name);
user = _strfindattr(fss->attr, "user"); user = _strfindattr(fss->attr, "user");
/* /*
* If our client is the user who started factotum (client==owner), then * If our client is the user who started factotum (client==owner), then
* he can use whatever keys we have to speak as whoever he pleases. * he can use whatever keys we have to speak as whoever he pleases.
@ -241,7 +295,7 @@ p9skwrite(Fsstate *fss, void *a, uint n)
attr = setattr(attr, "user=%q", user); attr = setattr(attr, "user=%q", user);
mkkeyinfo(&ki, fss, attr); mkkeyinfo(&ki, fss, attr);
ret = findkey(&s->key, &ki, ret = findkey(&s->key, &ki,
"role=client dom=%q %s", s->tr.authdom, p9sk1.keyprompt); "role=client dom=%q %s", s->tr.authdom, fss->proto->keyprompt);
if(ret == RpcOk) if(ret == RpcOk)
closekey(srvkey); closekey(srvkey);
else if(sret == RpcOk){ else if(sret == RpcOk){
@ -256,27 +310,32 @@ p9skwrite(Fsstate *fss, void *a, uint n)
} }
/* fill in the rest of the request */ /* fill in the rest of the request */
s->tr.type = AuthTreq;
safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid); safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid);
if(s->speakfor) if(s->speakfor)
safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid); safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid);
else else
safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid); safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
/* get tickets, from auth server or invent if we can */ /* get tickets from authserver or invent if we can */
ret = gettickets(s, &s->tr, tbuf, sizeof(tbuf)); if(fss->phase == CNeedPAKreq)
if(ret < 0){ ret = gettickets(s, &s->tr, (uchar*)a + m, tbuf, sizeof(tbuf));
else
ret = gettickets(s, &s->tr, nil, tbuf, sizeof(tbuf));
if(ret <= 0){
_freeattr(attr); _freeattr(attr);
return failure(fss, nil); return failure(fss, nil);
} }
m = convM2T(tbuf, ret, &s->t, &s->k);
m = convM2T(tbuf, ret, &s->t, (Authkey*)s->key->priv); if(m <= 0 || (fss->proto == &dp9ik && s->t.form == 0)){
_freeattr(attr);
return failure(fss, Easproto);
}
if(s->t.num != AuthTc){ if(s->t.num != AuthTc){
if(s->key->successes == 0 && !s->speakfor) if(s->key->successes == 0 && !s->speakfor)
disablekey(s->key); disablekey(s->key);
if(askforkeys && !s->speakfor){ if(askforkeys && !s->speakfor){
snprint(fss->keyinfo, sizeof fss->keyinfo, snprint(fss->keyinfo, sizeof fss->keyinfo,
"%A %s", attr, p9sk1.keyprompt); "%A %s", attr, fss->proto->keyprompt);
_freeattr(attr); _freeattr(attr);
return RpcNeedkey; return RpcNeedkey;
}else{ }else{
@ -288,32 +347,44 @@ p9skwrite(Fsstate *fss, void *a, uint n)
_freeattr(attr); _freeattr(attr);
ret -= m; ret -= m;
memmove(s->tbuf, tbuf+m, ret); memmove(s->tbuf, tbuf+m, ret);
genrandom(s->rand, NONCELEN);
auth.num = AuthAc; auth.num = AuthAc;
memmove(auth.chal, s->tr.chal, CHALLEN); memmove(auth.chal, s->tr.chal, CHALLEN);
auth.id = 0; memmove(auth.rand, s->rand, NONCELEN);
ret += convA2M(&auth, s->tbuf+ret, sizeof(s->tbuf)-ret, &s->t); ret += convA2M(&auth, s->tbuf+ret, sizeof(s->tbuf)-ret, &s->t);
s->tbuflen = ret; s->tbuflen = ret;
if(fss->phase == CNeedPAKreq)
fss->phase = CHavePAKy;
else
fss->phase = CHaveTicket; fss->phase = CHaveTicket;
return RpcOk; return RpcOk;
case SNeedPAKy:
m = PAKYLEN;
if(n < m)
return toosmall(fss, m);
if(authpak_finish(&s->p, &s->k, (uchar*)a))
return failure(fss, Easproto);
fss->phase = SNeedTicket;
return RpcOk;
case SNeedTicket: case SNeedTicket:
m = convM2T(a, n, &s->t, (Authkey*)s->key->priv); m = convM2T(a, n, &s->t, &s->k);
if(m <= 0) if(m <= 0 || convM2A((char*)a+m, n-m, &auth, &s->t) <= 0)
return toosmall(fss, -m); return toosmall(fss, MAXTICKETLEN + MAXAUTHENTLEN);
if(fss->proto == &dp9ik && s->t.form == 0)
return failure(fss, Easproto);
if(s->t.num != AuthTs if(s->t.num != AuthTs
|| memcmp(s->t.chal, s->tr.chal, CHALLEN) != 0) || tsmemcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
return failure(fss, Easproto); return failure(fss, Easproto);
ret = convM2A((char*)a+m, n-m, &auth, &s->t);
if(ret <= 0)
return toosmall(fss, -ret + m);
if(auth.num != AuthAc if(auth.num != AuthAc
|| memcmp(auth.chal, s->tr.chal, CHALLEN) != 0 || tsmemcmp(auth.chal, s->tr.chal, CHALLEN) != 0)
|| auth.id != 0)
return failure(fss, Easproto); return failure(fss, Easproto);
memmove(s->rand, auth.rand, NONCELEN);
genrandom(s->rand + NONCELEN, NONCELEN);
auth.num = AuthAs; auth.num = AuthAs;
memmove(auth.chal, s->cchal, CHALLEN); memmove(auth.chal, s->cchal, CHALLEN);
auth.id = 0; memmove(auth.rand, s->rand + NONCELEN, NONCELEN);
s->tbuflen = convA2M(&auth, s->tbuf, sizeof(s->tbuf), &s->t); s->tbuflen = convA2M(&auth, s->tbuf, sizeof(s->tbuf), &s->t);
fss->phase = SHaveAuth; fss->phase = SHaveAuth;
return RpcOk; return RpcOk;
@ -323,18 +394,10 @@ p9skwrite(Fsstate *fss, void *a, uint n)
if(m <= 0) if(m <= 0)
return toosmall(fss, -m); return toosmall(fss, -m);
if(auth.num != AuthAs if(auth.num != AuthAs
|| memcmp(auth.chal, s->cchal, CHALLEN) != 0 || tsmemcmp(auth.chal, s->cchal, CHALLEN) != 0)
|| auth.id != 0)
return failure(fss, Easproto); return failure(fss, Easproto);
fss->ai.cuid = s->t.cuid; memmove(s->rand+NONCELEN, auth.rand, NONCELEN);
fss->ai.suid = s->t.suid; return establish(fss);
s->secret = emalloc(8);
des56to64((uchar*)s->t.key, s->secret);
fss->ai.secret = s->secret;
fss->ai.nsecret = 8;
fss->haveai = 1;
fss->phase = Established;
return RpcOk;
} }
} }
@ -352,6 +415,7 @@ p9skclose(Fsstate *fss)
closekey(s->key); closekey(s->key);
s->key = nil; s->key = nil;
} }
memset(s, 0, sizeof(State));
free(s); free(s);
} }
@ -386,15 +450,28 @@ static int
p9skaddkey(Key *k, int before) p9skaddkey(Key *k, int before)
{ {
Authkey *akey; Authkey *akey;
char *s; char *s, *u;
u = _strfindattr(k->attr, "user");
if(u == nil){
werrstr("no user attribute");
return -1;
}
akey = emalloc(sizeof(Authkey)); akey = emalloc(sizeof(Authkey));
if(s = _strfindattr(k->privattr, "!hex")){ if(s = _strfindattr(k->privattr, "!hex")){
if(k->proto == &dp9ik){
if(hexparse(s, akey->aes, AESKEYLEN) < 0){
free(akey);
werrstr("malformed key data");
return -1;
}
} else {
if(hexparse(s, (uchar*)akey->des, DESKEYLEN) < 0){ if(hexparse(s, (uchar*)akey->des, DESKEYLEN) < 0){
free(akey); free(akey);
werrstr("malformed key data"); werrstr("malformed key data");
return -1; return -1;
} }
}
}else if(s = _strfindattr(k->privattr, "!password")){ }else if(s = _strfindattr(k->privattr, "!password")){
passtokey(akey, s); passtokey(akey, s);
}else{ }else{
@ -402,6 +479,10 @@ p9skaddkey(Key *k, int before)
free(akey); free(akey);
return -1; return -1;
} }
if(k->proto == &dp9ik)
authpak_hash(akey, u);
else
memset(akey->aes, 0, AESKEYLEN); /* don't attempt AuthPAK for p9sk1 key */
k->priv = akey; k->priv = akey;
return replacekey(k, before); return replacekey(k, before);
} }
@ -409,31 +490,12 @@ p9skaddkey(Key *k, int before)
static void static void
p9skclosekey(Key *k) p9skclosekey(Key *k)
{ {
memset(k->priv, 0, sizeof(Authkey));
free(k->priv); free(k->priv);
} }
static int static int
getastickets(State *s, Ticketreq *tr, char *tbuf, int tbuflen) mkservertickets(State *s, uchar *y, char *tbuf, int tbuflen)
{
int asfd, rv;
char *dom;
if((dom = _strfindattr(s->key->attr, "dom")) == nil){
werrstr("auth key has no domain");
return -1;
}
asfd = _authdial(nil, dom);
if(asfd < 0)
return -1;
alarm(30*1000);
rv = _asgetticket(asfd, tr, tbuf, tbuflen);
alarm(0);
close(asfd);
return rv;
}
static int
mkserverticket(State *s, char *tbuf, int tbuflen)
{ {
Ticketreq *tr = &s->tr; Ticketreq *tr = &s->tr;
Ticket t; Ticket t;
@ -446,26 +508,81 @@ mkserverticket(State *s, char *tbuf, int tbuflen)
return -1; return -1;
*/ */
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
ret = 0;
if(y != nil){
t.form = 1;
authpak_new(&s->p, &s->k, s->y, 0);
authpak_finish(&s->p, &s->k, y);
}
memmove(t.chal, tr->chal, CHALLEN); memmove(t.chal, tr->chal, CHALLEN);
strcpy(t.cuid, tr->uid); strcpy(t.cuid, tr->uid);
strcpy(t.suid, tr->uid); strcpy(t.suid, tr->uid);
genrandom((uchar*)t.key, DESKEYLEN); genrandom((uchar*)t.key, sizeof(t.key));
t.num = AuthTc; t.num = AuthTc;
ret = convT2M(&t, tbuf, tbuflen, (Authkey*)s->key->priv); ret += convT2M(&t, tbuf+ret, tbuflen-ret, &s->k);
t.num = AuthTs; t.num = AuthTs;
ret += convT2M(&t, tbuf+ret, tbuflen-ret, (Authkey*)s->key->priv); ret += convT2M(&t, tbuf+ret, tbuflen-ret, &s->k);
memset(&t, 0, sizeof(t));
return ret; return ret;
} }
static int static int
gettickets(State *s, Ticketreq *tr, char *tbuf, int tbuflen) getastickets(State *s, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
{
int asfd, rv;
char *dom;
if((dom = _strfindattr(s->key->attr, "dom")) == nil){
werrstr("auth key has no domain");
return -1;
}
asfd = _authdial(dom);
if(asfd < 0)
return -1;
alarm(30*1000);
if(y != nil){
rv = -1;
s->tr.type = AuthPAK;
if(_asrequest(asfd, tr) != 0 || write(asfd, y, PAKYLEN) != PAKYLEN)
goto Out;
authpak_new(&s->p, &s->k, (uchar*)tbuf, 1);
if(write(asfd, tbuf, PAKYLEN) != PAKYLEN)
goto Out;
if(_asrdresp(asfd, tbuf, 2*PAKYLEN) != 2*PAKYLEN)
goto Out;
memmove(s->y, tbuf, PAKYLEN);
if(authpak_finish(&s->p, &s->k, (uchar*)tbuf+PAKYLEN))
goto Out;
}
s->tr.type = AuthTreq;
rv = _asgetticket(asfd, tr, tbuf, tbuflen);
Out:
alarm(0);
close(asfd);
return rv;
}
static int
gettickets(State *s, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
{ {
int ret; int ret;
ret = getastickets(s, tr, tbuf, tbuflen); if(tr->authdom[0] == 0
if(ret >= 0) || tr->authid[0] == 0
|| tr->hostid[0] == 0
|| tr->uid[0] == 0){
werrstr("bad ticket request");
return -1;
}
memmove(&s->k, s->key->priv, sizeof(Authkey));
ret = getastickets(s, tr, y, tbuf, tbuflen);
if(ret > 0)
return ret; return ret;
return mkserverticket(s, tbuf, tbuflen); return mkservertickets(s, y, tbuf, tbuflen);
} }
Proto p9sk1 = { Proto p9sk1 = {
@ -479,11 +596,13 @@ Proto p9sk1 = {
.keyprompt= "user? !password?" .keyprompt= "user? !password?"
}; };
Proto p9sk2 = { Proto dp9ik = {
.name= "p9sk2", .name= "dp9ik",
.init= p9skinit, .init= p9skinit,
.write= p9skwrite, .write= p9skwrite,
.read= p9skread, .read= p9skread,
.close= p9skclose, .close= p9skclose,
.addkey= p9skaddkey,
.closekey= p9skclosekey,
.keyprompt= "user? !password?"
}; };

View file

@ -429,15 +429,20 @@ ctlwrite(char *a, int atzero)
return -1; return -1;
} }
} }
for(i=0; i<ring->nkey; ){ Again:
if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){ qlock(ring);
for(i=0; i<ring->nkey; i++){
k = ring->key[i];
if(matchattr(attr, k->attr, k->privattr)){
nmatch++; nmatch++;
closekey(ring->key[i]);
ring->nkey--; ring->nkey--;
memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0])); memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0]));
}else qunlock(ring);
i++; closekey(k);
goto Again;
} }
}
qunlock(ring);
_freeattr(attr); _freeattr(attr);
if(nmatch == 0){ if(nmatch == 0){
werrstr("found no keys to delete"); werrstr("found no keys to delete");

View file

@ -1,6 +1,7 @@
#include "dat.h" #include "dat.h"
static char secstore[100]; /* server name */ static char secstore[100]; /* server name */
static uchar zeros[16];
/* bind in the default network and cs */ /* bind in the default network and cs */
static int static int
@ -72,14 +73,13 @@ netndbauthaddr(void)
} }
int int
_authdial(char *net, char *authdom) _authdial(char *authdom)
{ {
int i, fd, vanilla; int i, fd;
alarm(30*1000); alarm(30*1000);
vanilla = net==nil || strcmp(net, "/net")==0; if(bindnetcs()>=0)
if(!vanilla || bindnetcs()>=0) fd = authdial(nil, authdom);
fd = authdial(net, authdom);
else { else {
/* /*
* If we failed to mount /srv/cs, assume that * If we failed to mount /srv/cs, assume that
@ -106,6 +106,31 @@ _authdial(char *net, char *authdom)
return fd; return fd;
} }
int
_authreq(Ticketreq *tr, Authkey *k)
{
int fd;
fd = _authdial(tr->authdom);
if(fd < 0)
return -1;
alarm(30*1000);
if(tsmemcmp(k->aes, zeros, AESKEYLEN) != 0){
if(_asgetpakkey(fd, tr, k) < 0){
alarm(0);
close(fd);
return -1;
}
}
if(_asrequest(fd, tr) < 0){
alarm(0);
close(fd);
return -1;
}
alarm(0);
return fd;
}
/* /*
* prompt user for a key. don't care about memory leaks, runs standalone * prompt user for a key. don't care about memory leaks, runs standalone
*/ */
@ -200,8 +225,8 @@ canusekey(Fsstate *fss, Key *k)
return fss->conf[i].canuse; return fss->conf[i].canuse;
if(fss->nconf%16 == 0) if(fss->nconf%16 == 0)
fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0]))); fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
incref(k);
fss->conf[fss->nconf].key = k; fss->conf[fss->nconf].key = k;
k->ref++;
fss->conf[fss->nconf].canuse = -1; fss->conf[fss->nconf].canuse = -1;
fss->conf[fss->nconf].tag = conftaggen++; fss->conf[fss->nconf].tag = conftaggen++;
fss->nconf++; fss->nconf++;
@ -216,7 +241,7 @@ closekey(Key *k)
{ {
if(k == nil) if(k == nil)
return; return;
if(--k->ref != 0) if(decref(k))
return; return;
if(k->proto && k->proto->closekey) if(k->proto && k->proto->closekey)
(*k->proto->closekey)(k); (*k->proto->closekey)(k);
@ -377,6 +402,7 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
return failure(ki->fss, nil); return failure(ki->fss, nil);
} }
qlock(ring);
nmatch = 0; nmatch = 0;
for(i=0; i<ring->nkey; i++){ for(i=0; i<ring->nkey; i++){
k = ring->key[i]; k = ring->key[i];
@ -391,6 +417,7 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
if(!ki->noconf){ if(!ki->noconf){
switch(canusekey(ki->fss, k)){ switch(canusekey(ki->fss, k)){
case -1: case -1:
qunlock(ring);
_freeattr(attr1); _freeattr(attr1);
return RpcConfirm; return RpcConfirm;
case 0: case 0:
@ -402,11 +429,13 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
_freeattr(attr1); _freeattr(attr1);
_freeattr(attr2); _freeattr(attr2);
_freeattr(attr3); _freeattr(attr3);
k->ref++; incref(k);
*ret = k; *ret = k;
qunlock(ring);
return RpcOk; return RpcOk;
} }
} }
qunlock(ring);
flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3); flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
werrstr("no key matches %A %A", attr0, attr1); werrstr("no key matches %A %A", attr0, attr1);
_freeattr(attr2); _freeattr(attr2);
@ -446,6 +475,7 @@ findp9authkey(Key **k, Fsstate *fss)
{ {
char *dom; char *dom;
Keyinfo ki; Keyinfo ki;
int rv;
/* /*
* We don't use fss->attr here because we don't * We don't use fss->attr here because we don't
@ -454,10 +484,18 @@ findp9authkey(Key **k, Fsstate *fss)
mkkeyinfo(&ki, fss, nil); mkkeyinfo(&ki, fss, nil);
ki.attr = nil; ki.attr = nil;
ki.user = nil; ki.user = nil;
if(dom = _strfindattr(fss->attr, "dom")) dom = _strfindattr(fss->attr, "dom");
return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom); if(dom != nil)
rv = findkey(k, &ki, "proto=dp9ik dom=%q role=server user?", dom);
else else
return findkey(k, &ki, "proto=p9sk1 role=server dom? user?"); rv = findkey(k, &ki, "proto=dp9ik role=server dom? user?");
if(rv != RpcOk){
if(dom != nil)
rv = findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
else
rv = findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
}
return rv;
} }
Proto* Proto*
@ -471,12 +509,11 @@ findproto(char *name)
return nil; return nil;
} }
char* int
getnvramkey(int flag) getnvramkey(int flag)
{ {
Nvrsafe safe; Nvrsafe safe;
char *s; char *s;
int i;
memset(&safe, 0, sizeof safe); memset(&safe, 0, sizeof safe);
/* /*
@ -484,24 +521,30 @@ getnvramkey(int flag)
* but safe still holds good data. * but safe still holds good data.
*/ */
if(readnvram(&safe, flag)<0 && safe.authid[0]==0) if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
return nil; return -1;
/* if(tsmemcmp(safe.machkey, zeros, DESKEYLEN) != 0){
* only use nvram key if it is non-zero
*/
for(i = 0; i < DESKEYLEN; i++)
if(safe.machkey[i] != 0)
break;
if(i == DESKEYLEN)
return nil;
fmtinstall('H', encodefmt);
s = smprint("key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______", s = smprint("key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
safe.authid, safe.authdom, DESKEYLEN, safe.machkey); safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
if(s != nil){
ctlwrite(s, 0);
memset(s, 0, strlen(s));
free(s);
}
}
if(tsmemcmp(safe.aesmachkey, zeros, AESKEYLEN) != 0){
s = smprint("key proto=dp9ik user=%q dom=%q !hex=%.*H !password=______",
safe.authid, safe.authdom, AESKEYLEN, safe.aesmachkey);
if(s != nil){
ctlwrite(s, 0);
memset(s, 0, strlen(s));
free(s);
}
}
writehostowner(safe.authid); writehostowner(safe.authid);
memset(&safe, 0, sizeof safe); memset(&safe, 0, sizeof safe);
return s; return 0;
} }
int int
@ -781,24 +824,26 @@ replacekey(Key *kn, int before)
int i; int i;
Key *k; Key *k;
qlock(ring);
incref(kn);
for(i=0; i<ring->nkey; i++){ for(i=0; i<ring->nkey; i++){
k = ring->key[i]; k = ring->key[i];
if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){ if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
closekey(k);
kn->ref++;
ring->key[i] = kn; ring->key[i] = kn;
qunlock(ring);
closekey(k);
return 0; return 0;
} }
} }
if(ring->nkey%16 == 0) if(ring->nkey%16 == 0)
ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0])); ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
kn->ref++;
if(before){ if(before){
memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]); memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
ring->key[0] = kn; ring->key[0] = kn;
ring->nkey++; ring->nkey++;
}else }else
ring->key[ring->nkey++] = kn; ring->key[ring->nkey++] = kn;
qunlock(ring);
return 0; return 0;
} }

View file

@ -25,6 +25,7 @@ enum {
Quser, Quser,
Qkey, Qkey,
Qaeskey, Qaeskey,
Qpakhash,
Qsecret, Qsecret,
Qlog, Qlog,
Qstatus, Qstatus,
@ -54,8 +55,7 @@ struct Fid {
struct User { struct User {
char *name; char *name;
char key[DESKEYLEN]; Authkey key;
uchar aeskey[AESKEYLEN];
char secret[SECRETLEN]; char secret[SECRETLEN];
ulong expire; /* 0 == never */ ulong expire; /* 0 == never */
uchar status; uchar status;
@ -73,6 +73,7 @@ char *qinfo[Qmax] = {
[Quser] ".", [Quser] ".",
[Qkey] "key", [Qkey] "key",
[Qaeskey] "aeskey", [Qaeskey] "aeskey",
[Qpakhash] "pakhash",
[Qsecret] "secret", [Qsecret] "secret",
[Qlog] "log", [Qlog] "log",
[Qexpire] "expire", [Qexpire] "expire",
@ -180,6 +181,7 @@ main(int argc, char *argv[])
if(pipe(p) < 0) if(pipe(p) < 0)
error("can't make pipe: %r"); error("can't make pipe: %r");
private();
if(usepass) if(usepass)
getpass(&authkey, nil, 0, 0); getpass(&authkey, nil, 0, 0);
else { else {
@ -374,7 +376,7 @@ Open(Fid *f)
mode = rhdr.mode; mode = rhdr.mode;
if(f->qtype == Quser && (mode & (OWRITE|OTRUNC))) if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
return "user already exists"; return "user already exists";
if(f->qtype == Qaeskey && !keydbaes) if((f->qtype == Qaeskey || f->qtype == Qpakhash) && !keydbaes)
return "keyfile not in aes format"; return "keyfile not in aes format";
thdr.qid = mkqid(f->user, f->qtype); thdr.qid = mkqid(f->user, f->qtype);
thdr.iounit = messagesize - IOHDRSZ; thdr.iounit = messagesize - IOHDRSZ;
@ -458,6 +460,7 @@ Read(Fid *f)
return 0; return 0;
case Qkey: case Qkey:
case Qaeskey: case Qaeskey:
case Qpakhash:
case Qsecret: case Qsecret:
if(f->user->status != Sok) if(f->user->status != Sok)
return "user disabled"; return "user disabled";
@ -468,13 +471,17 @@ Read(Fid *f)
m = 0; m = 0;
switch(f->qtype){ switch(f->qtype){
case Qkey: case Qkey:
data = f->user->key; data = (char*)f->user->key.des;
m = DESKEYLEN; m = DESKEYLEN;
break; break;
case Qaeskey: case Qaeskey:
data = (char*)f->user->aeskey; data = (char*)f->user->key.aes;
m = AESKEYLEN; m = AESKEYLEN;
break; break;
case Qpakhash:
data = (char*)f->user->key.pakhash;
m = PAKHASHLEN;
break;
case Qsecret: case Qsecret:
data = f->user->secret; data = f->user->secret;
Readstr: Readstr:
@ -531,14 +538,15 @@ Write(Fid *f)
case Qkey: case Qkey:
if(n != DESKEYLEN) if(n != DESKEYLEN)
return "garbled write data"; return "garbled write data";
memmove(f->user->key, data, DESKEYLEN); memmove(f->user->key.des, data, n);
thdr.count = DESKEYLEN; thdr.count = n;
break; break;
case Qaeskey: case Qaeskey:
if(n != AESKEYLEN) if(n != AESKEYLEN)
return "garbled write data"; return "garbled write data";
memmove(f->user->aeskey, data, AESKEYLEN); memmove(f->user->key.aes, data, n);
thdr.count = AESKEYLEN; authpak_hash(&f->user->key, f->user->name);
thdr.count = n;
break; break;
case Qsecret: case Qsecret:
if(n >= SECRETLEN) if(n >= SECRETLEN)
@ -728,7 +736,7 @@ writeusers(void)
for(u = users[i]; u != nil; u = u->link){ for(u = users[i]; u != nil; u = u->link){
strncpy((char*)p, u->name, Namelen); strncpy((char*)p, u->name, Namelen);
p += Namelen; p += Namelen;
memmove(p, u->key, DESKEYLEN); memmove(p, u->key.des, DESKEYLEN);
p += DESKEYLEN; p += DESKEYLEN;
*p++ = u->status; *p++ = u->status;
*p++ = u->warnings; *p++ = u->warnings;
@ -740,7 +748,7 @@ writeusers(void)
memmove(p, u->secret, SECRETLEN); memmove(p, u->secret, SECRETLEN);
p += SECRETLEN; p += SECRETLEN;
if(keydbaes){ if(keydbaes){
memmove(p, u->aeskey, AESKEYLEN); memmove(p, u->key.aes, AESKEYLEN);
p += AESKEYLEN; p += AESKEYLEN;
} }
} }
@ -773,6 +781,8 @@ writeusers(void)
free(buf); free(buf);
close(fd); close(fd);
newkeys();
} }
int int
@ -897,7 +907,7 @@ readusers(void)
u = finduser((char*)ep); u = finduser((char*)ep);
if(u == nil) if(u == nil)
u = installuser((char*)ep); u = installuser((char*)ep);
memmove(u->key, ep + Namelen, DESKEYLEN); memmove(u->key.des, ep + Namelen, DESKEYLEN);
p = ep + Namelen + DESKEYLEN; p = ep + Namelen + DESKEYLEN;
u->status = *p++; u->status = *p++;
u->warnings = *p++; u->warnings = *p++;
@ -908,8 +918,10 @@ readusers(void)
memmove(u->secret, p, SECRETLEN); memmove(u->secret, p, SECRETLEN);
u->secret[SECRETLEN-1] = 0; u->secret[SECRETLEN-1] = 0;
p += SECRETLEN; p += SECRETLEN;
if(keydbaes) if(keydbaes){
memmove(u->aeskey, p, AESKEYLEN); memmove(u->key.aes, p, AESKEYLEN);
authpak_hash(&u->key, u->name);
}
nu++; nu++;
} }
free(buf); free(buf);

View file

@ -6,6 +6,7 @@ OFILES=\
keyfmt.$O\ keyfmt.$O\
netcheck.$O\ netcheck.$O\
okpasswd.$O\ okpasswd.$O\
private.$O\
readwrite.$O\ readwrite.$O\
readarg.$O\ readarg.$O\
readln.$O\ readln.$O\

View file

@ -66,8 +66,14 @@ findkey(char *db, char *user, Authkey *key)
int ret; int ret;
memset(key, 0, sizeof(Authkey)); memset(key, 0, sizeof(Authkey));
ret = finddeskey(db, user, key->des) != nil; ret = findaeskey(db, user, key->aes) != nil;
ret |= findaeskey(db, user, key->aes) != nil; if(ret){
char filename[Maxpath];
snprint(filename, sizeof filename, "%s/%s/pakhash", db, user);
if(readfile(filename, (char*)key->pakhash, PAKHASHLEN) != PAKHASHLEN)
authpak_hash(key, user);
}
ret |= finddeskey(db, user, key->des) != nil;
return ret; return ret;
} }

View file

@ -15,8 +15,7 @@ usage(void)
void void
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
Authkey key; char buf[32], pass[32], key[DESKEYLEN];
char buf[32], pass[32];
char *s; char *s;
int n; int n;
@ -34,7 +33,7 @@ main(int argc, char *argv[])
} }
readln("Password: ", pass, sizeof pass, 1); readln("Password: ", pass, sizeof pass, 1);
passtokey(&key, pass); passtodeskey(key, pass);
for(;;){ for(;;){
print("challenge: "); print("challenge: ");
@ -44,7 +43,7 @@ main(int argc, char *argv[])
buf[n] = '\0'; buf[n] = '\0';
n = strtol(buf, 0, 10); n = strtol(buf, 0, 10);
sprint(buf, "%d", n); sprint(buf, "%d", n);
netcrypt(key.des, buf); netcrypt(key, buf);
print("response: %s\n", buf); print("response: %s\n", buf);
} }
} }

View file

@ -7,7 +7,7 @@
void void
main(int argc, char **argv) main(int argc, char **argv)
{ {
int fd, n; int fd, n, try;
Ticketreq tr; Ticketreq tr;
Ticket t; Ticket t;
Passwordreq pr; Passwordreq pr;
@ -20,6 +20,8 @@ main(int argc, char **argv)
ARGBEGIN{ ARGBEGIN{
}ARGEND }ARGEND
private();
s = nil; s = nil;
if(argc > 0){ if(argc > 0){
user = argv[0]; user = argv[0];
@ -34,6 +36,10 @@ main(int argc, char **argv)
if(fd < 0) if(fd < 0)
error("authdial: %r"); error("authdial: %r");
memset(&tr, 0, sizeof(tr));
strncpy(tr.uid, user, sizeof(tr.uid)-1);
tr.type = AuthPass;
/* /*
* get a password from the user and try to decrypt the * get a password from the user and try to decrypt the
* ticket. If it doesn't work we've got a bad password, * ticket. If it doesn't work we've got a bad password,
@ -43,18 +49,31 @@ main(int argc, char **argv)
readln("Plan 9 Password: ", pr.old, sizeof pr.old, 1); readln("Plan 9 Password: ", pr.old, sizeof pr.old, 1);
passtokey(&key, pr.old); passtokey(&key, pr.old);
memset(&tr, 0, sizeof(tr)); /*
strcpy(tr.uid, user); * negotiate PAK key. we need to retry in case the AS does
tr.type = AuthPass; * not support the AuthPAK request or when the user has
* not yet setup a new key and the AS made one up.
*/
try = 0;
authpak_hash(&key, tr.uid);
if(_asgetpakkey(fd, &tr, &key) < 0){
Retry:
try++;
close(fd);
fd = authdial(nil, s);
if(fd < 0)
error("authdial: %r");
}
/* send ticket request to AS */ /* send ticket request to AS */
if(_asrequest(fd, &tr) < 0) if(_asrequest(fd, &tr) < 0)
error("%r"); error("%r");
if(_asgetresp(fd, &t, nil, &key) < 0) if(_asgetresp(fd, &t, nil, &key) < 0)
error("%r"); error("%r");
if(t.num != AuthTp || strcmp(t.cuid, tr.uid) != 0){
if(t.num != AuthTp || strcmp(t.cuid, tr.uid) != 0) if(try == 0)
goto Retry;
error("bad password"); error("bad password");
}
/* loop trying new passwords */ /* loop trying new passwords */
for(;;){ for(;;){
@ -62,8 +81,7 @@ main(int argc, char **argv)
*pr.new = 0; *pr.new = 0;
readln("change Plan 9 Password? (y/n) ", buf, sizeof buf, 0); readln("change Plan 9 Password? (y/n) ", buf, sizeof buf, 0);
if(*buf == 'y' || *buf == 'Y'){ if(*buf == 'y' || *buf == 'Y'){
readln("Password(8 to 31 characters): ", pr.new, readln("Password: ", pr.new, sizeof pr.new, 1);
sizeof pr.new, 1);
readln("Confirm: ", buf, sizeof buf, 1); readln("Confirm: ", buf, sizeof buf, 1);
if(strcmp(pr.new, buf)){ if(strcmp(pr.new, buf)){
print("!mismatch\n"); print("!mismatch\n");
@ -81,8 +99,7 @@ main(int argc, char **argv)
else else
strcpy(pr.secret, pr.new); strcpy(pr.secret, pr.new);
} else { } else {
readln("Secret(0 to 256 characters): ", pr.secret, readln("Secret: ", pr.secret, sizeof pr.secret, 1);
sizeof pr.secret, 1);
readln("Confirm: ", buf, sizeof buf, 1); readln("Confirm: ", buf, sizeof buf, 1);
if(strcmp(pr.secret, buf)){ if(strcmp(pr.secret, buf)){
print("!mismatch\n"); print("!mismatch\n");

View file

@ -11,13 +11,13 @@
* this was copied from inet's guard. * this was copied from inet's guard.
*/ */
static void static void
netresp(Authkey *key, long chal, char *answer) netresp(char key[DESKEYLEN], long chal, char *answer)
{ {
uchar buf[8]; uchar buf[8];
memset(buf, 0, sizeof buf); memset(buf, 0, sizeof buf);
snprint((char *)buf, sizeof buf, "%lud", chal); snprint((char *)buf, sizeof buf, "%lud", chal);
if(encrypt(key->des, buf, 8) < 0) if(encrypt(key, buf, 8) < 0)
abort(); abort();
sprint(answer, "%.8ux", buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]); sprint(answer, "%.8ux", buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]);
} }
@ -25,8 +25,7 @@ netresp(Authkey *key, long chal, char *answer)
AuthInfo* AuthInfo*
auth_userpasswd(char *user, char *passwd) auth_userpasswd(char *user, char *passwd)
{ {
char resp[16]; char resp[16], key[DESKEYLEN];
Authkey key;
AuthInfo *ai; AuthInfo *ai;
Chalstate *ch; Chalstate *ch;
@ -38,9 +37,9 @@ auth_userpasswd(char *user, char *passwd)
if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil) if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil)
return nil; return nil;
passtokey(&key, passwd); passtodeskey(key, passwd);
netresp(&key, atol(ch->chal), resp); netresp(key, atol(ch->chal), resp);
memset(&key, 0, sizeof(Authkey)); memset(key, 0, sizeof(key));
ch->resp = resp; ch->resp = resp;
ch->nresp = strlen(resp); ch->nresp = strlen(resp);

View file

@ -0,0 +1,26 @@
#include <u.h>
#include <libc.h>
#include <authsrv.h>
int
_asgetpakkey(int fd, Ticketreq *tr, Authkey *a)
{
uchar y[PAKYLEN];
PAKpriv p;
int type;
type = tr->type;
tr->type = AuthPAK;
if(_asrequest(fd, tr) != 0){
tr->type = type;
return -1;
}
tr->type = type;
authpak_new(&p, a, y, 1);
if(write(fd, y, PAKYLEN) != PAKYLEN
|| _asrdresp(fd, (char*)y, PAKYLEN) != PAKYLEN){
memset(&p, 0, sizeof(p));
return -1;
}
return authpak_finish(&p, a, y);
}

View file

@ -5,28 +5,40 @@
int int
_asgetresp(int fd, Ticket *t, Authenticator *a, Authkey *k) _asgetresp(int fd, Ticket *t, Authenticator *a, Authkey *k)
{ {
char tbuf[TICKETLEN+AUTHENTLEN]; char buf[MAXTICKETLEN+MAXAUTHENTLEN], err[ERRMAX];
int n, m; int n, m;
m = TICKETLEN;
memset(t, 0, sizeof(Ticket)); memset(t, 0, sizeof(Ticket));
if(a != nil){ if(a != nil)
m += AUTHENTLEN;
memset(a, 0, sizeof(Authenticator)); memset(a, 0, sizeof(Authenticator));
strcpy(err, "AS protocol botch");
errstr(err, ERRMAX);
if(_asrdresp(fd, buf, 0) < 0)
return -1;
for(n = 0; (m = convM2T(buf, n, t, k)) <= 0; n += m){
m = -m;
if(m <= n || m > sizeof(buf))
return -1;
m -= n;
if(readn(fd, buf+n, m) != m)
return -1;
} }
n = _asrdresp(fd, tbuf, m);
if(n <= 0)
return -1;
m = convM2T(tbuf, n, t, k);
if(m <= 0)
return -1;
if(a != nil){ if(a != nil){
if(convM2A(tbuf+m, n-m, a, t) <= 0) for(n = 0; (m = convM2A(buf, n, a, t)) <= 0; n += m){
m = -m;
if(m <= n || m > sizeof(buf))
return -1;
m -= n;
if(readn(fd, buf+n, m) != m)
return -1; return -1;
} }
}
errstr(err, ERRMAX);
return 0; return 0;
} }

View file

@ -2,16 +2,36 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
static char *pbmsg = "AS protocol botch";
int int
_asgetticket(int fd, Ticketreq *tr, char *tbuf, int tbuflen) _asgetticket(int fd, Ticketreq *tr, char *tbuf, int tbuflen)
{ {
if(_asrequest(fd, tr) < 0){ char err[ERRMAX];
werrstr(pbmsg); int i, n, m, r;
strcpy(err, "AS protocol botch");
errstr(err, ERRMAX);
if(_asrequest(fd, tr) < 0)
return -1;
if(_asrdresp(fd, tbuf, 0) < 0)
return -1;
r = 0;
for(i = 0; i<2; i++){
for(n=0; (m = convM2T(tbuf, n, nil, nil)) <= 0; n += m){
m = -m;
if(m <= n || m > tbuflen)
return -1;
m -= n;
if(readn(fd, tbuf+n, m) != m)
return -1; return -1;
} }
if(tbuflen > 2*TICKETLEN) r += n;
tbuflen = 2*TICKETLEN; tbuf += n;
return _asrdresp(fd, tbuf, tbuflen); tbuflen -= n;
}
errstr(err, ERRMAX);
return r;
} }

View file

@ -0,0 +1,214 @@
#include <u.h>
#include <libc.h>
#include <mp.h>
#include <libsec.h>
#include <authsrv.h>
#include "msqrt.mpc"
#include "decaf.mpc"
#include "edwards.mpc"
#include "elligator2.mpc"
#include "spake2ee.mpc"
#include "ed448.mpc"
typedef struct PAKcurve PAKcurve;
struct PAKcurve
{
Lock;
mpint *P;
mpint *A;
mpint *D;
mpint *X;
mpint *Y;
};
static PAKcurve*
authpak_curve(void)
{
static PAKcurve a;
lock(&a);
if(a.P == nil){
a.P = mpnew(0);
a.A = mpnew(0);
a.D = mpnew(0);
a.X = mpnew(0);
a.Y = mpnew(0);
ed448_curve(a.P, a.A, a.D, a.X, a.Y);
a.P = mpfield(a.P);
}
unlock(&a);
return &a;
}
void
authpak_hash(Authkey *k, char *u)
{
static char info[] = "Plan 9 AuthPAK hash";
uchar *bp, salt[SHA2_256dlen], h[2*PAKSLEN];
mpint *H, *PX,*PY,*PZ,*PT;
PAKcurve *c;
H = mpnew(0);
PX = mpnew(0);
PY = mpnew(0);
PZ = mpnew(0);
PT = mpnew(0);
sha2_256((uchar*)u, strlen(u), salt, nil);
hkdf_x( salt, SHA2_256dlen,
(uchar*)info, sizeof(info)-1,
k->aes, AESKEYLEN,
h, sizeof(h),
hmac_sha2_256, SHA2_256dlen);
c = authpak_curve();
betomp(h + 0*PAKSLEN, PAKSLEN, H); /* HM */
spake2ee_h2P(c->P,c->A,c->D, H, PX,PY,PZ,PT); /* PM */
bp = k->pakhash;
mptober(PX, bp, PAKSLEN), bp += PAKSLEN;
mptober(PY, bp, PAKSLEN), bp += PAKSLEN;
mptober(PZ, bp, PAKSLEN), bp += PAKSLEN;
mptober(PT, bp, PAKSLEN), bp += PAKSLEN;
betomp(h + 1*PAKSLEN, PAKSLEN, H); /* HN */
spake2ee_h2P(c->P,c->A,c->D, H, PX,PY,PZ,PT); /* PN */
mptober(PX, bp, PAKSLEN), bp += PAKSLEN;
mptober(PY, bp, PAKSLEN), bp += PAKSLEN;
mptober(PZ, bp, PAKSLEN), bp += PAKSLEN;
mptober(PT, bp, PAKSLEN);
mpfree(PX);
mpfree(PY);
mpfree(PZ);
mpfree(PT);
mpfree(H);
}
void
authpak_new(PAKpriv *p, Authkey *k, uchar y[PAKYLEN], int isclient)
{
mpint *PX,*PY,*PZ,*PT, *X, *Y;
PAKcurve *c;
uchar *bp;
memset(p, 0, sizeof(PAKpriv));
p->isclient = isclient != 0;
X = mpnew(0);
Y = mpnew(0);
PX = mpnew(0);
PY = mpnew(0);
PZ = mpnew(0);
PT = mpnew(0);
PX->flags |= MPtimesafe;
PY->flags |= MPtimesafe;
PZ->flags |= MPtimesafe;
PT->flags |= MPtimesafe;
bp = k->pakhash + PAKPLEN*(p->isclient == 0);
betomp(bp, PAKSLEN, PX), bp += PAKSLEN;
betomp(bp, PAKSLEN, PY), bp += PAKSLEN;
betomp(bp, PAKSLEN, PZ), bp += PAKSLEN;
betomp(bp, PAKSLEN, PT);
c = authpak_curve();
X->flags |= MPtimesafe;
mpnrand(c->P, genrandom, X);
spake2ee_1(c->P,c->A,c->D, X, c->X,c->Y, PX,PY,PZ,PT, Y);
mptober(X, p->x, PAKXLEN);
mptober(Y, p->y, PAKYLEN);
memmove(y, p->y, PAKYLEN);
mpfree(PX);
mpfree(PY);
mpfree(PZ);
mpfree(PT);
mpfree(X);
mpfree(Y);
}
int
authpak_finish(PAKpriv *p, Authkey *k, uchar y[PAKYLEN])
{
static char info[] = "Plan 9 AuthPAK key";
uchar *bp, z[PAKSLEN], salt[SHA2_256dlen];
mpint *PX,*PY,*PZ,*PT, *X, *Y, *Z, *ok;
DigestState *s;
PAKcurve *c;
int ret;
X = mpnew(0);
Y = mpnew(0);
Z = mpnew(0);
ok = mpnew(0);
PX = mpnew(0);
PY = mpnew(0);
PZ = mpnew(0);
PT = mpnew(0);
PX->flags |= MPtimesafe;
PY->flags |= MPtimesafe;
PZ->flags |= MPtimesafe;
PT->flags |= MPtimesafe;
bp = k->pakhash + PAKPLEN*(p->isclient != 0);
betomp(bp, PAKSLEN, PX), bp += PAKSLEN;
betomp(bp, PAKSLEN, PY), bp += PAKSLEN;
betomp(bp, PAKSLEN, PZ), bp += PAKSLEN;
betomp(bp, PAKSLEN, PT);
Z->flags |= MPtimesafe;
X->flags |= MPtimesafe;
betomp(p->x, PAKXLEN, X);
betomp(y, PAKYLEN, Y);
c = authpak_curve();
spake2ee_2(c->P,c->A,c->D, PX,PY,PZ,PT, X, Y, ok, Z);
if(mpcmp(ok, mpzero) == 0){
ret = -1;
goto out;
}
mptober(Z, z, sizeof(z));
s = sha2_256(p->isclient ? p->y : y, PAKYLEN, nil, nil);
sha2_256(p->isclient ? y : p->y, PAKYLEN, salt, s);
hkdf_x( salt, SHA2_256dlen,
(uchar*)info, sizeof(info)-1,
z, sizeof(z),
k->pakkey, PAKKEYLEN,
hmac_sha2_256, SHA2_256dlen);
ret = 0;
out:
memset(z, 0, sizeof(z));
memset(p, 0, sizeof(PAKpriv));
mpfree(PX);
mpfree(PY);
mpfree(PZ);
mpfree(PT);
mpfree(X);
mpfree(Y);
mpfree(Z);
mpfree(ok);
return ret;
}

View file

@ -2,26 +2,35 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) *p++ = f->x extern int form1B2M(char *ap, int n, uchar key[32]);
#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
#define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(p, f->x, n); p += n
int int
convA2M(Authenticator *f, char *ap, int n, Ticket *t) convA2M(Authenticator *f, char *ap, int n, Ticket *t)
{ {
uchar *p; uchar *p;
if(n < AUTHENTLEN) if(n < 1+CHALLEN)
return 0; return 0;
p = (uchar*)ap; p = (uchar*)ap;
CHAR(num); *p++ = f->num;
STRING(chal, CHALLEN); memmove(p, f->chal, CHALLEN), p += CHALLEN;
LONG(id); switch(t->form){
case 0:
if(n < 1+CHALLEN+4)
return 0;
memset(p, 0, 4), p += 4; /* unused id field */
n = p - (uchar*)ap; n = p - (uchar*)ap;
if(t)
encrypt(t->key, ap, n); encrypt(t->key, ap, n);
return n; return n;
case 1:
if(n < 12+CHALLEN+NONCELEN+16)
return 0;
memmove(p, f->rand, NONCELEN), p += NONCELEN;
return form1B2M(ap, (char*)p - ap, t->key);
}
return 0;
} }

View file

@ -2,30 +2,35 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) f->x = *p++ extern int form1M2B(char *ap, int n, uchar key[32]);
#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
#define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(f->x, p, n); p += n
int int
convM2A(char *ap, int n, Authenticator *f, Ticket *t) convM2A(char *ap, int n, Authenticator *f, Ticket *t)
{ {
uchar *p, buf[AUTHENTLEN]; uchar buf[MAXAUTHENTLEN], *p;
int m;
memset(f, 0, sizeof(Authenticator)); memset(f, 0, sizeof(Authenticator));
if(n < AUTHENTLEN) if(t->form == 0){
return -AUTHENTLEN; m = 1+CHALLEN+4;
if(n < m)
return -m;
memmove(buf, ap, m);
decrypt(t->key, buf, m);
} else {
m = 12+CHALLEN+NONCELEN+16;
if(n < m)
return -m;
memmove(buf, ap, m);
if(form1M2B((char*)buf, m, t->key) < 0)
return m;
}
p = buf;
f->num = *p++;
memmove(f->chal, p, CHALLEN);
p += CHALLEN;
if(t->form == 1)
memmove(f->rand, p, NONCELEN);
if(t) { return m;
memmove(buf, ap, AUTHENTLEN);
ap = (char*)buf;
decrypt(t->key, ap, AUTHENTLEN);
}
p = (uchar*)ap;
CHAR(num);
STRING(chal, CHALLEN);
LONG(id);
n = p - (uchar*)ap;
return n;
} }

View file

@ -2,35 +2,38 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) f->x = *p++ extern int form1M2B(char *ap, int n, uchar key[32]);
#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
#define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(f->x, p, n); p += n
int int
convM2PR(char *ap, int n, Passwordreq *f, Ticket *t) convM2PR(char *ap, int n, Passwordreq *f, Ticket *t)
{ {
uchar *p, buf[PASSREQLEN]; uchar *p, buf[MAXPASSREQLEN];
int m;
memset(f, 0, sizeof(Passwordreq)); memset(f, 0, sizeof(Passwordreq));
if(n < PASSREQLEN) if(t->form == 0){
return -PASSREQLEN; m = 1+2*ANAMELEN+1+SECRETLEN;
if(n < m)
if(t){ return -m;
memmove(buf, ap, PASSREQLEN); memmove(buf, ap, m);
ap = (char*)buf; decrypt(t->key, buf, m);
decrypt(t->key, ap, PASSREQLEN); } else {
m = 12+2*ANAMELEN+1+SECRETLEN+16;
if(n < m)
return -m;
memmove(buf, ap, m);
if(form1M2B((char*)buf, m, t->key) < 0)
return m;
} }
p = (uchar*)ap; p = buf;
CHAR(num); f->num = *p++;
STRING(old, ANAMELEN); memmove(f->old, p, ANAMELEN), p += ANAMELEN;
memmove(f->new, p, ANAMELEN), p += ANAMELEN;
f->changesecret = *p++;
memmove(f->secret, p, SECRETLEN);
f->old[ANAMELEN-1] = 0; f->old[ANAMELEN-1] = 0;
STRING(new, ANAMELEN);
f->new[ANAMELEN-1] = 0; f->new[ANAMELEN-1] = 0;
CHAR(changesecret);
STRING(secret, SECRETLEN);
f->secret[SECRETLEN-1] = 0; f->secret[SECRETLEN-1] = 0;
n = p - (uchar*)ap;
return n; return m;
} }

View file

@ -2,34 +2,50 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) f->x = *p++ extern int form1check(char *ap, int n);
#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 extern int form1M2B(char *ap, int n, uchar key[32]);
#define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(f->x, p, n); p += n
int int
convM2T(char *ap, int n, Ticket *f, Authkey *key) convM2T(char *ap, int n, Ticket *f, Authkey *k)
{ {
uchar *p, buf[TICKETLEN]; uchar buf[MAXTICKETLEN], *p;
int m;
if(f != nil)
memset(f, 0, sizeof(Ticket)); memset(f, 0, sizeof(Ticket));
if(n < TICKETLEN)
return -TICKETLEN;
if(key){ if(n < 8)
memmove(buf, ap, TICKETLEN); return -8;
ap = (char*)buf;
decrypt(key->des, ap, TICKETLEN); if(form1check(ap, n) < 0){
m = 1+CHALLEN+2*ANAMELEN+DESKEYLEN;
if(n < m)
return -m;
if(f == nil || k == nil)
return m;
f->form = 0;
memmove(buf, ap, m);
decrypt(k->des, buf, m);
} else {
m = 12+CHALLEN+2*ANAMELEN+NONCELEN+16;
if(n < m)
return -m;
if(f == nil || k == nil)
return m;
f->form = 1;
memmove(buf, ap, m);
if(form1M2B((char*)buf, m, k->pakkey) < 0)
return m;
} }
p = (uchar*)ap; p = buf;
CHAR(num); f->num = *p++;
STRING(chal, CHALLEN); memmove(f->chal, p, CHALLEN), p += CHALLEN;
STRING(cuid, ANAMELEN); memmove(f->cuid, p, ANAMELEN), p += ANAMELEN;
memmove(f->suid, p, ANAMELEN), p += ANAMELEN;
memmove(f->key, p, f->form == 0 ? DESKEYLEN : NONCELEN);
f->cuid[ANAMELEN-1] = 0; f->cuid[ANAMELEN-1] = 0;
STRING(suid, ANAMELEN);
f->suid[ANAMELEN-1] = 0; f->suid[ANAMELEN-1] = 0;
STRING(key, DESKEYLEN);
n = p - (uchar*)ap; return m;
return n;
} }

View file

@ -2,12 +2,6 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) f->x = *p++
#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
#define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(f->x, p, n); p += n
int int
convM2TR(char *ap, int n, Ticketreq *f) convM2TR(char *ap, int n, Ticketreq *f)
{ {
@ -18,16 +12,18 @@ convM2TR(char *ap, int n, Ticketreq *f)
return -TICKREQLEN; return -TICKREQLEN;
p = (uchar*)ap; p = (uchar*)ap;
CHAR(type); f->type = *p++;
STRING(authid, ANAMELEN); memmove(f->authid, p, ANAMELEN), p += ANAMELEN;
memmove(f->authdom, p, DOMLEN), p += DOMLEN;
memmove(f->chal, p, CHALLEN), p += CHALLEN;
memmove(f->hostid, p, ANAMELEN), p += ANAMELEN;
memmove(f->uid, p, ANAMELEN), p += ANAMELEN;
f->authid[ANAMELEN-1] = 0; f->authid[ANAMELEN-1] = 0;
STRING(authdom, DOMLEN);
f->authdom[DOMLEN-1] = 0; f->authdom[DOMLEN-1] = 0;
STRING(chal, CHALLEN);
STRING(hostid, ANAMELEN);
f->hostid[ANAMELEN-1] = 0; f->hostid[ANAMELEN-1] = 0;
STRING(uid, ANAMELEN);
f->uid[ANAMELEN-1] = 0; f->uid[ANAMELEN-1] = 0;
n = p - (uchar*)ap; n = p - (uchar*)ap;
return n; return n;
} }

View file

@ -2,29 +2,33 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) *p++ = f->x extern int form1B2M(char *ap, int n, uchar key[32]);
#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
#define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(p, f->x, n); p += n
int int
convPR2M(Passwordreq *f, char *ap, int n, Ticket *t) convPR2M(Passwordreq *f, char *ap, int n, Ticket *t)
{ {
uchar *p; uchar *p;
if(n < PASSREQLEN) if(n < 1+2*ANAMELEN+1+SECRETLEN)
return 0; return 0;
p = (uchar*)ap; p = (uchar*)ap;
CHAR(num); *p++ = f->num;
STRING(old, ANAMELEN); memmove(p, f->old, ANAMELEN), p += ANAMELEN;
STRING(new, ANAMELEN); memmove(p, f->new, ANAMELEN), p += ANAMELEN;
CHAR(changesecret); *p++ = f->changesecret;
STRING(secret, SECRETLEN); memmove(p, f->secret, SECRETLEN), p += SECRETLEN;
switch(t->form){
case 0:
n = p - (uchar*)ap; n = p - (uchar*)ap;
if(t)
encrypt(t->key, ap, n); encrypt(t->key, ap, n);
return n; return n;
case 1:
if(n < 12+2*ANAMELEN+1+SECRETLEN+16)
return 0;
return form1B2M(ap, p - (uchar*)ap, t->key);
}
return 0;
} }

View file

@ -1,29 +1,39 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#include <libsec.h>
#define CHAR(x) *p++ = f->x extern int form1B2M(char *ap, int n, uchar key[32]);
#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
#define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(p, f->x, n); p += n
int int
convT2M(Ticket *f, char *ap, int n, Authkey *key) convT2M(Ticket *f, char *ap, int n, Authkey *key)
{ {
uchar *p; uchar *p;
if(n < TICKETLEN) if(n < 1+CHALLEN+2*ANAMELEN)
return 0; return 0;
p = (uchar*)ap; p = (uchar*)ap;
CHAR(num); *p++ = f->num;
STRING(chal, CHALLEN); memmove(p, f->chal, CHALLEN), p += CHALLEN;
STRING(cuid, ANAMELEN); memmove(p, f->cuid, ANAMELEN), p += ANAMELEN;
STRING(suid, ANAMELEN); memmove(p, f->suid, ANAMELEN), p += ANAMELEN;
STRING(key, DESKEYLEN); switch(f->form){
case 0:
if(n < 1+CHALLEN+2*ANAMELEN+DESKEYLEN)
return 0;
memmove(p, f->key, DESKEYLEN), p += DESKEYLEN;
n = p - (uchar*)ap; n = p - (uchar*)ap;
if(key)
encrypt(key->des, ap, n); encrypt(key->des, ap, n);
return n; return n;
case 1:
if(n < 12+CHALLEN+2*ANAMELEN+NONCELEN+16)
return 0;
memmove(p, f->key, NONCELEN), p += NONCELEN;
return form1B2M(ap, p - (uchar*)ap, key->pakkey);
}
return 0;
} }

View file

@ -2,12 +2,6 @@
#include <libc.h> #include <libc.h>
#include <authsrv.h> #include <authsrv.h>
#define CHAR(x) *p++ = f->x
#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
#define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
#define LONG(x) VLONG(f->x)
#define STRING(x,n) memmove(p, f->x, n); p += n
int int
convTR2M(Ticketreq *f, char *ap, int n) convTR2M(Ticketreq *f, char *ap, int n)
{ {
@ -17,12 +11,13 @@ convTR2M(Ticketreq *f, char *ap, int n)
return 0; return 0;
p = (uchar*)ap; p = (uchar*)ap;
CHAR(type); *p++ = f->type;
STRING(authid, 28); /* BUG */ memmove(p, f->authid, ANAMELEN), p += ANAMELEN;
STRING(authdom, DOMLEN); memmove(p, f->authdom, DOMLEN), p += DOMLEN;
STRING(chal, CHALLEN); memmove(p, f->chal, CHALLEN), p += CHALLEN;
STRING(hostid, 28); /* BUG */ memmove(p, f->hostid, ANAMELEN), p += ANAMELEN;
STRING(uid, 28); /* BUG */ memmove(p, f->uid, ANAMELEN), p += ANAMELEN;
n = p - (uchar*)ap; n = p - (uchar*)ap;
return n; return n;
} }

View file

@ -0,0 +1,49 @@
# negate r when n > (p-1)/2
decaf_neg(p, n, r) {
mod(p) m = -r;
r = n > (p-1)>>1 ? m : r;
}
# field F_p
# curve a*x**2+y**2==1+d*x**2*y**2
# input X,Y,Z,T (extended coordinates)
decaf_encode(p,a,d, X,Y,Z,T, s) mod(p) {
r = misqrt((a-d)*(Z+Y)*(Z-Y), p);
u = (a-d)*r;
decaf_neg(p, -2*u*Z, r);
s = u*(r*(a*Z*X-d*Y*T)+Y)/a;
decaf_neg(p, s, s);
}
# field F_p
# curve a*x**2+y**2==1+d*x**2*y**2
# input s
# output in extended coordinates
decaf_decode(p,a,d, s, ok,X,Y,Z,T) {
if(s > (p-1)>>1){
ok = 0;
} else mod(p) {
ss = s^2;
Z = 1+a*ss;
u = Z^2 - 4*d*ss;
v = u*ss;
if(v == 0)
ok = 1;
else {
ok = msqrt(v, p);
if(ok != 0){
v = 1/ok;
ok = 1;
}
}
if(ok != 0) {
decaf_neg(p, u*v, v);
w = v * s * (2-Z);
if(s == 0)
w = w + 1;
X = 2*s;
Y = w * Z;
T = w * X;
}
}
}

View file

@ -0,0 +1,11 @@
# Edwards Curve Ed448-Goldilocks
# x^2+y^2 = 1-39081x^2y^2
# modulo p = 2^448 - 1^224 - 1
ed448_curve(p,a,d,x,y) {
p = (1<<448) - (1<<224) - 1;
a = 1;
d = -39081;
x = 117812161263436946737282484343310064665180535357016373416879082147939404277809514858788439644911793978499419995990477371552926308078495;
y = 19;
}

View file

@ -0,0 +1,40 @@
# Edwards curve arithmetic
edwards_add(p,a,d, X1,Y1,Z1,T1, X2,Y2,Z2,T2, X3,Y3,Z3,T3) mod(p) {
A = X1*X2;
B = Y1*Y2;
C = d*T1*T2;
D = Z1*Z2;
E = (X1+Y1)*(X2+Y2);
E = E - A - B;
F = D - C;
G = D + C;
H = B - a*A;
X3 = E*F;
Y3 = G*H;
Z3 = F*G;
T3 = E*H;
}
edwards_sel(s, X1,Y1,Z1,T1, X2,Y2,Z2,T2, X3,Y3,Z3,T3){
X3 = s != 0 ? X1 : X2;
Y3 = s != 0 ? Y1 : Y2;
Z3 = s != 0 ? Z1 : Z2;
T3 = s != 0 ? T1 : T2;
}
edwards_new(x,y,z,t, X,Y,Z,T) {
X = x;
Y = y;
Z = z;
T = t;
}
edwards_scale(p,a,d, s, X1,Y1,Z1,T1, X3,Y3,Z3,T3) {
X2,Y2,Z2,T2 = edwards_new(X1,Y1,Z1,T1);
X4,Y4,Z4,T4 = edwards_new( 0, 1, 1, 0);
X3,Y3,Z3,T3 = edwards_sel(s % 2, X2,Y2,Z2,T2, X4,Y4,Z4,T4);
k = s >> 1; j = p >> 1;
while(j != 0){
X2,Y2,Z2,T2 = edwards_add(p,a,d, X2,Y2,Z2,T2, X2,Y2,Z2,T2);
X4,Y4,Z4,T4 = edwards_add(p,a,d, X2,Y2,Z2,T2, X3,Y3,Z3,T3);
X3,Y3,Z3,T3 = edwards_sel(k % 2, X4,Y4,Z4,T4, X3,Y3,Z3,T3);
k = k >> 1; j = j >> 1;
}
}

View file

@ -0,0 +1,30 @@
#elligator2:
# curve a*x^2+y^2==1+d*x^2*y^2
# input r0
# n is any non-square
#
elligator2(p,a,d, n, r0, X,Y,Z,T) mod(p) {
r = n*r0*r0;
D = (d*r+a-d)*(d*r-a*r-d);
N = (r+1)*(a-2*d);
ND = N*D;
if(ND == 0) {
c = 1;
e = 0;
} else {
e = msqrt(ND, p);
if(e != 0) {
c = 1;
e = 1/e;
} else {
c = -1;
e = n*r0*misqrt(n*ND, p);
}
}
s = c*N*e;
t = -c*N*(r-1)*((a-2*d)*e)^2-1;
X = 2*s*t;
Y = (1-a*s*s)*(1+a*s*s);
Z = (1+a*s*s)*t;
T = (2*s)*(1-a*s*s);
}

View file

@ -0,0 +1,90 @@
#include <u.h>
#include <libc.h>
#include <authsrv.h>
#include <libsec.h>
/*
* new ticket format: the reply protector/type is replaced by a
* 8 byte signature and a 4 byte counter forming the 12 byte
* nonce for chacha20/poly1305 encryption. a 16 byte poly1305
* authentication tag is appended for message authentication.
* the counter is needed for the AuthPass message which uses
* the same key for several messages.
*/
static struct {
char num;
char sig[8];
} form1sig[] = {
AuthPass, "form1 PR", /* password change request encrypted with ticket key */
AuthTs, "form1 Ts", /* ticket encrypted with server's key */
AuthTc, "form1 Tc", /* ticket encrypted with client's key */
AuthAs, "form1 As", /* server generated authenticator */
AuthAc, "form1 Ac", /* client generated authenticator */
AuthTp, "form1 Tp", /* ticket encrypted with client's key for password change */
AuthHr, "form1 Hr", /* http reply */
};
int
form1check(char *ap, int n)
{
if(n < 8)
return -1;
for(n=0; n<nelem(form1sig); n++)
if(memcmp(form1sig[n].sig, ap, 8) == 0)
return form1sig[n].num;
return -1;
}
int
form1B2M(char *ap, int n, uchar key[32])
{
static u32int counter;
Chachastate s;
uchar *p;
int i;
for(i=nelem(form1sig)-1; i>=0; i--)
if(form1sig[i].num == *ap)
break;
if(i < 0)
abort();
p = (uchar*)ap + 12;
memmove(p, ap+1, --n);
/* nonce[12] = sig[8] | counter[4] */
memmove(ap, form1sig[i].sig, 8);
i = counter++;
ap[8] = i, ap[9] = i>>8, ap[10] = i>>16, ap[11] = i>>24;
setupChachastate(&s, key, 32, (uchar*)ap, 12, 20);
ccpoly_encrypt(p, n, nil, 0, p+n, &s);
return 12+16 + n;
}
int
form1M2B(char *ap, int n, uchar key[32])
{
Chachastate s;
uchar *p;
int num;
num = form1check(ap, n);
if(num < 0)
return -1;
n -= 12+16;
if(n <= 0)
return -1;
p = (uchar*)ap + 12;
setupChachastate(&s, key, 32, (uchar*)ap, 12, 20);
if(ccpoly_decrypt(p, n, nil, 0, p+n, &s))
return -1;
memmove(ap+1, p, n);
ap[0] = num;
return n+1;
}

View file

@ -2,10 +2,12 @@
LIB=/$objtype/lib/libauthsrv.a LIB=/$objtype/lib/libauthsrv.a
OFILES=\ OFILES=\
_asgetpakkey.$O\
_asgetticket.$O\ _asgetticket.$O\
_asgetresp.$O\ _asgetresp.$O\
_asrequest.$O\ _asrequest.$O\
_asrdresp.$O\ _asrdresp.$O\
authpak.$O\
authdial.$O\ authdial.$O\
convA2M.$O\ convA2M.$O\
convM2A.$O\ convM2A.$O\
@ -15,17 +17,35 @@ OFILES=\
convPR2M.$O\ convPR2M.$O\
convT2M.$O\ convT2M.$O\
convTR2M.$O\ convTR2M.$O\
form1.$O\
nvcsum.$O\ nvcsum.$O\
passtokey.$O\ passtokey.$O\
readnvram.$O\ readnvram.$O\
HFILES=\ HFILES=\
/sys/include/authsrv.h\ /sys/include/authsrv.h
MPCFILES=\
msqrt.mpc\
decaf.mpc\
edwards.mpc\
elligator2.mpc\
spake2ee.mpc\
ed448.mpc\
UPDATE=\ UPDATE=\
mkfile\ mkfile\
$HFILES\ $HFILES\
${OFILES:%.$O=%.c}\ ${OFILES:%.$O=%.c}\
${MPCFILES:.mpc=%.mp}\
${LIB:/$objtype/%=/386/%}\ ${LIB:/$objtype/%=/386/%}\
CLEANFILES=$MPCFILES
</sys/src/cmd/mksyslib </sys/src/cmd/mksyslib
authpak.$O: $MPCFILES
%.mpc: %.mp
mpc $stem.mp > $target

100
sys/src/libauthsrv/msqrt.mp Normal file
View file

@ -0,0 +1,100 @@
# derived from: http://eli.thegreenplace.net/2009/03/07/computing-square-roots-in-python
# Compute the Legendre symbol a|p using Euler's criterion.
# p is a prime, a is relatively prime to p (if p divides a,
# then a|p = 0)
legendresymbol(a, p, r) {
pm1 = p-1;
mod(p) r = a^(pm1>>1);
if(r == pm1)
r = -1;
}
# Find a quadratic residue (mod p) of 'a'. p must be an
# odd prime.
#
# Solve the congruence of the form:
# x^2 = a (mod p)
# And returns x. Node that p - x is also a root.
#
# 0 is returned if no square root exists for these
# a and p.
#
# The Tonelli-Shanks algorithm is used (except
# for some simple cases in which the solution is known
# from an identity).
msqrt(a, p, r) {
if(legendresymbol(a, p) != 1)
r = 0;
else if(a == 0)
r = 0;
else if(p == 2)
r = a;
else if(p%4 == 3){
e = p+1 >> 2;
mod(p) r = a^e;
} else {
# Partition p-1 to s * 2^e for an odd s (i.e.
# reduce all the powers of 2 from p-1)
s = p-1;
e = 0;
while(s%2 == 0){
s = s >> 1;
e = e + 1;
}
# Find some 'n' with a legendre symbol n|p = -1.
# Shouldn't take long.
n = 2;
while(legendresymbol(n, p) != -1)
n = n + 1;
# x is a guess of the square root that gets better
# with each iteration.
# b is the "fudge factor" - by now much we're off
# with the guess. The invariant x^2 == a*b (mod p)
# is maintained throughout the loop.
# g is used for successive powers of n to update
# both a and b
# e is the exponent - decreases with each update
mod(p){
x = a^(s+1 >> 1);
b = a^s;
g = n^s;
}
while(1==1){
t = b;
m = 0;
while(m < e){
if(t == 1)
break;
t = t*t % p;
m = m + 1;
}
if(m == 0){
r = x;
break;
}
t = 2^(e-m-1);
mod(p){
gs = g^t;
g = gs*gs;
x = x*gs;
b = b*g;
}
e = m;
}
}
}
# modular inverse square-root
misqrt(a, p, r) {
if((p % 4) == 3){
e = ((p-3)>>2);
mod(p) r = a^e;
} else {
r = msqrt(a, p);
if(r != 0)
mod(p) r = 1/r;
}
}

View file

@ -3,8 +3,8 @@
#include <authsrv.h> #include <authsrv.h>
#include <libsec.h> #include <libsec.h>
static void void
passtodeskey(char *key, char *p) passtodeskey(char key[DESKEYLEN], char *p)
{ {
uchar buf[ANAMELEN], *t; uchar buf[ANAMELEN], *t;
int i, n; int i, n;
@ -32,17 +32,17 @@ passtodeskey(char *key, char *p)
} }
} }
static void void
passtoaeskey(uchar *key, char *p) passtoaeskey(uchar key[AESKEYLEN], char *p)
{ {
static char salt[] = "Plan 9 key derivation"; static char salt[] = "Plan 9 key derivation";
pbkdf2_x((uchar*)p, strlen(p), (uchar*)salt, sizeof(salt)-1, 9001, key, AESKEYLEN, hmac_sha1, SHA1dlen); pbkdf2_x((uchar*)p, strlen(p), (uchar*)salt, sizeof(salt)-1, 9001, key, AESKEYLEN, hmac_sha1, SHA1dlen);
} }
void void
passtokey(Authkey *key, char *p) passtokey(Authkey *key, char *pw)
{ {
memset(key, 0, sizeof(Authkey)); memset(key, 0, sizeof(Authkey));
passtodeskey(key->des, p); passtodeskey(key->des, pw);
passtoaeskey(key->aes, p); passtoaeskey(key->aes, pw);
} }

View file

@ -0,0 +1,35 @@
#
# this implements a variant of SPAKE2 Elligator edition described in:
# https://www.mail-archive.com/curves@moderncrypto.org/msg00412.html
#
# derive points PM or PN from a (password) hash
spake2ee_h2P(p,a,d, h, PX,PY,PZ,PT){
# find a small non-square for elligator
n = 2;
while(legendresymbol(n, p) != -1)
n = n + 1;
PX,PY,PZ,PT = elligator2(p,a,d, n, h%p);
}
# Ya = xa*G+PM, Yb = xb*G+PN
spake2ee_1(p,a,d, x, GX,GY, PX,PY,PZ,PT, y){
mod(p) X,Y,Z,T = edwards_scale(p,a,d, x, GX,GY,1,GX*GY);
X,Y,Z,T = edwards_add(p,a,d, X,Y,Z,T, PX,PY,PZ,PT);
y = decaf_encode(p,a,d, X,Y,Z,T);
}
# Z = xa*(Yb-PN)
# = xa*(xb*G+PN-PN)
# = xa*xb*G
# = xb*xa*G
# = xb*(xa*G+PM-PM)
# = xb*(Ya-PM)
spake2ee_2(p,a,d, PX,PY,PZ,PT, x, y, ok, z){
ok, X,Y,Z,T = decaf_decode(p,a,d, y);
if(ok != 0){
mod(p) X,Y,Z,T = edwards_add(p,a,d, X,Y,Z,T, -PX,PY,PZ,-PT);
X,Y,Z,T = edwards_scale(p,a,d, x, X,Y,Z,T);
z = decaf_encode(p,a,d, X,Y,Z,T);
}
}