ref: 2dae1ed53a73d81bfb86778793a6bda265d5140d
parent: e064752dd476b7a2f76567f8cc15f9c2645e5d3d
author: cinap_lenrek <[email protected]>
date: Tue Jan 5 22:09:00 EST 2016
auth: release dp9ik implementation and reentrant factotum
--- a/sys/include/authsrv.h
+++ b/sys/include/authsrv.h
@@ -20,16 +20,27 @@
AERRLEN= 64, /* errstr max size in previous proto */
DOMLEN= 48, /* authentication domain name length */
DESKEYLEN= 7, /* encrypt/decrypt des key length */
- AESKEYLEN= 16,
+ AESKEYLEN= 16, /* encrypt/decrypt aes key length */
+
CHALLEN= 8, /* plan9 sk1 challenge length */
NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
CONFIGLEN= 14,
SECRETLEN= 32, /* secret max size */
+ NONCELEN= 32,
+
KEYDBOFF= 8, /* bytes of random data at key file's start */
OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* old key file entry length */
KEYDBLEN= OKEYDBLEN+SECRETLEN, /* key file entry length */
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) */
@@ -48,8 +59,7 @@
AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
AuthHttp=13, /* http domain login */
AuthVNC=14, /* VNC server login (deprecated) */
-
-
+ AuthPAK=19, /* authenticated diffie hellman key agreement */
AuthTs=64, /* ticket encrypted with server's key */
AuthTc, /* ticket encrypted with client's key */
AuthAs, /* server generated authenticator */
@@ -75,17 +85,19 @@
char chal[CHALLEN]; /* server challenge */
char cuid[ANAMELEN]; /* uid on client */
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
{
char num; /* replay protection */
- char chal[CHALLEN];
- ulong id; /* authenticator id, ++'d with each auth */
+ char chal[CHALLEN]; /* server/client challenge */
+ uchar rand[NONCELEN]; /* server/client nonce */
};
-#define AUTHENTLEN (CHALLEN+4+1)
+#define MAXAUTHENTLEN (12+CHALLEN+NONCELEN+16)
struct Passwordreq
{
@@ -95,7 +107,7 @@
char changesecret;
char secret[SECRETLEN]; /* new secret */
};
-#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN)
+#define MAXPASSREQLEN (12+2*ANAMELEN+1+SECRETLEN+16)
struct OChapreply
{
@@ -115,8 +127,10 @@
struct Authkey
{
- char des[DESKEYLEN];
- uchar aes[AESKEYLEN];
+ char des[DESKEYLEN]; /* DES key from password */
+ 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 convM2PR(char*, int, Passwordreq*, Ticket*);
/*
- * convert ascii password to DES key
+ * convert ascii password to auth key
*/
extern void passtokey(Authkey*, char*);
+extern void passtodeskey(char key[DESKEYLEN], char *p);
+extern void passtoaeskey(uchar key[AESKEYLEN], char *p);
+
/*
* Nvram interface
*/
@@ -169,7 +186,7 @@
};
extern uchar nvcsum(void*, int);
-extern int readnvram(Nvrsafe*, int);
+extern int readnvram(Nvrsafe*, int);
/*
* call up auth server
@@ -179,7 +196,23 @@
/*
* exchange messages with auth server
*/
+extern int _asgetpakkey(int, Ticketreq*, Authkey*);
extern int _asgetticket(int, Ticketreq*, char*, int);
extern int _asrequest(int, Ticketreq*);
extern int _asgetresp(int, Ticket*, Authenticator*, Authkey *);
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]);
--- a/sys/man/6/authsrv
+++ b/sys/man/6/authsrv
@@ -1,6 +1,6 @@
.TH AUTHSRV 6
.SH NAME
-authsrv, p9any, p9sk1, p9sk2 \- authentication protocols
+authsrv, p9any, p9sk1, dp9ik \- authentication protocols
.SH DESCRIPTION
This manual page describes
the protocols used to authorize connections, confirm the identities
@@ -14,8 +14,9 @@
holds for each public machine, such as a CPU server or
file server, the name of the authentication server that machine uses.
.PP
-Each machine contains three values important to authentication; a 56-bit DES
-key, a 28-byte authentication ID, and a 48-byte authentication domain name.
+Each machine contains four values important to authentication; a 56-bit DES
+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
kernel running on that machine.
The domain name identifies the machines across which the ID is valid.
@@ -29,7 +30,7 @@
.I passtokey
(see
.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.
If possible,
.I factotum
@@ -60,7 +61,7 @@
a nonce key created for a ticket
.RB ( key )
.TP
-.IR K { m }
+.I K{m}
message
.I m
encrypted with key
@@ -91,6 +92,24 @@
client's desired ID on server
.RB ( uid ,
.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
.PP
The parenthesized names are the ones used in the
@@ -112,8 +131,9 @@
.IR AuthChap ,
.IR AuthMSchap ,
.IR AuthCram ,
+.IR AuthVNC ,
and
-.IR AuthVNC
+.IR AuthPAK
.RB ( type )
are defined in
.BR <authsrv.h> ,
@@ -142,7 +162,6 @@
.IR CHs ,
.IR IDc ,
.IR IDr
-.sp -\n(PDu
.TP
.IR A \(-> C
.IR AuthOK ,
@@ -265,16 +284,254 @@
.I Kn
and therefore
.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
-.I P9sk2
-is an older variant of
+The
+.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
-used only when connecting to pre-9P2000 remote
-execution services.
-It omits the first message and last
-messages and therefore does not
-authenticate the server to the client.
+that adds the random strings
+.I RNc
+and
+.I RNs
+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
.I P9any
is the standard Plan 9 authentication protocol.
@@ -288,12 +545,10 @@
.IB proto@authdom
.IB proto@authdom
.I ...
-.sp -\n(PDu
.TP
.IR C \(-> S
.I proto
.I dom
-.sp -\n(PDu
.TP
.IR S \(-> C
.B OK
@@ -349,10 +604,10 @@
.TP
.IR C \(-> A
.IR AuthPass ,
-.IR IDc ,
-.IR DN ,
+.IR \- ,
+.IR \- ,
.IR CHc ,
-.IR IDc ,
+.IR \- ,
.IR IDc
.br
The client sends a password change ticket request.
@@ -471,18 +726,15 @@
.I AuthErr
message may be substituted.
.de Ok
-.sp -\n(PDu
.TP
.IR A \(-> S
.IR AuthOK ,
-.IR Ks { \\$1 ,
-.IR IDs ,
-.IR DN ,
+.IR Ks { AuthTs ,
.IR CHs ,
-.IR IDs ,
.IR IDc ,
+.IR IDc ,
.IR Kn },
-.IR Kn { AuthTs ,
+.IR Kn { AuthAc ,
.IR CHs }
..
.PP
@@ -489,21 +741,19 @@
.TP
.IR S \(-> A
.IR AuthChal ,
-.IR IDs ,
+.IR \- ,
.IR DN ,
.IR CHs ,
.IR IDs ,
.IR IDc
-.sp -\n(PDu
.TP
.IR A \(-> S
.IR AuthOK ,
.IR challenge
-.sp -\n(PDu
.TP
.IR S \(-> A
.IR response
-.Ok AuthChal
+.Ok
.IP
This protocol allows the use of
handheld authenticators such as SecureNet
@@ -562,28 +812,26 @@
same id in both places.
.TP
.IR S \(-> A
-AuthApop ,
-.IR IDs ,
+.IR AuthApop ,
+.IR \- ,
.IR DN ,
.IR CHs ,
-.IR \- ,
+.IR IDs ,
.IR \-
-.sp -\n(PDu
.TP
.IR A \(-> S
.IR AuthOKvar ,
.IR challenge
-.sp -\n(PDu
.TP
.IR S \(-> A
-AuthApop ,
-.IR IDs ,
+.IR AuthApop ,
+.IR \- ,
.IR DN ,
.IR CHs ,
-.IR IDc ,
+.IR IDs ,
.IR IDc ;
hexadecimal MD5 checksum
-.Ok AuthApop
+.Ok
.IP
This protocol implements APOP authentication
(see
@@ -616,22 +864,20 @@
.TP
.IR S \(-> A
.IR AuthChap ,
-.IR IDs ,
+.IR \- ,
.IR DN ,
.IR CHs ,
-.IR \- ,
+.IR IDs ,
.IR \-
-.sp -\n(PDu
.TP
.IR A \(-> S
.I challenge
-.sp -\n(PDu
.TP
.IR S \(-> A
.IR pktid ,
.IR IDc ,
.IR response
-.Ok AuthChap
+.Ok
.IP
This protocol implements CHAP authentication
(see
@@ -648,22 +894,20 @@
.TP
.IR S \(-> A
.IR AuthMSchap ,
-.IR IDs ,
+.IR \- ,
.IR DN ,
.IR CHs ,
-.IR \- ,
+.IR IDs ,
.IR \-
-.sp -\n(PDu
.TP
.IR A \(-> S
.I challenge
-.sp -\n(PDu
.TP
.IR S \(-> A
.IR IDc ,
.IR lm-response ,
.IR nt-response
-.Ok AuthMschap
+.Ok
.IP
This protocol implements Microsoft's MS-CHAP
authentication
@@ -682,17 +926,15 @@
.TP
.IR S \(-> A
.IR AuthVNC ,
-.IR IDs ,
+.IR \- ,
.IR DN ,
.IR CHs ,
.IR IDs ,
.IR IDc
-.sp -\n(PDu
.TP
.IR A \(-> S
.IR AuthOKvar ,
.I challenge
-.sp -\n(PDu
.TP
.IR S \(-> A
.I response
--- a/sys/src/cmd/auth/authcmdlib.h
+++ b/sys/src/cmd/auth/authcmdlib.h
@@ -53,6 +53,7 @@
char* netdecimal(char*);
char* netresp(char*, long, char*);
char* okpasswd(char*);
+void private(void);
int querybio(char*, char*, Acctbio*);
void rdbio(char*, char*, Acctbio*);
int readarg(int, char*, int);
--- a/sys/src/cmd/auth/authsrv.c
+++ b/sys/src/cmd/auth/authsrv.c
@@ -8,11 +8,21 @@
#include <authsrv.h>
#include "authcmdlib.h"
-int debug;
Ndb *db;
char raddr[128];
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 */
enum {
MShashlen = 16,
@@ -20,18 +30,19 @@
MSresplen = 24,
};
-int ticketrequest(Ticketreq*);
+void pak(Ticketreq*);
+void ticketrequest(Ticketreq*);
void challengebox(Ticketreq*);
void changepasswd(Ticketreq*);
void apop(Ticketreq*, int);
void chap(Ticketreq*);
void mschap(Ticketreq*);
-void http(Ticketreq*);
void vnc(Ticketreq*);
int speaksfor(char*, char*);
void replyerror(char*, ...);
void getraddr(char*);
-void mkkey(Authkey*);
+void initkeyseed(void);
+void mkkey(Keyslot*);
void mkticket(Ticketreq*, Ticket*);
void nthash(uchar hash[MShashlen], char *passwd);
void lmhash(uchar hash[MShashlen], char *passwd);
@@ -38,7 +49,7 @@
void ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom);
void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
void desencrypt(uchar data[8], uchar key[7]);
-int tickauthreply(Ticketreq*, Authkey*);
+void tickauthreply(Ticketreq*, Authkey*);
void safecpy(char*, char*, int);
void
@@ -49,8 +60,9 @@
int n;
ARGBEGIN{
- case 'd':
- debug++;
+ case 'N':
+ ticketform = 1;
+ break;
}ARGEND
strcpy(raddr, "unknown");
@@ -59,6 +71,9 @@
alarm(10*60*1000); /* kill a connection after 10 minutes */
+ private();
+ initkeyseed();
+
db = ndbopen("/lib/ndb/auth");
if(db == 0)
syslog(0, AUTHLOG, "no /lib/ndb/auth");
@@ -89,48 +104,114 @@
case AuthCram:
apop(&tr, AuthCram);
break;
- case AuthHttp:
- http(&tr);
- break;
case AuthVNC:
vnc(&tr);
break;
+ case AuthPAK:
+ pak(&tr);
+ continue;
default:
syslog(0, AUTHLOG, "unknown ticket request type: %d", tr.type);
exits(0);
}
+ /* invalidate pak keys */
+ akey.id[0] = 0;
+ hkey.id[0] = 0;
+ ukey.id[0] = 0;
}
/* 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
+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)
{
- Authkey akey, hkey;
- char tbuf[2*TICKETLEN+1];
+ char tbuf[2*MAXTICKETLEN+1];
Ticket t;
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 */
mkkey(&akey);
- if(debug)
- syslog(0, AUTHLOG, "tr-fail authid %s", raddr);
+ syslog(0, AUTHLOG, "tr-fail authid %s", tr->authid);
}
- if(!findkey(KEYDB, tr->hostid, &hkey)){
+ if(!getkey(tr->hostid, &hkey)){
/* make one up so caller doesn't know it was wrong */
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);
if(!speaksfor(tr->hostid, tr->uid)){
mkkey(&akey);
mkkey(&hkey);
- if(debug)
- syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
- tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
+ syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for",
+ tr->uid, tr->hostid, raddr, tr->uid, tr->authid);
}
n = 0;
tbuf[n++] = AuthOK;
@@ -138,29 +219,21 @@
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &hkey);
t.num = AuthTs;
n += convT2M(&t, tbuf+n, sizeof(tbuf)-n, &akey);
- if(write(1, tbuf, n) < 0){
- if(debug)
- syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup",
- tr->uid, tr->hostid, raddr);
+ if(write(1, tbuf, n) != n)
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
challengebox(Ticketreq *tr)
{
+ char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], buf[NETCHLEN+1];
+ char *key, *netkey, *err;
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);
netkey = finddeskey(NETKEYDB, tr->uid, nkbuf);
if(key == nil && netkey == nil){
@@ -167,15 +240,13 @@
/* make one up so caller doesn't know it was wrong */
genrandom((uchar*)nkbuf, DESKEYLEN);
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 */
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,9 +256,9 @@
buf[0] = AuthOK;
chal = nfastrand(MAXNETCHAL);
sprint(buf+1, "%lud", chal);
- if(write(1, buf, NETCHLEN+1) < 0)
+ if(write(1, buf, NETCHLEN+1) != NETCHLEN+1)
exits(0);
- if(readn(0, buf, NETCHLEN) < 0)
+ if(readn(0, buf, NETCHLEN) != NETCHLEN)
exits(0);
if(!(key != nil && netcheck(key, chal, buf))
&& !(netkey != nil && netcheck(netkey, chal, buf))
@@ -194,9 +265,6 @@
&& (err = secureidcheck(tr->uid, buf)) != nil){
replyerror("cr-fail %s %s %s", err, tr->uid, raddr);
logfail(tr->uid);
- if(debug)
- syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp",
- tr->uid, tr->hostid, raddr);
return;
}
succeed(tr->uid);
@@ -204,33 +272,24 @@
/*
* reply with ticket & authenticator
*/
- if(tickauthreply(tr, &hkey) < 0){
- if(debug)
- syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup",
- tr->uid, tr->hostid, raddr);
- exits(0);
- }
+ tickauthreply(tr, &hkey);
- 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
changepasswd(Ticketreq *tr)
{
- Ticket t;
- char tbuf[TICKETLEN+1];
- char prbuf[PASSREQLEN];
+ char tbuf[MAXTICKETLEN+1], prbuf[MAXPASSREQLEN], *err;
Passwordreq pr;
- Authkey okey, nkey;
- char *err;
- int n;
+ Authkey nkey;
+ Ticket t;
+ 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 */
- mkkey(&okey);
- syslog(0, AUTHLOG, "cp-fail uid %s", raddr);
+ mkkey(&ukey);
+ syslog(0, AUTHLOG, "cp-fail uid %s@%s", tr->uid, raddr);
}
/* send back a ticket with a new key */
@@ -238,25 +297,30 @@
t.num = AuthTp;
n = 0;
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)
exits(0);
/* loop trying passwords out */
for(;;){
- n = readn(0, prbuf, sizeof(prbuf));
- if(n <= 0 || convM2PR(prbuf, n, &pr, &t) <= 0)
- exits(0);
+ for(n=0; (m = convM2PR(prbuf, n, &pr, &t)) <= 0; n += m){
+ m = -m;
+ if(m <= n || m > sizeof(prbuf))
+ exits(0);
+ m -= n;
+ if(readn(0, prbuf+n, m) != m)
+ exits(0);
+ }
if(pr.num != AuthPass){
replyerror("protocol botch1: %s", raddr);
exits(0);
}
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);
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);
continue;
}
@@ -276,58 +340,17 @@
replyerror("can't write key %s", raddr);
continue;
}
+ memmove(ukey.des, nkey.des, DESKEYLEN);
+ memmove(ukey.aes, nkey.aes, AESKEYLEN);
break;
}
+ succeed(tr->uid);
prbuf[0] = AuthOK;
- write(1, prbuf, 1);
- succeed(tr->uid);
- return;
+ if(write(1, prbuf, 1) != 1)
+ exits(0);
}
-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*
domainname(void)
{
@@ -371,7 +394,6 @@
{
int challen, i, n, tries;
char *secret, *p;
- Authkey hkey;
Ticketreq treq;
DigestState *s;
char sbuf[SECRETLEN];
@@ -402,7 +424,7 @@
if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)
exits(0);
tr = &treq;
- if(tr->type != type)
+ if(tr->type != type || tr->uid[0] == 0)
exits(0);
/*
@@ -417,11 +439,11 @@
* lookup
*/
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);
logfail(tr->uid);
if(tries > 5)
- return;
+ exits(0);
continue;
}
@@ -436,11 +458,11 @@
s = md5((uchar*)chal, challen, 0, 0);
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);
logfail(tr->uid);
if(tries > 5)
- return;
+ exits(0);
continue;
}
break;
@@ -451,15 +473,12 @@
/*
* reply with ticket & authenticator
*/
- if(tickauthreply(tr, &hkey) < 0)
- exits(0);
+ tickauthreply(tr, &hkey);
- if(debug){
- if(type == AuthCram)
- syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);
- else
- syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);
- }
+ if(type == AuthCram)
+ syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr);
+ else
+ syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr);
}
enum {
@@ -489,14 +508,16 @@
void
vnc(Ticketreq *tr)
{
- char *secret;
- Authkey hkey;
uchar chal[VNCchallen+6];
uchar reply[VNCchallen];
char sbuf[SECRETLEN];
+ char *secret;
DESstate s;
int i;
+ if(tr->uid[0] == 0)
+ exits(0);
+
/*
* Create a challenge and send it.
*/
@@ -504,7 +525,7 @@
chal[0] = AuthOKvar;
sprint((char*)chal+1, "%-5d", VNCchallen);
if(write(1, chal, sizeof(chal)) != sizeof(chal))
- return;
+ exits(0);
/*
* lookup keys (and swizzle bits)
@@ -511,7 +532,8 @@
*/
memset(sbuf, 0, sizeof(sbuf));
secret = findsecret(KEYDB, tr->uid, sbuf);
- if(secret == nil){
+ if(!getkey(tr->hostid, &hkey) || secret == nil){
+ mkkey(&hkey);
genrandom((uchar*)sbuf, sizeof(sbuf));
secret = sbuf;
}
@@ -518,14 +540,11 @@
for(i = 0; i < 8; i++)
secret[i] = swizzletab[(uchar)secret[i]];
- if(!findkey(KEYDB, tr->hostid, &hkey))
- mkkey(&hkey);
-
/*
* get response
*/
if(readn(0, reply, sizeof(reply)) != sizeof(reply))
- return;
+ exits(0);
/*
* decrypt response and compare
@@ -532,7 +551,7 @@
*/
setupDESstate(&s, (uchar*)secret, nil);
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);
logfail(tr->uid);
return;
@@ -542,11 +561,9 @@
/*
* reply with ticket & authenticator
*/
- if(tickauthreply(tr, &hkey) < 0)
- exits(0);
+ tickauthreply(tr, &hkey);
- if(debug)
- syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr);
+ syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr);
}
void
@@ -553,7 +570,6 @@
chap(Ticketreq *tr)
{
char *secret;
- Authkey hkey;
DigestState *s;
char sbuf[SECRETLEN];
uchar digest[MD5dlen];
@@ -564,7 +580,8 @@
* Create a challenge and send it.
*/
genrandom((uchar*)chal, sizeof(chal));
- write(1, chal, sizeof(chal));
+ if(write(1, chal, sizeof(chal)) != sizeof(chal))
+ exits(0);
/*
* get chap reply
@@ -572,15 +589,17 @@
if(readn(0, &reply, sizeof(reply)) < 0)
exits(0);
safecpy(tr->uid, reply.uid, sizeof(tr->uid));
+ if(tr->uid[0] == 0)
+ exits(0);
/*
* lookup
*/
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);
logfail(tr->uid);
- exits(0);
+ return;
}
/*
@@ -590,10 +609,10 @@
md5((uchar*)secret, strlen(secret), 0, 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);
logfail(tr->uid);
- exits(0);
+ return;
}
succeed(tr->uid);
@@ -601,25 +620,11 @@
/*
* reply with ticket & authenticator
*/
- if(tickauthreply(tr, &hkey) < 0)
- exits(0);
+ tickauthreply(tr, &hkey);
- 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 {
MsvAvEOL = 0,
MsvAvNbComputerName,
@@ -666,7 +671,6 @@
mschap(Ticketreq *tr)
{
char *secret;
- Authkey hkey;
char sbuf[SECRETLEN], windom[128];
uchar chal[CHALLEN], ntblob[1024];
uchar hash[MShashlen];
@@ -681,7 +685,8 @@
* Create a challenge and send it.
*/
genrandom(chal, sizeof(chal));
- write(1, chal, sizeof(chal));
+ if(write(1, chal, sizeof(chal)) != sizeof(chal))
+ exits(0);
/*
* get chap reply
@@ -734,15 +739,17 @@
}
safecpy(tr->uid, reply.uid, sizeof(tr->uid));
+ if(tr->uid[0] == 0)
+ exits(0);
+
/*
* lookup
*/
secret = findsecret(KEYDB, tr->uid, sbuf);
- if(!findkey(KEYDB, tr->hostid, &hkey) || secret == nil){
- replyerror("mschap-fail bad response %s/%s(%s)",
- tr->uid, tr->hostid, raddr);
+ if(!getkey(tr->hostid, &hkey) || secret == nil){
+ replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
logfail(tr->uid);
- exits(0);
+ return;
}
if(ntbloblen > 0){
@@ -756,7 +763,7 @@
*/
s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
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)
@@ -763,7 +770,7 @@
*/
s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
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')
break;
@@ -774,11 +781,11 @@
} else {
lmhash(hash, secret);
mschalresp(resp, hash, chal);
- lmok = memcmp(resp, reply.LMresp, MSresplen) == 0;
+ lmok = tsmemcmp(resp, reply.LMresp, MSresplen) == 0;
nthash(hash, secret);
mschalresp(resp, hash, chal);
- ntok = memcmp(resp, reply.NTresp, MSresplen) == 0;
- dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
+ ntok = tsmemcmp(resp, reply.NTresp, MSresplen) == 0;
+ dupe = tsmemcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
}
/*
@@ -795,10 +802,9 @@
* windows clients don't seem to use the feature.
*/
if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){
- replyerror("mschap-fail bad response %s/%s(%s) %d,%d,%d",
- tr->uid, tr->hostid, raddr, dupe, lmok, ntok);
+ replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
logfail(tr->uid);
- exits(0);
+ return;
}
succeed(tr->uid);
@@ -806,11 +812,9 @@
/*
* reply with ticket & authenticator
*/
- if(tickauthreply(tr, &hkey) < 0)
- exits(0);
+ tickauthreply(tr, &hkey);
- if(debug)
- replyerror("mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
+ syslog(0, AUTHLOG, "mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
nthash(hash, secret);
md4(hash, 16, hash2, 0);
@@ -818,7 +822,7 @@
sha1(hash2, 16, 0, s);
sha1(chal, 8, digest, s);
- if(write(1, digest, 16) < 0)
+ if(write(1, digest, 16) != 16)
exits(0);
}
@@ -997,31 +1001,57 @@
}
void
-mkkey(Authkey *k)
+initkeyseed(void)
{
- genrandom((uchar*)k->des, DESKEYLEN);
- genrandom((uchar*)k->aes, AESKEYLEN);
+ static char info[] = "PRF key for generation of dummy user keys";
+ 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
mkticket(Ticketreq *tr, Ticket *t)
{
memset(t, 0, sizeof(Ticket));
memmove(t->chal, tr->chal, CHALLEN);
- safecpy(t->cuid, tr->uid, sizeof(t->cuid));
- safecpy(t->suid, tr->uid, sizeof(t->suid));
- genrandom((uchar*)t->key, DESKEYLEN);
+ safecpy(t->cuid, tr->uid, ANAMELEN);
+ safecpy(t->suid, tr->uid, ANAMELEN);
+ genrandom(t->key, NONCELEN);
+ t->form = ticketform;
}
/*
* reply with ticket and authenticator
*/
-int
-tickauthreply(Ticketreq *tr, Authkey *hkey)
+void
+tickauthreply(Ticketreq *tr, Authkey *key)
{
Ticket t;
Authenticator a;
- char buf[TICKETLEN+AUTHENTLEN+1];
+ char buf[MAXTICKETLEN+MAXAUTHENTLEN+1];
int n;
mkticket(tr, &t);
@@ -1028,15 +1058,14 @@
t.num = AuthTs;
n = 0;
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));
memmove(a.chal, t.chal, CHALLEN);
+ genrandom(a.rand, NONCELEN);
a.num = AuthAc;
- a.id = 0;
n += convA2M(&a, buf+n, sizeof(buf)-n, &t);
if(write(1, buf, n) != n)
- return -1;
- return 0;
+ exits(0);
}
void
--- a/sys/src/cmd/auth/convkeys.c
+++ b/sys/src/cmd/auth/convkeys.c
@@ -43,6 +43,8 @@
usage();
file = argv[0];
+ private();
+
/* get original key */
if(usepass){
print("enter password file is encoded with\n");
--- a/sys/src/cmd/auth/debug.c
+++ b/sys/src/cmd/auth/debug.c
@@ -116,8 +116,8 @@
}
}
-void authdialfutz(char*, char*);
-void authfutz(char*, char*);
+void authdialfutz(char*, char*, char*);
+void authfutz(char*, char*, char*);
/* scan factotum for p9sk1 keys; check them */
void
@@ -143,7 +143,7 @@
a = _parseattr(s+4);
free(s);
proto = _strfindattr(a, "proto");
- if(proto==nil || strcmp(proto, "p9sk1")!=0)
+ if(proto==nil || (strcmp(proto, "p9sk1")!=0 && strcmp(proto, "dp9ik")!=0))
continue;
dom = _strfindattr(a, "dom");
if(dom == nil){
@@ -157,17 +157,17 @@
_freeattr(a);
continue;
}
- print("p9sk1 key: %A\n", a);
+ print("key: %A\n", a);
found = 1;
- authdialfutz(dom, user);
+ authdialfutz(dom, user, proto);
_freeattr(a);
}
if(!found)
- print("no p9sk1 keys found in factotum\n");
+ print("no p9sk1/dp9ik keys found in factotum\n");
}
void
-authdialfutz(char *dom, char *user)
+authdialfutz(char *dom, char *user, char *proto)
{
int fd;
char *server;
@@ -177,7 +177,7 @@
if(fd >= 0){
print("\tsuccessfully dialed auth server\n");
close(fd);
- authfutz(dom, user);
+ authfutz(dom, user, proto);
return;
}
print("\tcannot dial auth server: %r\n");
@@ -205,11 +205,44 @@
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
-authfutz(char *dom, char *user)
+authfutz(char *dom, char *user, char *proto)
{
int fd, nobootes, n, m;
- char pw[128], prompt[128], tbuf[2*TICKETLEN];
+ char pw[128], prompt[128], tbuf[2*MAXTICKETLEN];
Authkey key, booteskey;
Ticket t;
Ticketreq tr;
@@ -219,6 +252,7 @@
if(pw[0] == '\0')
return;
passtokey(&key, pw);
+ booteskey = key;
fd = authdial(nil, dom);
if(fd < 0){
@@ -234,6 +268,13 @@
strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
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){
print("\t_asgetticket failed: %r\n");
close(fd);
@@ -252,7 +293,7 @@
return;
}
- convM2T(tbuf+m, n-m, &t, &key);
+ convM2T(tbuf+m, n-m, &t, &booteskey);
if(t.num != AuthTs){
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);
@@ -269,9 +310,24 @@
/* try ticket request using bootes key */
snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
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);
+ return;
+ }
+
+ if((n = _asgetticket(fd, &tr, tbuf, sizeof(tbuf))) < 0){
print("\t_asgetticket failed: %r\n");
+ close(fd);
return;
}
m = convM2T(tbuf, n, &t, &key);
@@ -286,16 +342,7 @@
print("\tauth server is rogue\n");
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);
if(t.num != AuthTs){
print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
@@ -321,7 +368,6 @@
* auth server (assumes running cpu service)
* to test that bootes key is right over there
*/
-
}
void
--- a/sys/src/cmd/auth/factotum/apop.c
+++ b/sys/src/cmd/auth/factotum/apop.c
@@ -20,6 +20,7 @@
int asfd;
int astype;
Key *key;
+ Authkey k;
Ticket t;
Ticketreq tr;
char chal[128];
@@ -214,28 +215,22 @@
s->asfd = -1;
/* send request to authentication server and get challenge */
- /* send request to authentication server and get challenge */
if((dom = _strfindattr(s->key->attr, "dom")) == nil
|| (user = _strfindattr(s->key->attr, "user")) == nil){
werrstr("apop/dochal cannot happen");
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));
safecpy(s->tr.authdom, dom, sizeof s->tr.authdom);
safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
s->tr.type = s->astype;
- alarm(30*1000);
- if(_asrequest(s->asfd, &s->tr) < 0){
- alarm(0);
+
+ s->asfd = _authreq(&s->tr, &s->k);
+ if(s->asfd < 0)
goto err;
- }
+ alarm(30*1000);
n = _asrdresp(s->asfd, s->chal, sizeof s->chal);
alarm(0);
if(n <= 5)
@@ -272,7 +267,7 @@
alarm(0);
goto err;
}
- n = _asgetresp(s->asfd, &s->t, &a, (Authkey*)s->key->priv);
+ n = _asgetresp(s->asfd, &s->t, &a, &s->k);
alarm(0);
if(n < 0){
/* leave connection open so we can try again */
@@ -282,7 +277,7 @@
s->asfd = -1;
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)
disablekey(s->key);
werrstr(Easproto);
@@ -290,8 +285,7 @@
}
s->key->successes++;
if(a.num != AuthAc
- || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
- || a.id != 0){
+ || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0){
werrstr(Easproto);
goto err;
}
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -41,6 +41,7 @@
int astype;
int asfd;
Key *key;
+ Authkey k;
Ticket t;
Ticketreq tr;
char chal[ChapChallen];
@@ -309,19 +310,18 @@
werrstr("chap/dochal cannot happen");
goto err;
}
- s->asfd = _authdial(nil, dom);
- if(s->asfd < 0)
- goto err;
-
+ memmove(&s->k, s->key->priv, sizeof(Authkey));
+
memset(&s->tr, 0, sizeof(s->tr));
safecpy(s->tr.authdom, dom, sizeof(s->tr.authdom));
safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
s->tr.type = s->astype;
- alarm(30*1000);
- if(_asrequest(s->asfd, &s->tr) < 0){
- alarm(0);
+
+ s->asfd = _authreq(&s->tr, &s->k);
+ if(s->asfd < 0)
goto err;
- }
+
+ alarm(30*1000);
n = readn(s->asfd, s->chal, sizeof s->chal);
alarm(0);
if(n != sizeof s->chal)
@@ -347,7 +347,7 @@
alarm(0);
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){
alarm(0);
/* leave connection open so we can try again */
@@ -361,7 +361,7 @@
s->asfd = -1;
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)
disablekey(s->key);
werrstr(Easproto);
@@ -369,8 +369,7 @@
}
s->key->successes++;
if(a.num != AuthAc
- || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
- || a.id != 0){
+ || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0){
werrstr(Easproto);
return -1;
}
--- a/sys/src/cmd/auth/factotum/confirm.c
+++ b/sys/src/cmd/auth/factotum/confirm.c
@@ -16,6 +16,7 @@
{
Req **l;
+ qlock(&confbuf);
for(l=&cusewait; *l; l=&(*l)->aux){
if(*l == r){
*l = r->aux;
@@ -22,10 +23,12 @@
if(r->aux == nil)
cuselast = l;
r->aux = nil;
+ qunlock(&confbuf);
respond(r, "interrupted");
return;
}
}
+ qunlock(&confbuf);
logbufflush(&confbuf, r);
}
@@ -43,7 +46,7 @@
}
int
-confirmwrite(char *s)
+confirmwrite(Srv *srv, char *s)
{
char *t, *ans;
int allow, tagoff;
@@ -54,15 +57,18 @@
a = _parseattr(s);
if(a == nil){
+ _freeattr(a);
werrstr("empty write");
return -1;
}
if((t = _strfindattr(a, "tag")) == nil){
+ _freeattr(a);
werrstr("no tag");
return -1;
}
tag = strtoul(t, 0, 0);
if((ans = _strfindattr(a, "answer")) == nil){
+ _freeattr(a);
werrstr("no answer");
return -1;
}
@@ -71,14 +77,18 @@
else if(strcmp(ans, "no") == 0)
allow = 0;
else{
+ _freeattr(a);
werrstr("bad answer");
return -1;
}
- r = nil;
+ _freeattr(a);
+ srvrelease(srv);
+ qlock(&confbuf);
+ fss = nil;
tagoff = -1;
- for(l=&cusewait; *l; l=&(*l)->aux){
- r = *l;
- if(hastag(r->fid->aux, tag, &tagoff)){
+ for(l=&cusewait; (r = *l) != nil; l=&(*l)->aux){
+ fss = r->fid->aux;
+ if(hastag(fss, tag, &tagoff)){
*l = r->aux;
if(r->aux == nil)
cuselast = l;
@@ -86,13 +96,17 @@
break;
}
}
+ qunlock(&confbuf);
if(r == nil || tagoff == -1){
+ srvacquire(srv);
werrstr("tag not found");
return -1;
}
- fss = r->fid->aux;
+ qlock(fss);
fss->conf[tagoff].canuse = allow;
rpcread(r);
+ qunlock(fss);
+ srvacquire(srv);
return 0;
}
@@ -118,9 +132,11 @@
respond(r, "no confirmations to wait for (bug)");
return;
}
- *cuselast = r;
+ qlock(&confbuf);
r->aux = nil;
+ *cuselast = r;
cuselast = &r->aux;
+ qunlock(&confbuf);
}
/* Yes, I am unhappy that the code below is a copy of the code above. */
@@ -140,6 +156,7 @@
{
Req **l;
+ qlock(&needkeybuf);
for(l=&needwait; *l; l=&(*l)->aux){
if(*l == r){
*l = r->aux;
@@ -146,32 +163,38 @@
if(r->aux == nil)
needlast = l;
r->aux = nil;
+ qunlock(&needkeybuf);
respond(r, "interrupted");
return;
}
}
+ qunlock(&needkeybuf);
logbufflush(&needkeybuf, r);
}
int
-needkeywrite(char *s)
+needkeywrite(Srv *srv, char *s)
{
char *t;
ulong tag;
Attr *a;
Req *r, **l;
+ Fsstate *fss;
a = _parseattr(s);
if(a == nil){
+ _freeattr(a);
werrstr("empty write");
return -1;
}
if((t = _strfindattr(a, "tag")) == nil){
+ _freeattr(a);
werrstr("no tag");
return -1;
}
tag = strtoul(t, 0, 0);
r = nil;
+ qlock(&needkeybuf);
for(l=&needwait; *l; l=&(*l)->aux){
r = *l;
if(r->tag == tag){
@@ -182,15 +205,23 @@
break;
}
}
+ qunlock(&needkeybuf);
if(r == nil){
+ _freeattr(a);
werrstr("tag not found");
return -1;
}
+ fss = r->fid->aux;
+ srvrelease(srv);
+ qlock(fss);
if(s = _strfindattr(a, "error")){
werrstr("%s", s);
- retrpc(r, RpcErrstr, (Fsstate*)r->fid->aux);
+ retrpc(r, RpcErrstr, fss);
}else
rpcread(r);
+ _freeattr(a);
+ qunlock(fss);
+ srvacquire(srv);
return 0;
}
@@ -204,9 +235,13 @@
snprint(msg, sizeof msg, "needkey tag=%lud %s", r->tag, fss->keyinfo);
logbufappend(&needkeybuf, msg);
- *needlast = r;
+
+ qlock(&needkeybuf);
r->aux = nil;
+ *needlast = r;
needlast = &r->aux;
+ qunlock(&needkeybuf);
+
return 0;
}
--- a/sys/src/cmd/auth/factotum/dat.h
+++ b/sys/src/cmd/auth/factotum/dat.h
@@ -45,6 +45,7 @@
struct Fsstate
{
+ QLock;
char *sysuser; /* user according to system */
/* keylist, protolist */
@@ -76,7 +77,8 @@
struct Key
{
- int ref;
+ Ref;
+
Attr *attr;
Attr *privattr; /* private attributes, like *data */
Proto *proto;
@@ -97,6 +99,8 @@
struct Keyring
{
+ QLock;
+
Key **key;
int nkey;
};
@@ -103,6 +107,8 @@
struct Logbuf
{
+ QLock;
+
Req *wait;
Req **waitlast;
int rp;
@@ -133,11 +139,11 @@
/* confirm.c */
void confirmread(Req*);
void confirmflush(Req*);
-int confirmwrite(char*);
+int confirmwrite(Srv*, char*);
void confirmqueue(Req*, Fsstate*);
void needkeyread(Req*);
void needkeyflush(Req*);
-int needkeywrite(char*);
+int needkeywrite(Srv*, char*);
int needkeyqueue(Req*, Fsstate*);
/* fs.c */
@@ -162,12 +168,7 @@
void logflush(Req*);
void logbufflush(Logbuf*, Req*);
void logbufread(Logbuf*, Req*);
-void logbufproc(Logbuf*);
void logbufappend(Logbuf*, char*);
-void needkeyread(Req*);
-void needkeyflush(Req*);
-int needkeywrite(char*);
-int needkeyqueue(Req*, Fsstate*);
/* rpc.c */
int ctlwrite(char*, int);
@@ -185,7 +186,8 @@
#pragma varargck argpos findkey 3
#pragma varargck argpos setattr 2
-int _authdial(char*, char*);
+int _authdial(char*);
+int _authreq(Ticketreq *, Authkey *);
void askuser(char*);
int attrnamefmt(Fmt *fmt);
int canusekey(Fsstate*, Key*);
@@ -199,7 +201,7 @@
int findkey(Key**, Keyinfo*, char*, ...);
int findp9authkey(Key**, Fsstate*);
Proto *findproto(char*);
-char *getnvramkey(int);
+int getnvramkey(int);
void initcap(void);
int isclient(char*);
int matchattr(Attr*, Attr*, Attr*);
@@ -221,7 +223,7 @@
/* protocols */
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 p9cr, vnc; /* p9cr.c */
extern Proto pass; /* pass.c */
@@ -231,4 +233,3 @@
extern Proto httpdigest; /* httpdigest.c */
extern Proto ecdsa; /* ecdsa.c */
extern Proto wpapsk; /* wpapsk.c */
-
--- a/sys/src/cmd/auth/factotum/fs.c
+++ b/sys/src/cmd/auth/factotum/fs.c
@@ -36,7 +36,7 @@
&p9any,
&p9cr,
&p9sk1,
- &p9sk2,
+ &dp9ik,
&pass,
/* &srs, */
&rsa,
@@ -148,15 +148,8 @@
}
if(sflag){
- s = getnvramkey(kflag ? NVwrite : NVwriteonerr);
- if(s == nil)
+ if(getnvramkey(kflag ? NVwrite : NVwriteonerr) < 0)
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)
promptforhostowner();
owner = getuser();
@@ -418,9 +411,11 @@
fss = fid->aux;
if(fss == nil)
return;
+ qlock(fss);
if(fss->ps)
(*fss->proto->close)(fss);
_freeattr(fss->attr);
+ qunlock(fss);
free(fss);
}
@@ -452,14 +447,14 @@
int wb;
Keyinfo ki;
Key *k;
- static char zero[Nearend];
k = nil;
mkkeyinfo(&ki, fss, nil);
ki.attr = nil;
+ ki.noconf = 1;
ki.skip = i;
ki.usedisabled = 1;
- if(findkey(&k, &ki, "") != RpcOk)
+ if(findkey(&k, &ki, nil) != RpcOk)
return 0;
memset(a + n - Nearend, 0, Nearend);
@@ -489,6 +484,24 @@
}
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
fsread(Req *r)
{
Fsstate *s;
@@ -507,7 +520,7 @@
respond(r, nil);
break;
case Qrpc:
- rpcread(r);
+ fsrpcio(r);
break;
case Qneedkey:
needkeyread(r);
@@ -540,7 +553,7 @@
respond(r, "bug in fswrite");
break;
case Qrpc:
- rpcwrite(r);
+ fsrpcio(r);
break;
case Qneedkey:
case Qconfirm:
@@ -552,10 +565,10 @@
default:
abort();
case Qneedkey:
- ret = needkeywrite(s);
+ ret = needkeywrite(r->srv, s);
break;
case Qconfirm:
- ret = confirmwrite(s);
+ ret = confirmwrite(r->srv, s);
break;
case Qctl:
ret = ctlwrite(s, 0);
--- a/sys/src/cmd/auth/factotum/log.c
+++ b/sys/src/cmd/auth/factotum/log.c
@@ -1,6 +1,6 @@
#include "dat.h"
-void
+static void
logbufproc(Logbuf *lb)
{
char *s;
@@ -43,6 +43,7 @@
void
logbufread(Logbuf *lb, Req *r)
{
+ qlock(lb);
if(lb->waitlast == nil)
lb->waitlast = &lb->wait;
*(lb->waitlast) = r;
@@ -49,6 +50,7 @@
lb->waitlast = &r->aux;
r->aux = nil;
logbufproc(lb);
+ qunlock(lb);
}
void
@@ -56,6 +58,7 @@
{
Req **l;
+ qlock(lb);
for(l=&lb->wait; *l; l=&(*l)->aux){
if(*l == r){
*l = r->aux;
@@ -66,6 +69,7 @@
break;
}
}
+ qunlock(lb);
}
void
@@ -74,6 +78,7 @@
if(debug)
fprint(2, "%s\n", buf);
+ qlock(lb);
if(lb->msg[lb->wp])
free(lb->msg[lb->wp]);
lb->msg[lb->wp] = estrdup9p(buf);
@@ -80,6 +85,7 @@
if(++lb->wp == nelem(lb->msg))
lb->wp = 0;
logbufproc(lb);
+ qunlock(lb);
}
Logbuf logbuf;
--- a/sys/src/cmd/auth/factotum/p9any.c
+++ b/sys/src/cmd/auth/factotum/p9any.c
@@ -13,7 +13,8 @@
#include "dat.h"
static Proto *negotiable[] = {
- &p9sk1,
+ &p9sk1, /* has to be first because of drawterm bug */
+ &dp9ik,
};
struct State
@@ -98,6 +99,7 @@
fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name);
fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom"));
s->subfss.attr = fss->attr;
+ s->subfss.proto = s->subproto;
s->subfss.phase = Notstarted;
s->subfss.sysuser = fss->sysuser;
s->subfss.seqnum = fss->seqnum;
@@ -229,8 +231,8 @@
return p+1;
}
-static Proto*
-findneg(char *name)
+static int
+findprotox(char *name)
{
int i, len;
char *p;
@@ -239,14 +241,28 @@
len = p-name;
else
len = strlen(name);
-
for(i=0; i<nelem(negotiable); i++)
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;
}
static int
+protopref(void *a, void *b)
+{
+ return findprotox(*(char**)b) - findprotox(*(char**)a);
+}
+
+static int
p9anywrite(Fsstate *fss, void *va, uint n)
{
char *a, *dom, *user, *token[20];
@@ -274,7 +290,11 @@
free(a);
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
@@ -285,7 +305,7 @@
k = nil;
p = nil;
dom = nil;
- for(i=(s->version==1?0:1); i<m; i++){
+ for(i=0; i<m; i++){
p = findneg(token[i]);
if(p == nil)
continue;
--- a/sys/src/cmd/auth/factotum/p9cr.c
+++ b/sys/src/cmd/auth/factotum/p9cr.c
@@ -24,6 +24,7 @@
Key *key;
int astype;
int asfd;
+ Authkey k;
Ticket t;
Ticketreq tr;
char chal[Maxchal];
@@ -165,18 +166,14 @@
static int
p9response(Fsstate *fss, State *s)
{
- Authkey key;
+ Authkey *akey;
uchar buf[8];
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);
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");
chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal);
@@ -287,7 +284,7 @@
return failure(fss, Easproto);
}
/* 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);
if(ret < 0)
@@ -295,7 +292,7 @@
/* check ticket */
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)
disablekey(s->key);
return failure(fss, Easproto);
@@ -302,8 +299,7 @@
}
s->key->successes++;
if(a.num != AuthAc
- || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
- || a.id != 0)
+ || tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0)
return failure(fss, Easproto);
fss->haveai = 1;
@@ -321,19 +317,16 @@
{
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.authdom, _strfindattr(s->key->attr, "dom"), sizeof(s->tr.authdom));
s->tr.type = s->astype;
- /* get challenge from auth server */
- s->asfd = _authdial(nil, _strfindattr(s->key->attr, "dom"));
+ s->asfd = _authreq(&s->tr, &s->k);
if(s->asfd < 0)
return failure(fss, Easproto);
alarm(30*1000);
- if(_asrequest(s->asfd, &s->tr) < 0){
- alarm(0);
- return failure(fss, Easproto);
- }
n = _asrdresp(s->asfd, s->chal, s->challen);
alarm(0);
if(n <= 0){
--- a/sys/src/cmd/auth/factotum/p9sk1.c
+++ b/sys/src/cmd/auth/factotum/p9sk1.c
@@ -1,18 +1,24 @@
/*
- * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
- * p9sk2 is an incomplete flawed variant of p9sk1.
+ * p9sk1, dp9ik - Plan 9 secret (private) key authentication.
+ * dp9ik uses AuthPAK diffie hellman key exchange with the
+ * auth server to protect the password derived key from offline
+ * dictionary attacks.
*
* Client protocol:
- * write challenge[challen] (p9sk1 only)
- * read tickreq[tickreqlen]
- * write ticket[ticketlen]
- * read authenticator[authentlen]
+ * write challenge[challen]
+ * read pakreq[ticketreqlen + pakylen] (dp9ik only)
+ * write paky[pakylen]
+ * read tickreq[tickreqlen] (p9sk1 only)
+ * write ticket + authenticator
+ * read authenticator
*
* Server protocol:
- * read challenge[challen] (p9sk1 only)
- * write tickreq[tickreqlen]
- * read ticket[ticketlen]
- * write authenticator[authentlen]
+ * read challenge[challen]
+ * write pakreq[ticketreqlen + pakylen] (dp9ik only)
+ * read paky[pakylen]
+ * write tickreq[tickreqlen] (p9sk1 only)
+ * read ticket + authenticator
+ * write authenticator
*/
#include "dat.h"
@@ -19,12 +25,14 @@
struct State
{
- int vers;
Key *key;
Ticket t;
Ticketreq tr;
+ Authkey k;
+ PAKpriv p;
char cchal[CHALLEN];
- char tbuf[TICKETLEN+AUTHENTLEN];
+ uchar y[PAKYLEN], rand[2*NONCELEN];
+ char tbuf[MAXTICKETLEN + MAXAUTHENTLEN];
int tbuflen;
uchar *secret;
int speakfor;
@@ -34,16 +42,20 @@
{
/* client phases */
CHaveChal,
- CNeedTreq,
+ CNeedPAKreq, /* dp9ik only */
+ CHavePAKy,
+ CNeedTreq, /* p9sk1 only */
CHaveTicket,
CNeedAuth,
/* server phases */
SNeedChal,
- SHaveTreq,
+ SHavePAKreq, /* dp9ik only */
+ SNeedPAKy,
+ SHaveTreq, /* p9sk1 only */
SNeedTicket,
SHaveAuth,
-
+
Maxphase,
};
@@ -50,17 +62,21 @@
static char *phasenames[Maxphase] =
{
[CHaveChal] "CHaveChal",
+[CNeedPAKreq] "CNeedPAKreq",
+[CHavePAKy] "CHavePAKy",
[CNeedTreq] "CNeedTreq",
[CHaveTicket] "CHaveTicket",
[CNeedAuth] "CNeedAuth",
[SNeedChal] "SNeedChal",
+[SHavePAKreq] "SHavePAKreq",
+[SNeedPAKy] "SNeedPAKy",
[SHaveTreq] "SHaveTreq",
[SNeedTicket] "SNeedTicket",
[SHaveAuth] "SHaveAuth",
};
-static int gettickets(State*, Ticketreq *, char*, int);
+static int gettickets(State*, Ticketreq*, uchar*, char*, int);
static int
p9skinit(Proto *p, Fsstate *fss)
@@ -78,25 +94,13 @@
fss = fss;
fss->phasename = phasenames;
fss->maxphase = Maxphase;
- if(p == &p9sk1)
- s->vers = 1;
- else if(p == &p9sk2)
- s->vers = 2;
- else
- abort();
+ fss->proto = p;
if(iscli){
- switch(s->vers){
- case 1:
- fss->phase = CHaveChal;
- genrandom((uchar*)s->cchal, CHALLEN);
- break;
- case 2:
- fss->phase = CNeedTreq;
- break;
- }
+ fss->phase = CHaveChal;
+ genrandom((uchar*)s->cchal, CHALLEN);
}else{
s->tr.type = AuthTreq;
- attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
+ attr = setattr(_copyattr(fss->attr), "proto=%q", p->name);
mkkeyinfo(&ki, fss, attr);
ki.user = nil;
ret = findkey(&k, &ki, "user? dom?");
@@ -108,16 +112,9 @@
safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid));
safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom));
s->key = k;
+ memmove(&s->k, k->priv, sizeof(Authkey));
genrandom((uchar*)s->tr.chal, sizeof s->tr.chal);
- switch(s->vers){
- case 1:
- fss->phase = SNeedChal;
- break;
- case 2:
- fss->phase = SHaveTreq;
- memmove(s->cchal, s->tr.chal, CHALLEN);
- break;
- }
+ fss->phase = SNeedChal;
}
s->tbuflen = 0;
s->secret = nil;
@@ -126,6 +123,39 @@
}
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
p9skread(Fsstate *fss, void *a, uint *n)
{
int m;
@@ -142,13 +172,37 @@
return toosmall(fss, m);
*n = m;
memmove(a, s->cchal, m);
- fss->phase = CNeedTreq;
+ if(fss->proto == &dp9ik)
+ fss->phase = CNeedPAKreq;
+ else
+ fss->phase = CNeedTreq;
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:
m = TICKREQLEN;
if(*n < m)
return toosmall(fss, m);
+ s->tr.type = AuthTreq;
*n = convTR2M(&s->tr, a, *n);
fss->phase = SNeedTicket;
return RpcOk;
@@ -168,15 +222,7 @@
return toosmall(fss, m);
*n = m;
memmove(a, s->tbuf, m);
- fss->ai.cuid = s->t.cuid;
- 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;
+ return establish(fss);
}
}
@@ -184,12 +230,12 @@
p9skwrite(Fsstate *fss, void *a, uint n)
{
int m, ret, sret;
- char tbuf[2*TICKETLEN], *user;
+ char tbuf[2*PAKYLEN+2*MAXTICKETLEN], *user;
Attr *attr;
- Authenticator auth;
State *s;
Key *srvkey;
Keyinfo ki;
+ Authenticator auth;
s = fss->ps;
switch(fss->phase){
@@ -201,24 +247,32 @@
if(n < m)
return toosmall(fss, m);
memmove(s->cchal, a, m);
- fss->phase = SHaveTreq;
+ if(fss->proto == &dp9ik)
+ fss->phase = SHavePAKreq;
+ else
+ fss->phase = SHaveTreq;
return RpcOk;
+ case CNeedPAKreq:
+ m = TICKREQLEN+PAKYLEN;
+ if(n < m)
+ return toosmall(fss, m);
case CNeedTreq:
+ m = TICKREQLEN;
+ if(n < m)
+ return toosmall(fss, m);
+
m = convM2TR(a, n, &s->tr);
- if(m <= 0)
- return toosmall(fss, -m);
+ if(m <= 0 || s->tr.type != (fss->phase==CNeedPAKreq ? AuthPAK : AuthTreq))
+ return failure(fss, Easproto);
- /* remember server's chal */
- if(s->vers == 2)
- memmove(s->cchal, s->tr.chal, CHALLEN);
-
if(s->key != nil)
closekey(s->key);
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");
+
/*
* 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.
@@ -241,7 +295,7 @@
attr = setattr(attr, "user=%q", user);
mkkeyinfo(&ki, fss, attr);
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)
closekey(srvkey);
else if(sret == RpcOk){
@@ -256,7 +310,6 @@
}
/* fill in the rest of the request */
- s->tr.type = AuthTreq;
safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid);
if(s->speakfor)
safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid);
@@ -263,20 +316,26 @@
else
safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
- /* get tickets, from auth server or invent if we can */
- ret = gettickets(s, &s->tr, tbuf, sizeof(tbuf));
- if(ret < 0){
+ /* get tickets from authserver or invent if we can */
+ if(fss->phase == CNeedPAKreq)
+ 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);
return failure(fss, nil);
}
-
- m = convM2T(tbuf, ret, &s->t, (Authkey*)s->key->priv);
+ m = convM2T(tbuf, ret, &s->t, &s->k);
+ if(m <= 0 || (fss->proto == &dp9ik && s->t.form == 0)){
+ _freeattr(attr);
+ return failure(fss, Easproto);
+ }
if(s->t.num != AuthTc){
if(s->key->successes == 0 && !s->speakfor)
disablekey(s->key);
if(askforkeys && !s->speakfor){
snprint(fss->keyinfo, sizeof fss->keyinfo,
- "%A %s", attr, p9sk1.keyprompt);
+ "%A %s", attr, fss->proto->keyprompt);
_freeattr(attr);
return RpcNeedkey;
}else{
@@ -288,32 +347,44 @@
_freeattr(attr);
ret -= m;
memmove(s->tbuf, tbuf+m, ret);
-
+ genrandom(s->rand, NONCELEN);
auth.num = AuthAc;
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);
s->tbuflen = ret;
- fss->phase = CHaveTicket;
+ if(fss->phase == CNeedPAKreq)
+ fss->phase = CHavePAKy;
+ else
+ fss->phase = CHaveTicket;
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:
- m = convM2T(a, n, &s->t, (Authkey*)s->key->priv);
- if(m <= 0)
- return toosmall(fss, -m);
+ m = convM2T(a, n, &s->t, &s->k);
+ if(m <= 0 || convM2A((char*)a+m, n-m, &auth, &s->t) <= 0)
+ return toosmall(fss, MAXTICKETLEN + MAXAUTHENTLEN);
+ if(fss->proto == &dp9ik && s->t.form == 0)
+ return failure(fss, Easproto);
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);
- ret = convM2A((char*)a+m, n-m, &auth, &s->t);
- if(ret <= 0)
- return toosmall(fss, -ret + m);
if(auth.num != AuthAc
- || memcmp(auth.chal, s->tr.chal, CHALLEN) != 0
- || auth.id != 0)
+ || tsmemcmp(auth.chal, s->tr.chal, CHALLEN) != 0)
return failure(fss, Easproto);
+ memmove(s->rand, auth.rand, NONCELEN);
+ genrandom(s->rand + NONCELEN, NONCELEN);
auth.num = AuthAs;
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);
fss->phase = SHaveAuth;
return RpcOk;
@@ -323,18 +394,10 @@
if(m <= 0)
return toosmall(fss, -m);
if(auth.num != AuthAs
- || memcmp(auth.chal, s->cchal, CHALLEN) != 0
- || auth.id != 0)
+ || tsmemcmp(auth.chal, s->cchal, CHALLEN) != 0)
return failure(fss, Easproto);
- fss->ai.cuid = s->t.cuid;
- 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;
+ memmove(s->rand+NONCELEN, auth.rand, NONCELEN);
+ return establish(fss);
}
}
@@ -352,6 +415,7 @@
closekey(s->key);
s->key = nil;
}
+ memset(s, 0, sizeof(State));
free(s);
}
@@ -386,14 +450,27 @@
p9skaddkey(Key *k, int before)
{
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));
if(s = _strfindattr(k->privattr, "!hex")){
- if(hexparse(s, (uchar*)akey->des, DESKEYLEN) < 0){
- free(akey);
- werrstr("malformed key data");
- return -1;
+ 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){
+ free(akey);
+ werrstr("malformed key data");
+ return -1;
+ }
}
}else if(s = _strfindattr(k->privattr, "!password")){
passtokey(akey, s);
@@ -402,6 +479,10 @@
free(akey);
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;
return replacekey(k, before);
}
@@ -409,32 +490,13 @@
static void
p9skclosekey(Key *k)
{
+ memset(k->priv, 0, sizeof(Authkey));
free(k->priv);
}
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;
Ticket t;
int ret;
@@ -446,31 +508,86 @@
return -1;
*/
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);
strcpy(t.cuid, tr->uid);
strcpy(t.suid, tr->uid);
- genrandom((uchar*)t.key, DESKEYLEN);
+ genrandom((uchar*)t.key, sizeof(t.key));
t.num = AuthTc;
- ret = convT2M(&t, tbuf, tbuflen, (Authkey*)s->key->priv);
+ ret += convT2M(&t, tbuf+ret, tbuflen-ret, &s->k);
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;
}
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;
- ret = getastickets(s, tr, tbuf, tbuflen);
- if(ret >= 0)
+ if(tr->authdom[0] == 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 mkserverticket(s, tbuf, tbuflen);
+ return mkservertickets(s, y, tbuf, tbuflen);
}
Proto p9sk1 = {
.name= "p9sk1",
-.init= p9skinit,
+.init= p9skinit,
.write= p9skwrite,
.read= p9skread,
.close= p9skclose,
@@ -479,11 +596,13 @@
.keyprompt= "user? !password?"
};
-Proto p9sk2 = {
-.name= "p9sk2",
-.init= p9skinit,
+Proto dp9ik = {
+.name= "dp9ik",
+.init= p9skinit,
.write= p9skwrite,
.read= p9skread,
.close= p9skclose,
+.addkey= p9skaddkey,
+.closekey= p9skclosekey,
+.keyprompt= "user? !password?"
};
-
--- a/sys/src/cmd/auth/factotum/rpc.c
+++ b/sys/src/cmd/auth/factotum/rpc.c
@@ -429,15 +429,20 @@
return -1;
}
}
- for(i=0; i<ring->nkey; ){
- if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){
+ Again:
+ qlock(ring);
+ for(i=0; i<ring->nkey; i++){
+ k = ring->key[i];
+ if(matchattr(attr, k->attr, k->privattr)){
nmatch++;
- closekey(ring->key[i]);
ring->nkey--;
memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0]));
- }else
- i++;
+ qunlock(ring);
+ closekey(k);
+ goto Again;
+ }
}
+ qunlock(ring);
_freeattr(attr);
if(nmatch == 0){
werrstr("found no keys to delete");
--- a/sys/src/cmd/auth/factotum/util.c
+++ b/sys/src/cmd/auth/factotum/util.c
@@ -1,6 +1,7 @@
#include "dat.h"
static char secstore[100]; /* server name */
+static uchar zeros[16];
/* bind in the default network and cs */
static int
@@ -72,14 +73,13 @@
}
int
-_authdial(char *net, char *authdom)
+_authdial(char *authdom)
{
- int i, fd, vanilla;
+ int i, fd;
alarm(30*1000);
- vanilla = net==nil || strcmp(net, "/net")==0;
- if(!vanilla || bindnetcs()>=0)
- fd = authdial(net, authdom);
+ if(bindnetcs()>=0)
+ fd = authdial(nil, authdom);
else {
/*
* If we failed to mount /srv/cs, assume that
@@ -106,6 +106,31 @@
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
*/
@@ -200,8 +225,8 @@
return fss->conf[i].canuse;
if(fss->nconf%16 == 0)
fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
+ incref(k);
fss->conf[fss->nconf].key = k;
- k->ref++;
fss->conf[fss->nconf].canuse = -1;
fss->conf[fss->nconf].tag = conftaggen++;
fss->nconf++;
@@ -216,7 +241,7 @@
{
if(k == nil)
return;
- if(--k->ref != 0)
+ if(decref(k))
return;
if(k->proto && k->proto->closekey)
(*k->proto->closekey)(k);
@@ -377,6 +402,7 @@
return failure(ki->fss, nil);
}
+ qlock(ring);
nmatch = 0;
for(i=0; i<ring->nkey; i++){
k = ring->key[i];
@@ -391,6 +417,7 @@
if(!ki->noconf){
switch(canusekey(ki->fss, k)){
case -1:
+ qunlock(ring);
_freeattr(attr1);
return RpcConfirm;
case 0:
@@ -402,11 +429,13 @@
_freeattr(attr1);
_freeattr(attr2);
_freeattr(attr3);
- k->ref++;
+ incref(k);
*ret = k;
+ qunlock(ring);
return RpcOk;
}
}
+ qunlock(ring);
flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
werrstr("no key matches %A %A", attr0, attr1);
_freeattr(attr2);
@@ -446,6 +475,7 @@
{
char *dom;
Keyinfo ki;
+ int rv;
/*
* We don't use fss->attr here because we don't
@@ -454,10 +484,18 @@
mkkeyinfo(&ki, fss, nil);
ki.attr = nil;
ki.user = nil;
- if(dom = _strfindattr(fss->attr, "dom"))
- return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
+ dom = _strfindattr(fss->attr, "dom");
+ if(dom != nil)
+ rv = findkey(k, &ki, "proto=dp9ik dom=%q role=server user?", dom);
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*
@@ -471,12 +509,11 @@
return nil;
}
-char*
+int
getnvramkey(int flag)
{
Nvrsafe safe;
char *s;
- int i;
memset(&safe, 0, sizeof safe);
/*
@@ -484,24 +521,30 @@
* but safe still holds good data.
*/
if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
- return nil;
+ return -1;
- /*
- * 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=______",
- safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
+ if(tsmemcmp(safe.machkey, zeros, DESKEYLEN) != 0){
+ s = smprint("key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
+ 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);
memset(&safe, 0, sizeof safe);
- return s;
+ return 0;
}
int
@@ -781,18 +824,19 @@
int i;
Key *k;
+ qlock(ring);
+ incref(kn);
for(i=0; i<ring->nkey; i++){
k = ring->key[i];
if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
- closekey(k);
- kn->ref++;
ring->key[i] = kn;
+ qunlock(ring);
+ closekey(k);
return 0;
}
}
if(ring->nkey%16 == 0)
ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
- kn->ref++;
if(before){
memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
ring->key[0] = kn;
@@ -799,6 +843,7 @@
ring->nkey++;
}else
ring->key[ring->nkey++] = kn;
+ qunlock(ring);
return 0;
}
--- a/sys/src/cmd/auth/keyfs.c
+++ b/sys/src/cmd/auth/keyfs.c
@@ -25,6 +25,7 @@
Quser,
Qkey,
Qaeskey,
+ Qpakhash,
Qsecret,
Qlog,
Qstatus,
@@ -54,8 +55,7 @@
struct User {
char *name;
- char key[DESKEYLEN];
- uchar aeskey[AESKEYLEN];
+ Authkey key;
char secret[SECRETLEN];
ulong expire; /* 0 == never */
uchar status;
@@ -73,6 +73,7 @@
[Quser] ".",
[Qkey] "key",
[Qaeskey] "aeskey",
+ [Qpakhash] "pakhash",
[Qsecret] "secret",
[Qlog] "log",
[Qexpire] "expire",
@@ -180,6 +181,7 @@
if(pipe(p) < 0)
error("can't make pipe: %r");
+ private();
if(usepass)
getpass(&authkey, nil, 0, 0);
else {
@@ -374,7 +376,7 @@
mode = rhdr.mode;
if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
return "user already exists";
- if(f->qtype == Qaeskey && !keydbaes)
+ if((f->qtype == Qaeskey || f->qtype == Qpakhash) && !keydbaes)
return "keyfile not in aes format";
thdr.qid = mkqid(f->user, f->qtype);
thdr.iounit = messagesize - IOHDRSZ;
@@ -458,6 +460,7 @@
return 0;
case Qkey:
case Qaeskey:
+ case Qpakhash:
case Qsecret:
if(f->user->status != Sok)
return "user disabled";
@@ -468,13 +471,17 @@
m = 0;
switch(f->qtype){
case Qkey:
- data = f->user->key;
+ data = (char*)f->user->key.des;
m = DESKEYLEN;
break;
case Qaeskey:
- data = (char*)f->user->aeskey;
+ data = (char*)f->user->key.aes;
m = AESKEYLEN;
break;
+ case Qpakhash:
+ data = (char*)f->user->key.pakhash;
+ m = PAKHASHLEN;
+ break;
case Qsecret:
data = f->user->secret;
Readstr:
@@ -531,14 +538,15 @@
case Qkey:
if(n != DESKEYLEN)
return "garbled write data";
- memmove(f->user->key, data, DESKEYLEN);
- thdr.count = DESKEYLEN;
+ memmove(f->user->key.des, data, n);
+ thdr.count = n;
break;
case Qaeskey:
if(n != AESKEYLEN)
return "garbled write data";
- memmove(f->user->aeskey, data, AESKEYLEN);
- thdr.count = AESKEYLEN;
+ memmove(f->user->key.aes, data, n);
+ authpak_hash(&f->user->key, f->user->name);
+ thdr.count = n;
break;
case Qsecret:
if(n >= SECRETLEN)
@@ -728,7 +736,7 @@
for(u = users[i]; u != nil; u = u->link){
strncpy((char*)p, u->name, Namelen);
p += Namelen;
- memmove(p, u->key, DESKEYLEN);
+ memmove(p, u->key.des, DESKEYLEN);
p += DESKEYLEN;
*p++ = u->status;
*p++ = u->warnings;
@@ -740,7 +748,7 @@
memmove(p, u->secret, SECRETLEN);
p += SECRETLEN;
if(keydbaes){
- memmove(p, u->aeskey, AESKEYLEN);
+ memmove(p, u->key.aes, AESKEYLEN);
p += AESKEYLEN;
}
}
@@ -773,6 +781,8 @@
free(buf);
close(fd);
+
+ newkeys();
}
int
@@ -897,7 +907,7 @@
u = finduser((char*)ep);
if(u == nil)
u = installuser((char*)ep);
- memmove(u->key, ep + Namelen, DESKEYLEN);
+ memmove(u->key.des, ep + Namelen, DESKEYLEN);
p = ep + Namelen + DESKEYLEN;
u->status = *p++;
u->warnings = *p++;
@@ -908,8 +918,10 @@
memmove(u->secret, p, SECRETLEN);
u->secret[SECRETLEN-1] = 0;
p += SECRETLEN;
- if(keydbaes)
- memmove(u->aeskey, p, AESKEYLEN);
+ if(keydbaes){
+ memmove(u->key.aes, p, AESKEYLEN);
+ authpak_hash(&u->key, u->name);
+ }
nu++;
}
free(buf);
--- a/sys/src/cmd/auth/lib/mkfile
+++ b/sys/src/cmd/auth/lib/mkfile
@@ -6,6 +6,7 @@
keyfmt.$O\
netcheck.$O\
okpasswd.$O\
+ private.$O\
readwrite.$O\
readarg.$O\
readln.$O\
--- a/sys/src/cmd/auth/lib/readwrite.c
+++ b/sys/src/cmd/auth/lib/readwrite.c
@@ -66,8 +66,14 @@
int ret;
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;
}
--- a/sys/src/cmd/auth/netkey.c
+++ b/sys/src/cmd/auth/netkey.c
@@ -15,8 +15,7 @@
void
main(int argc, char *argv[])
{
- Authkey key;
- char buf[32], pass[32];
+ char buf[32], pass[32], key[DESKEYLEN];
char *s;
int n;
@@ -34,7 +33,7 @@
}
readln("Password: ", pass, sizeof pass, 1);
- passtokey(&key, pass);
+ passtodeskey(key, pass);
for(;;){
print("challenge: ");
@@ -44,7 +43,7 @@
buf[n] = '\0';
n = strtol(buf, 0, 10);
sprint(buf, "%d", n);
- netcrypt(key.des, buf);
+ netcrypt(key, buf);
print("response: %s\n", buf);
}
}
--- a/sys/src/cmd/auth/passwd.c
+++ b/sys/src/cmd/auth/passwd.c
@@ -7,7 +7,7 @@
void
main(int argc, char **argv)
{
- int fd, n;
+ int fd, n, try;
Ticketreq tr;
Ticket t;
Passwordreq pr;
@@ -20,6 +20,8 @@
ARGBEGIN{
}ARGEND
+ private();
+
s = nil;
if(argc > 0){
user = argv[0];
@@ -34,6 +36,10 @@
if(fd < 0)
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
* ticket. If it doesn't work we've got a bad password,
@@ -43,18 +49,31 @@
readln("Plan 9 Password: ", pr.old, sizeof pr.old, 1);
passtokey(&key, pr.old);
- memset(&tr, 0, sizeof(tr));
- strcpy(tr.uid, user);
- tr.type = AuthPass;
-
+ /*
+ * negotiate PAK key. we need to retry in case the AS does
+ * 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 */
if(_asrequest(fd, &tr) < 0)
error("%r");
if(_asgetresp(fd, &t, nil, &key) < 0)
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");
+ }
/* loop trying new passwords */
for(;;){
@@ -62,8 +81,7 @@
*pr.new = 0;
readln("change Plan 9 Password? (y/n) ", buf, sizeof buf, 0);
if(*buf == 'y' || *buf == 'Y'){
- readln("Password(8 to 31 characters): ", pr.new,
- sizeof pr.new, 1);
+ readln("Password: ", pr.new, sizeof pr.new, 1);
readln("Confirm: ", buf, sizeof buf, 1);
if(strcmp(pr.new, buf)){
print("!mismatch\n");
@@ -81,8 +99,7 @@
else
strcpy(pr.secret, pr.new);
} else {
- readln("Secret(0 to 256 characters): ", pr.secret,
- sizeof pr.secret, 1);
+ readln("Secret: ", pr.secret, sizeof pr.secret, 1);
readln("Confirm: ", buf, sizeof buf, 1);
if(strcmp(pr.secret, buf)){
print("!mismatch\n");
--- a/sys/src/libauth/auth_userpasswd.c
+++ b/sys/src/libauth/auth_userpasswd.c
@@ -11,13 +11,13 @@
* this was copied from inet's guard.
*/
static void
-netresp(Authkey *key, long chal, char *answer)
+netresp(char key[DESKEYLEN], long chal, char *answer)
{
uchar buf[8];
memset(buf, 0, sizeof buf);
snprint((char *)buf, sizeof buf, "%lud", chal);
- if(encrypt(key->des, buf, 8) < 0)
+ if(encrypt(key, buf, 8) < 0)
abort();
sprint(answer, "%.8ux", buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]);
}
@@ -25,8 +25,7 @@
AuthInfo*
auth_userpasswd(char *user, char *passwd)
{
- char resp[16];
- Authkey key;
+ char resp[16], key[DESKEYLEN];
AuthInfo *ai;
Chalstate *ch;
@@ -38,9 +37,9 @@
if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil)
return nil;
- passtokey(&key, passwd);
- netresp(&key, atol(ch->chal), resp);
- memset(&key, 0, sizeof(Authkey));
+ passtodeskey(key, passwd);
+ netresp(key, atol(ch->chal), resp);
+ memset(key, 0, sizeof(key));
ch->resp = resp;
ch->nresp = strlen(resp);
--- /dev/null
+++ b/sys/src/libauthsrv/_asgetpakkey.c
@@ -1,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);
+}
--- a/sys/src/libauthsrv/_asgetresp.c
+++ b/sys/src/libauthsrv/_asgetresp.c
@@ -5,28 +5,40 @@
int
_asgetresp(int fd, Ticket *t, Authenticator *a, Authkey *k)
{
- char tbuf[TICKETLEN+AUTHENTLEN];
+ char buf[MAXTICKETLEN+MAXAUTHENTLEN], err[ERRMAX];
int n, m;
- m = TICKETLEN;
memset(t, 0, sizeof(Ticket));
- if(a != nil){
- m += AUTHENTLEN;
+ if(a != nil)
memset(a, 0, sizeof(Authenticator));
- }
- n = _asrdresp(fd, tbuf, m);
- if(n <= 0)
- return -1;
+ strcpy(err, "AS protocol botch");
+ errstr(err, ERRMAX);
- m = convM2T(tbuf, n, t, k);
- if(m <= 0)
+ if(_asrdresp(fd, buf, 0) < 0)
return -1;
- if(a != nil){
- if(convM2A(tbuf+m, n-m, a, t) <= 0)
+ 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;
}
+
+ if(a != nil){
+ 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;
+ }
+ }
+
+ errstr(err, ERRMAX);
return 0;
}
--- a/sys/src/libauthsrv/_asgetticket.c
+++ b/sys/src/libauthsrv/_asgetticket.c
@@ -2,16 +2,36 @@
#include <libc.h>
#include <authsrv.h>
-static char *pbmsg = "AS protocol botch";
-
int
_asgetticket(int fd, Ticketreq *tr, char *tbuf, int tbuflen)
{
- if(_asrequest(fd, tr) < 0){
- werrstr(pbmsg);
+ char err[ERRMAX];
+ 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;
+ }
+ r += n;
+ tbuf += n;
+ tbuflen -= n;
}
- if(tbuflen > 2*TICKETLEN)
- tbuflen = 2*TICKETLEN;
- return _asrdresp(fd, tbuf, tbuflen);
+
+ errstr(err, ERRMAX);
+
+ return r;
}
--- /dev/null
+++ b/sys/src/libauthsrv/authpak.c
@@ -1,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;
+}
--- a/sys/src/libauthsrv/convA2M.c
+++ b/sys/src/libauthsrv/convA2M.c
@@ -2,11 +2,7 @@
#include <libc.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
+extern int form1B2M(char *ap, int n, uchar key[32]);
int
convA2M(Authenticator *f, char *ap, int n, Ticket *t)
@@ -13,15 +9,28 @@
{
uchar *p;
- if(n < AUTHENTLEN)
+ if(n < 1+CHALLEN)
return 0;
p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- LONG(id);
- n = p - (uchar*)ap;
- if(t)
+ *p++ = f->num;
+ memmove(p, f->chal, CHALLEN), p += CHALLEN;
+ 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;
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;
}
--- a/sys/src/libauthsrv/convM2A.c
+++ b/sys/src/libauthsrv/convM2A.c
@@ -2,30 +2,35 @@
#include <libc.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
+extern int form1M2B(char *ap, int n, uchar key[32]);
int
convM2A(char *ap, int n, Authenticator *f, Ticket *t)
{
- uchar *p, buf[AUTHENTLEN];
+ uchar buf[MAXAUTHENTLEN], *p;
+ int m;
memset(f, 0, sizeof(Authenticator));
- if(n < AUTHENTLEN)
- return -AUTHENTLEN;
-
- if(t) {
- memmove(buf, ap, AUTHENTLEN);
- ap = (char*)buf;
- decrypt(t->key, ap, AUTHENTLEN);
+ if(t->form == 0){
+ 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 = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- LONG(id);
- n = p - (uchar*)ap;
- return n;
+ p = buf;
+ f->num = *p++;
+ memmove(f->chal, p, CHALLEN);
+ p += CHALLEN;
+ if(t->form == 1)
+ memmove(f->rand, p, NONCELEN);
+
+ return m;
}
--- a/sys/src/libauthsrv/convM2PR.c
+++ b/sys/src/libauthsrv/convM2PR.c
@@ -2,35 +2,38 @@
#include <libc.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
+extern int form1M2B(char *ap, int n, uchar key[32]);
int
convM2PR(char *ap, int n, Passwordreq *f, Ticket *t)
{
- uchar *p, buf[PASSREQLEN];
+ uchar *p, buf[MAXPASSREQLEN];
+ int m;
memset(f, 0, sizeof(Passwordreq));
- if(n < PASSREQLEN)
- return -PASSREQLEN;
-
- if(t){
- memmove(buf, ap, PASSREQLEN);
- ap = (char*)buf;
- decrypt(t->key, ap, PASSREQLEN);
+ if(t->form == 0){
+ m = 1+2*ANAMELEN+1+SECRETLEN;
+ if(n < m)
+ return -m;
+ memmove(buf, ap, m);
+ decrypt(t->key, buf, m);
+ } 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;
- CHAR(num);
- STRING(old, ANAMELEN);
+ p = buf;
+ f->num = *p++;
+ 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;
- STRING(new, ANAMELEN);
f->new[ANAMELEN-1] = 0;
- CHAR(changesecret);
- STRING(secret, SECRETLEN);
f->secret[SECRETLEN-1] = 0;
- n = p - (uchar*)ap;
- return n;
+
+ return m;
}
--- a/sys/src/libauthsrv/convM2T.c
+++ b/sys/src/libauthsrv/convM2T.c
@@ -2,34 +2,50 @@
#include <libc.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
+extern int form1check(char *ap, int n);
+extern int form1M2B(char *ap, int n, uchar key[32]);
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;
- memset(f, 0, sizeof(Ticket));
- if(n < TICKETLEN)
- return -TICKETLEN;
+ if(f != nil)
+ memset(f, 0, sizeof(Ticket));
- if(key){
- memmove(buf, ap, TICKETLEN);
- ap = (char*)buf;
- decrypt(key->des, ap, TICKETLEN);
+ if(n < 8)
+ return -8;
+
+ 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;
- CHAR(num);
- STRING(chal, CHALLEN);
- STRING(cuid, ANAMELEN);
+ p = buf;
+ f->num = *p++;
+ memmove(f->chal, p, CHALLEN), p += CHALLEN;
+ 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;
- STRING(suid, ANAMELEN);
f->suid[ANAMELEN-1] = 0;
- STRING(key, DESKEYLEN);
- n = p - (uchar*)ap;
- return n;
+
+ return m;
}
--- a/sys/src/libauthsrv/convM2TR.c
+++ b/sys/src/libauthsrv/convM2TR.c
@@ -2,12 +2,6 @@
#include <libc.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
convM2TR(char *ap, int n, Ticketreq *f)
{
@@ -18,16 +12,18 @@
return -TICKREQLEN;
p = (uchar*)ap;
- CHAR(type);
- STRING(authid, ANAMELEN);
+ f->type = *p++;
+ 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;
- STRING(authdom, DOMLEN);
f->authdom[DOMLEN-1] = 0;
- STRING(chal, CHALLEN);
- STRING(hostid, ANAMELEN);
f->hostid[ANAMELEN-1] = 0;
- STRING(uid, ANAMELEN);
f->uid[ANAMELEN-1] = 0;
n = p - (uchar*)ap;
+
return n;
}
--- a/sys/src/libauthsrv/convPR2M.c
+++ b/sys/src/libauthsrv/convPR2M.c
@@ -2,11 +2,7 @@
#include <libc.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
+extern int form1B2M(char *ap, int n, uchar key[32]);
int
convPR2M(Passwordreq *f, char *ap, int n, Ticket *t)
@@ -13,18 +9,26 @@
{
uchar *p;
- if(n < PASSREQLEN)
+ if(n < 1+2*ANAMELEN+1+SECRETLEN)
return 0;
p = (uchar*)ap;
- CHAR(num);
- STRING(old, ANAMELEN);
- STRING(new, ANAMELEN);
- CHAR(changesecret);
- STRING(secret, SECRETLEN);
- n = p - (uchar*)ap;
- if(t)
+ *p++ = f->num;
+ memmove(p, f->old, ANAMELEN), p += ANAMELEN;
+ memmove(p, f->new, ANAMELEN), p += ANAMELEN;
+ *p++ = f->changesecret;
+ memmove(p, f->secret, SECRETLEN), p += SECRETLEN;
+ switch(t->form){
+ case 0:
+ n = p - (uchar*)ap;
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;
}
--- a/sys/src/libauthsrv/convT2M.c
+++ b/sys/src/libauthsrv/convT2M.c
@@ -1,12 +1,9 @@
#include <u.h>
#include <libc.h>
#include <authsrv.h>
+#include <libsec.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
+extern int form1B2M(char *ap, int n, uchar key[32]);
int
convT2M(Ticket *f, char *ap, int n, Authkey *key)
@@ -13,17 +10,30 @@
{
uchar *p;
- if(n < TICKETLEN)
+ if(n < 1+CHALLEN+2*ANAMELEN)
return 0;
p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- STRING(cuid, ANAMELEN);
- STRING(suid, ANAMELEN);
- STRING(key, DESKEYLEN);
- n = p - (uchar*)ap;
- if(key)
+ *p++ = f->num;
+ memmove(p, f->chal, CHALLEN), p += CHALLEN;
+ memmove(p, f->cuid, ANAMELEN), p += ANAMELEN;
+ memmove(p, f->suid, ANAMELEN), p += ANAMELEN;
+ 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;
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;
}
--- a/sys/src/libauthsrv/convTR2M.c
+++ b/sys/src/libauthsrv/convTR2M.c
@@ -2,12 +2,6 @@
#include <libc.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
convTR2M(Ticketreq *f, char *ap, int n)
{
@@ -17,12 +11,13 @@
return 0;
p = (uchar*)ap;
- CHAR(type);
- STRING(authid, 28); /* BUG */
- STRING(authdom, DOMLEN);
- STRING(chal, CHALLEN);
- STRING(hostid, 28); /* BUG */
- STRING(uid, 28); /* BUG */
+ *p++ = f->type;
+ memmove(p, f->authid, ANAMELEN), p += ANAMELEN;
+ memmove(p, f->authdom, DOMLEN), p += DOMLEN;
+ memmove(p, f->chal, CHALLEN), p += CHALLEN;
+ memmove(p, f->hostid, ANAMELEN), p += ANAMELEN;
+ memmove(p, f->uid, ANAMELEN), p += ANAMELEN;
n = p - (uchar*)ap;
+
return n;
}
--- /dev/null
+++ b/sys/src/libauthsrv/decaf.mp
@@ -1,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;
+ }
+ }
+}
--- /dev/null
+++ b/sys/src/libauthsrv/ed448.mp
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/libauthsrv/edwards.mp
@@ -1,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;
+ }
+}
--- /dev/null
+++ b/sys/src/libauthsrv/elligator2.mp
@@ -1,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);
+}
--- /dev/null
+++ b/sys/src/libauthsrv/form1.c
@@ -1,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;
+}
--- a/sys/src/libauthsrv/mkfile
+++ b/sys/src/libauthsrv/mkfile
@@ -2,10 +2,12 @@
LIB=/$objtype/lib/libauthsrv.a
OFILES=\
+ _asgetpakkey.$O\
_asgetticket.$O\
_asgetresp.$O\
_asrequest.$O\
_asrdresp.$O\
+ authpak.$O\
authdial.$O\
convA2M.$O\
convM2A.$O\
@@ -15,17 +17,35 @@
convPR2M.$O\
convT2M.$O\
convTR2M.$O\
+ form1.$O\
nvcsum.$O\
passtokey.$O\
readnvram.$O\
HFILES=\
- /sys/include/authsrv.h\
+ /sys/include/authsrv.h
+MPCFILES=\
+ msqrt.mpc\
+ decaf.mpc\
+ edwards.mpc\
+ elligator2.mpc\
+ spake2ee.mpc\
+ ed448.mpc\
+
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
+ ${MPCFILES:.mpc=%.mp}\
${LIB:/$objtype/%=/386/%}\
+
+CLEANFILES=$MPCFILES
+
</sys/src/cmd/mksyslib
+
+authpak.$O: $MPCFILES
+
+%.mpc: %.mp
+ mpc $stem.mp > $target
--- /dev/null
+++ b/sys/src/libauthsrv/msqrt.mp
@@ -1,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;
+ }
+}
--- a/sys/src/libauthsrv/passtokey.c
+++ b/sys/src/libauthsrv/passtokey.c
@@ -3,8 +3,8 @@
#include <authsrv.h>
#include <libsec.h>
-static void
-passtodeskey(char *key, char *p)
+void
+passtodeskey(char key[DESKEYLEN], char *p)
{
uchar buf[ANAMELEN], *t;
int i, n;
@@ -32,8 +32,8 @@
}
}
-static void
-passtoaeskey(uchar *key, char *p)
+void
+passtoaeskey(uchar key[AESKEYLEN], char *p)
{
static char salt[] = "Plan 9 key derivation";
pbkdf2_x((uchar*)p, strlen(p), (uchar*)salt, sizeof(salt)-1, 9001, key, AESKEYLEN, hmac_sha1, SHA1dlen);
@@ -40,9 +40,9 @@
}
void
-passtokey(Authkey *key, char *p)
+passtokey(Authkey *key, char *pw)
{
memset(key, 0, sizeof(Authkey));
- passtodeskey(key->des, p);
- passtoaeskey(key->aes, p);
+ passtodeskey(key->des, pw);
+ passtoaeskey(key->aes, pw);
}
--- /dev/null
+++ b/sys/src/libauthsrv/spake2ee.mp
@@ -1,0 +1,35 @@
+#
+# this implements a variant of SPAKE2 Elligator edition described in:
+# https://www.mail-archive.com/[email protected]/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);
+ }
+}