auth: release dp9ik implementation and reentrant factotum
This commit is contained in:
parent
e064752dd4
commit
2dae1ed53a
44 changed files with 2034 additions and 732 deletions
|
@ -20,16 +20,27 @@ enum
|
|||
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 @@ enum
|
|||
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 @@ struct Ticket
|
|||
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 @@ struct Passwordreq
|
|||
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 OMSchapreply
|
|||
|
||||
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 convPR2M(Passwordreq*, char*, int, Ticket*);
|
|||
extern int convM2PR(char*, int, Passwordreq*, Ticket*);
|
||||
|
||||
/*
|
||||
* convert ascii password to DES key
|
||||
* convert ascii password to auth key
|
||||
*/
|
||||
extern void passtokey(Authkey*, char*);
|
||||
|
||||
extern void passtodeskey(char key[DESKEYLEN], char *p);
|
||||
extern void passtoaeskey(uchar key[AESKEYLEN], char *p);
|
||||
|
||||
/*
|
||||
* Nvram interface
|
||||
*/
|
||||
|
@ -169,7 +186,7 @@ struct Nvrsafe
|
|||
};
|
||||
|
||||
extern uchar nvcsum(void*, int);
|
||||
extern int readnvram(Nvrsafe*, int);
|
||||
extern int readnvram(Nvrsafe*, int);
|
||||
|
||||
/*
|
||||
* call up auth server
|
||||
|
@ -179,7 +196,23 @@ extern int authdial(char *netroot, char *authdom);
|
|||
/*
|
||||
* 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]);
|
||||
|
|
|
@ -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 @@ The network database
|
|||
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 @@ The password is converted using
|
|||
.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 @@ client's host ID's key
|
|||
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 ID
|
|||
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 @@ The message type constants
|
|||
.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 @@ The protocol to obtain a ticket pair is:
|
|||
.IR CHs ,
|
||||
.IR IDc ,
|
||||
.IR IDr
|
||||
.sp -\n(PDu
|
||||
.TP
|
||||
.IR A \(-> C
|
||||
.IR AuthOK ,
|
||||
|
@ -265,16 +284,254 @@ proving to the client that it also knows
|
|||
.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 @@ The negotiation protocol is:
|
|||
.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 @@ The protocol is:
|
|||
.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,39 +726,34 @@ message is expected, a
|
|||
.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
|
||||
.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 @@ Users not listed are assumed to have the
|
|||
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 @@ in
|
|||
.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 @@ in
|
|||
.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 @@ in
|
|||
.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
|
||||
|
|
|
@ -53,6 +53,7 @@ int netcheck(void*, long, char*);
|
|||
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);
|
||||
|
|
|
@ -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,25 +30,26 @@ enum {
|
|||
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);
|
||||
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 @@ main(int argc, char *argv[])
|
|||
int n;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'd':
|
||||
debug++;
|
||||
case 'N':
|
||||
ticketform = 1;
|
||||
break;
|
||||
}ARGEND
|
||||
|
||||
strcpy(raddr, "unknown");
|
||||
|
@ -59,6 +71,9 @@ main(int argc, char *argv[])
|
|||
|
||||
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 @@ main(int argc, char *argv[])
|
|||
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,44 +219,34 @@ ticketrequest(Ticketreq *tr)
|
|||
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){
|
||||
/* 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,18 +256,15 @@ challengebox(Ticketreq *tr)
|
|||
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))
|
||||
&& (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 @@ challengebox(Ticketreq *tr)
|
|||
/*
|
||||
* 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 @@ changepasswd(Ticketreq *tr)
|
|||
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,56 +340,15 @@ changepasswd(Ticketreq *tr)
|
|||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if(write(1, prbuf, 1) != 1)
|
||||
exits(0);
|
||||
}
|
||||
|
||||
static char*
|
||||
|
@ -371,7 +394,6 @@ apop(Ticketreq *tr, int type)
|
|||
{
|
||||
int challen, i, n, tries;
|
||||
char *secret, *p;
|
||||
Authkey hkey;
|
||||
Ticketreq treq;
|
||||
DigestState *s;
|
||||
char sbuf[SECRETLEN];
|
||||
|
@ -402,7 +424,7 @@ apop(Ticketreq *tr, int type)
|
|||
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 @@ apop(Ticketreq *tr, int type)
|
|||
* 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 @@ apop(Ticketreq *tr, int type)
|
|||
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 @@ apop(Ticketreq *tr, int type)
|
|||
/*
|
||||
* 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 @@ uchar swizzletab[256] = {
|
|||
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,35 +525,33 @@ vnc(Ticketreq *tr)
|
|||
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)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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
|
||||
*/
|
||||
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,18 +561,15 @@ vnc(Ticketreq *tr)
|
|||
/*
|
||||
* 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
|
||||
chap(Ticketreq *tr)
|
||||
{
|
||||
char *secret;
|
||||
Authkey hkey;
|
||||
DigestState *s;
|
||||
char sbuf[SECRETLEN];
|
||||
uchar digest[MD5dlen];
|
||||
|
@ -564,7 +580,8 @@ chap(Ticketreq *tr)
|
|||
* 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 @@ chap(Ticketreq *tr)
|
|||
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 @@ chap(Ticketreq *tr)
|
|||
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,23 +620,9 @@ chap(Ticketreq *tr)
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr);
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -666,7 +671,6 @@ void
|
|||
mschap(Ticketreq *tr)
|
||||
{
|
||||
char *secret;
|
||||
Authkey hkey;
|
||||
char sbuf[SECRETLEN], windom[128];
|
||||
uchar chal[CHALLEN], ntblob[1024];
|
||||
uchar hash[MShashlen];
|
||||
|
@ -681,7 +685,8 @@ mschap(Ticketreq *tr)
|
|||
* 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 @@ mschap(Ticketreq *tr)
|
|||
}
|
||||
|
||||
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,14 +763,14 @@ mschap(Ticketreq *tr)
|
|||
*/
|
||||
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)
|
||||
*/
|
||||
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 @@ mschap(Ticketreq *tr)
|
|||
} 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 @@ mschap(Ticketreq *tr)
|
|||
* 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 @@ mschap(Ticketreq *tr)
|
|||
/*
|
||||
* 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 @@ mschap(Ticketreq *tr)
|
|||
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,10 +1001,35 @@ getraddr(char *dir)
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -1008,35 +1037,35 @@ 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);
|
||||
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
|
||||
|
|
|
@ -43,6 +43,8 @@ main(int argc, char *argv[])
|
|||
usage();
|
||||
file = argv[0];
|
||||
|
||||
private();
|
||||
|
||||
/* get original key */
|
||||
if(usepass){
|
||||
print("enter password file is encoded with\n");
|
||||
|
|
|
@ -116,8 +116,8 @@ readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ debugfactotumkeys(void)
|
|||
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 @@ debugfactotumkeys(void)
|
|||
_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 @@ authdialfutz(char *dom, char *user)
|
|||
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 @@ authdialfutz(char *dom, char *user)
|
|||
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 @@ authfutz(char *dom, char *user)
|
|||
if(pw[0] == '\0')
|
||||
return;
|
||||
passtokey(&key, pw);
|
||||
booteskey = key;
|
||||
|
||||
fd = authdial(nil, dom);
|
||||
if(fd < 0){
|
||||
|
@ -234,6 +268,13 @@ authfutz(char *dom, char *user)
|
|||
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 @@ authfutz(char *dom, char *user)
|
|||
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 @@ authfutz(char *dom, char *user)
|
|||
/* 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 @@ authfutz(char *dom, char *user)
|
|||
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 @@ Nobootes:;
|
|||
* auth server (assumes running cpu service)
|
||||
* to test that bootes key is right over there
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -20,6 +20,7 @@ struct State
|
|||
int asfd;
|
||||
int astype;
|
||||
Key *key;
|
||||
Authkey k;
|
||||
Ticket t;
|
||||
Ticketreq tr;
|
||||
char chal[128];
|
||||
|
@ -213,29 +214,23 @@ dochal(State *s)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
s->asfd = _authdial(nil, dom);
|
||||
|
||||
/* could generate our own challenge on error here */
|
||||
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 = _asrdresp(s->asfd, s->chal, sizeof s->chal);
|
||||
alarm(0);
|
||||
if(n <= 5)
|
||||
|
@ -272,7 +267,7 @@ doreply(State *s, char *user, char *response)
|
|||
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 @@ doreply(State *s, char *user, char *response)
|
|||
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 @@ doreply(State *s, char *user, char *response)
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ struct State
|
|||
int astype;
|
||||
int asfd;
|
||||
Key *key;
|
||||
Authkey k;
|
||||
Ticket t;
|
||||
Ticketreq tr;
|
||||
char chal[ChapChallen];
|
||||
|
@ -309,19 +310,18 @@ dochal(State *s)
|
|||
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 @@ doreply(State *s, uchar *reply, int nreply)
|
|||
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 @@ doreply(State *s, uchar *reply, int nreply)
|
|||
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 @@ doreply(State *s, uchar *reply, int nreply)
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -16,16 +16,19 @@ confirmflush(Req *r)
|
|||
{
|
||||
Req **l;
|
||||
|
||||
qlock(&confbuf);
|
||||
for(l=&cusewait; *l; l=&(*l)->aux){
|
||||
if(*l == r){
|
||||
*l = r->aux;
|
||||
if(r->aux == nil)
|
||||
cuselast = l;
|
||||
r->aux = nil;
|
||||
qunlock(&confbuf);
|
||||
respond(r, "interrupted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
qunlock(&confbuf);
|
||||
logbufflush(&confbuf, r);
|
||||
}
|
||||
|
||||
|
@ -43,7 +46,7 @@ hastag(Fsstate *fss, int tag, int *tagoff)
|
|||
}
|
||||
|
||||
int
|
||||
confirmwrite(char *s)
|
||||
confirmwrite(Srv *srv, char *s)
|
||||
{
|
||||
char *t, *ans;
|
||||
int allow, tagoff;
|
||||
|
@ -54,15 +57,18 @@ confirmwrite(char *s)
|
|||
|
||||
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 @@ confirmwrite(char *s)
|
|||
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 @@ confirmwrite(char *s)
|
|||
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 @@ confirmqueue(Req *r, Fsstate *fss)
|
|||
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,38 +156,45 @@ needkeyflush(Req *r)
|
|||
{
|
||||
Req **l;
|
||||
|
||||
qlock(&needkeybuf);
|
||||
for(l=&needwait; *l; l=&(*l)->aux){
|
||||
if(*l == r){
|
||||
*l = r->aux;
|
||||
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 @@ needkeywrite(char *s)
|
|||
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 @@ needkeyqueue(Req *r, Fsstate *fss)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef struct State State;
|
|||
|
||||
struct Fsstate
|
||||
{
|
||||
QLock;
|
||||
char *sysuser; /* user according to system */
|
||||
|
||||
/* keylist, protolist */
|
||||
|
@ -76,7 +77,8 @@ struct Fsstate
|
|||
|
||||
struct Key
|
||||
{
|
||||
int ref;
|
||||
Ref;
|
||||
|
||||
Attr *attr;
|
||||
Attr *privattr; /* private attributes, like *data */
|
||||
Proto *proto;
|
||||
|
@ -97,12 +99,16 @@ struct Keyinfo /* for findkey */
|
|||
|
||||
struct Keyring
|
||||
{
|
||||
QLock;
|
||||
|
||||
Key **key;
|
||||
int nkey;
|
||||
};
|
||||
|
||||
struct Logbuf
|
||||
{
|
||||
QLock;
|
||||
|
||||
Req *wait;
|
||||
Req **waitlast;
|
||||
int rp;
|
||||
|
@ -133,11 +139,11 @@ extern char Etoolarge[];
|
|||
/* 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 logread(Req*);
|
|||
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 @@ void retrpc(Req*, int, Fsstate*);
|
|||
#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 @@ Keyinfo* mkkeyinfo(Keyinfo*, Fsstate*, Attr*);
|
|||
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 @@ void writehostowner(char*);
|
|||
|
||||
/* 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 wep; /* wep.c */
|
|||
extern Proto httpdigest; /* httpdigest.c */
|
||||
extern Proto ecdsa; /* ecdsa.c */
|
||||
extern Proto wpapsk; /* wpapsk.c */
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ prototab[] =
|
|||
&p9any,
|
||||
&p9cr,
|
||||
&p9sk1,
|
||||
&p9sk2,
|
||||
&dp9ik,
|
||||
&pass,
|
||||
/* &srs, */
|
||||
&rsa,
|
||||
|
@ -148,15 +148,8 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
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 @@ fsdestroyfid(Fid *fid)
|
|||
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 @@ keylist(int i, char *a, uint n, Fsstate *fss)
|
|||
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);
|
||||
|
@ -488,6 +483,24 @@ protolist(int i, char *a, uint n, Fsstate *fss)
|
|||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
fsrpcio(Req *r)
|
||||
{
|
||||
Fsstate *fss;
|
||||
Srv *srv;
|
||||
|
||||
fss = r->fid->aux;
|
||||
srv = r->srv;
|
||||
srvrelease(srv);
|
||||
qlock(fss);
|
||||
if(r->ifcall.type == Tread)
|
||||
rpcread(r);
|
||||
else
|
||||
rpcwrite(r);
|
||||
qunlock(fss);
|
||||
srvacquire(srv);
|
||||
}
|
||||
|
||||
static void
|
||||
fsread(Req *r)
|
||||
{
|
||||
|
@ -507,7 +520,7 @@ fsread(Req *r)
|
|||
respond(r, nil);
|
||||
break;
|
||||
case Qrpc:
|
||||
rpcread(r);
|
||||
fsrpcio(r);
|
||||
break;
|
||||
case Qneedkey:
|
||||
needkeyread(r);
|
||||
|
@ -540,7 +553,7 @@ fswrite(Req *r)
|
|||
respond(r, "bug in fswrite");
|
||||
break;
|
||||
case Qrpc:
|
||||
rpcwrite(r);
|
||||
fsrpcio(r);
|
||||
break;
|
||||
case Qneedkey:
|
||||
case Qconfirm:
|
||||
|
@ -552,10 +565,10 @@ fswrite(Req *r)
|
|||
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);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "dat.h"
|
||||
|
||||
void
|
||||
static void
|
||||
logbufproc(Logbuf *lb)
|
||||
{
|
||||
char *s;
|
||||
|
@ -43,12 +43,14 @@ logbufproc(Logbuf *lb)
|
|||
void
|
||||
logbufread(Logbuf *lb, Req *r)
|
||||
{
|
||||
qlock(lb);
|
||||
if(lb->waitlast == nil)
|
||||
lb->waitlast = &lb->wait;
|
||||
*(lb->waitlast) = r;
|
||||
lb->waitlast = &r->aux;
|
||||
r->aux = nil;
|
||||
logbufproc(lb);
|
||||
qunlock(lb);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -56,6 +58,7 @@ logbufflush(Logbuf *lb, Req *r)
|
|||
{
|
||||
Req **l;
|
||||
|
||||
qlock(lb);
|
||||
for(l=&lb->wait; *l; l=&(*l)->aux){
|
||||
if(*l == r){
|
||||
*l = r->aux;
|
||||
|
@ -66,6 +69,7 @@ logbufflush(Logbuf *lb, Req *r)
|
|||
break;
|
||||
}
|
||||
}
|
||||
qunlock(lb);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -74,12 +78,14 @@ logbufappend(Logbuf *lb, char *buf)
|
|||
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);
|
||||
if(++lb->wp == nelem(lb->msg))
|
||||
lb->wp = 0;
|
||||
logbufproc(lb);
|
||||
qunlock(lb);
|
||||
}
|
||||
|
||||
Logbuf logbuf;
|
||||
|
|
|
@ -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 @@ setupfss(Fsstate *fss, State *s, Key *k)
|
|||
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 @@ getdom(char *p)
|
|||
return p+1;
|
||||
}
|
||||
|
||||
static Proto*
|
||||
findneg(char *name)
|
||||
static int
|
||||
findprotox(char *name)
|
||||
{
|
||||
int i, len;
|
||||
char *p;
|
||||
|
@ -239,13 +241,27 @@ findneg(char *name)
|
|||
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)
|
||||
{
|
||||
|
@ -274,7 +290,11 @@ p9anywrite(Fsstate *fss, void *va, uint n)
|
|||
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 @@ p9anywrite(Fsstate *fss, void *va, uint n)
|
|||
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;
|
||||
|
|
|
@ -24,6 +24,7 @@ struct State
|
|||
Key *key;
|
||||
int astype;
|
||||
int asfd;
|
||||
Authkey k;
|
||||
Ticket t;
|
||||
Ticketreq tr;
|
||||
char chal[Maxchal];
|
||||
|
@ -165,18 +166,14 @@ p9crread(Fsstate *fss, void *va, uint *n)
|
|||
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 @@ p9crwrite(Fsstate *fss, void *va, uint n)
|
|||
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,15 +292,14 @@ p9crwrite(Fsstate *fss, void *va, uint n)
|
|||
|
||||
/* 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);
|
||||
}
|
||||
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 @@ getchal(State *s, Fsstate *fss)
|
|||
{
|
||||
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){
|
||||
|
|
|
@ -1,30 +1,38 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
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,33 +42,41 @@ enum
|
|||
{
|
||||
/* 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,
|
||||
};
|
||||
|
||||
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 @@ p9skinit(Proto *p, Fsstate *fss)
|
|||
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 @@ p9skinit(Proto *p, Fsstate *fss)
|
|||
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;
|
||||
|
@ -125,6 +122,39 @@ p9skinit(Proto *p, Fsstate *fss)
|
|||
return RpcOk;
|
||||
}
|
||||
|
||||
static int
|
||||
establish(Fsstate *fss)
|
||||
{
|
||||
AuthInfo *ai;
|
||||
State *s;
|
||||
|
||||
s = fss->ps;
|
||||
ai = &fss->ai;
|
||||
|
||||
ai->cuid = s->t.cuid;
|
||||
ai->suid = s->t.suid;
|
||||
if(fss->proto == &dp9ik){
|
||||
static char info[] = "Plan 9 session secret";
|
||||
|
||||
ai->nsecret = 256;
|
||||
ai->secret = emalloc(ai->nsecret);
|
||||
hkdf_x( s->rand, 2*NONCELEN,
|
||||
(uchar*)info, sizeof(info)-1,
|
||||
s->t.key, NONCELEN,
|
||||
ai->secret, ai->nsecret,
|
||||
hmac_sha2_256, SHA2_256dlen);
|
||||
} else {
|
||||
ai->nsecret = 8;
|
||||
ai->secret = emalloc(ai->nsecret);
|
||||
des56to64((uchar*)s->t.key, ai->secret);
|
||||
}
|
||||
s->secret = ai->secret;
|
||||
|
||||
fss->haveai = 1;
|
||||
fss->phase = Established;
|
||||
return RpcOk;
|
||||
}
|
||||
|
||||
static int
|
||||
p9skread(Fsstate *fss, void *a, uint *n)
|
||||
{
|
||||
|
@ -142,13 +172,37 @@ p9skread(Fsstate *fss, void *a, uint *n)
|
|||
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 @@ p9skread(Fsstate *fss, void *a, uint *n)
|
|||
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 @@ static int
|
|||
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 @@ p9skwrite(Fsstate *fss, void *a, uint n)
|
|||
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 = convM2TR(a, n, &s->tr);
|
||||
if(m <= 0)
|
||||
return toosmall(fss, -m);
|
||||
m = TICKREQLEN;
|
||||
if(n < m)
|
||||
return toosmall(fss, m);
|
||||
|
||||
/* remember server's chal */
|
||||
if(s->vers == 2)
|
||||
memmove(s->cchal, s->tr.chal, CHALLEN);
|
||||
m = convM2TR(a, n, &s->tr);
|
||||
if(m <= 0 || s->tr.type != (fss->phase==CNeedPAKreq ? AuthPAK : AuthTreq))
|
||||
return failure(fss, Easproto);
|
||||
|
||||
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 @@ p9skwrite(Fsstate *fss, void *a, uint n)
|
|||
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,27 +310,32 @@ p9skwrite(Fsstate *fss, void *a, uint n)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
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 @@ p9skwrite(Fsstate *fss, void *a, uint n)
|
|||
_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 @@ p9skwrite(Fsstate *fss, void *a, uint n)
|
|||
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 @@ p9skclose(Fsstate *fss)
|
|||
closekey(s->key);
|
||||
s->key = nil;
|
||||
}
|
||||
memset(s, 0, sizeof(State));
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
@ -386,14 +450,27 @@ static int
|
|||
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 @@ p9skaddkey(Key *k, int before)
|
|||
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,31 +490,12 @@ p9skaddkey(Key *k, int before)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
mkservertickets(State *s, uchar *y, char *tbuf, int tbuflen)
|
||||
{
|
||||
Ticketreq *tr = &s->tr;
|
||||
Ticket t;
|
||||
|
@ -446,31 +508,86 @@ mkserverticket(State *s, char *tbuf, int tbuflen)
|
|||
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 @@ Proto p9sk1 = {
|
|||
.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?"
|
||||
};
|
||||
|
||||
|
|
|
@ -429,15 +429,20 @@ ctlwrite(char *a, int atzero)
|
|||
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");
|
||||
|
|
|
@ -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 @@ netndbauthaddr(void)
|
|||
}
|
||||
|
||||
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 @@ _authdial(char *net, char *authdom)
|
|||
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 @@ canusekey(Fsstate *fss, Key *k)
|
|||
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 @@ closekey(Key *k)
|
|||
{
|
||||
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 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
|
|||
return failure(ki->fss, nil);
|
||||
}
|
||||
|
||||
qlock(ring);
|
||||
nmatch = 0;
|
||||
for(i=0; i<ring->nkey; i++){
|
||||
k = ring->key[i];
|
||||
|
@ -391,6 +417,7 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
|
|||
if(!ki->noconf){
|
||||
switch(canusekey(ki->fss, k)){
|
||||
case -1:
|
||||
qunlock(ring);
|
||||
_freeattr(attr1);
|
||||
return RpcConfirm;
|
||||
case 0:
|
||||
|
@ -402,11 +429,13 @@ findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
|
|||
_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 @@ findp9authkey(Key **k, Fsstate *fss)
|
|||
{
|
||||
char *dom;
|
||||
Keyinfo ki;
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* We don't use fss->attr here because we don't
|
||||
|
@ -454,10 +484,18 @@ findp9authkey(Key **k, Fsstate *fss)
|
|||
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 @@ findproto(char *name)
|
|||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
int
|
||||
getnvramkey(int flag)
|
||||
{
|
||||
Nvrsafe safe;
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
memset(&safe, 0, sizeof safe);
|
||||
/*
|
||||
|
@ -484,24 +521,30 @@ getnvramkey(int flag)
|
|||
* 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,24 +824,26 @@ replacekey(Key *kn, int before)
|
|||
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;
|
||||
ring->nkey++;
|
||||
}else
|
||||
ring->key[ring->nkey++] = kn;
|
||||
qunlock(ring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ enum {
|
|||
Quser,
|
||||
Qkey,
|
||||
Qaeskey,
|
||||
Qpakhash,
|
||||
Qsecret,
|
||||
Qlog,
|
||||
Qstatus,
|
||||
|
@ -54,8 +55,7 @@ struct Fid {
|
|||
|
||||
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 @@ char *qinfo[Qmax] = {
|
|||
[Quser] ".",
|
||||
[Qkey] "key",
|
||||
[Qaeskey] "aeskey",
|
||||
[Qpakhash] "pakhash",
|
||||
[Qsecret] "secret",
|
||||
[Qlog] "log",
|
||||
[Qexpire] "expire",
|
||||
|
@ -180,6 +181,7 @@ main(int argc, char *argv[])
|
|||
if(pipe(p) < 0)
|
||||
error("can't make pipe: %r");
|
||||
|
||||
private();
|
||||
if(usepass)
|
||||
getpass(&authkey, nil, 0, 0);
|
||||
else {
|
||||
|
@ -374,7 +376,7 @@ Open(Fid *f)
|
|||
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 @@ Read(Fid *f)
|
|||
return 0;
|
||||
case Qkey:
|
||||
case Qaeskey:
|
||||
case Qpakhash:
|
||||
case Qsecret:
|
||||
if(f->user->status != Sok)
|
||||
return "user disabled";
|
||||
|
@ -468,13 +471,17 @@ Read(Fid *f)
|
|||
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 @@ Write(Fid *f)
|
|||
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 @@ writeusers(void)
|
|||
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 @@ writeusers(void)
|
|||
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 @@ writeusers(void)
|
|||
|
||||
free(buf);
|
||||
close(fd);
|
||||
|
||||
newkeys();
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -897,7 +907,7 @@ readusers(void)
|
|||
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 @@ readusers(void)
|
|||
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);
|
||||
|
|
|
@ -6,6 +6,7 @@ OFILES=\
|
|||
keyfmt.$O\
|
||||
netcheck.$O\
|
||||
okpasswd.$O\
|
||||
private.$O\
|
||||
readwrite.$O\
|
||||
readarg.$O\
|
||||
readln.$O\
|
||||
|
|
|
@ -66,8 +66,14 @@ findkey(char *db, char *user, Authkey *key)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ usage(void)
|
|||
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 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
readln("Password: ", pass, sizeof pass, 1);
|
||||
passtokey(&key, pass);
|
||||
passtodeskey(key, pass);
|
||||
|
||||
for(;;){
|
||||
print("challenge: ");
|
||||
|
@ -44,7 +43,7 @@ main(int argc, char *argv[])
|
|||
buf[n] = '\0';
|
||||
n = strtol(buf, 0, 10);
|
||||
sprint(buf, "%d", n);
|
||||
netcrypt(key.des, buf);
|
||||
netcrypt(key, buf);
|
||||
print("response: %s\n", buf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ main(int argc, char **argv)
|
|||
ARGBEGIN{
|
||||
}ARGEND
|
||||
|
||||
private();
|
||||
|
||||
s = nil;
|
||||
if(argc > 0){
|
||||
user = argv[0];
|
||||
|
@ -34,6 +36,10 @@ main(int argc, char **argv)
|
|||
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 @@ main(int argc, char **argv)
|
|||
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 @@ main(int argc, char **argv)
|
|||
*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 @@ main(int argc, char **argv)
|
|||
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");
|
||||
|
|
|
@ -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 @@ netresp(Authkey *key, long chal, char *answer)
|
|||
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 @@ auth_userpasswd(char *user, char *passwd)
|
|||
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);
|
||||
|
|
26
sys/src/libauthsrv/_asgetpakkey.c
Normal file
26
sys/src/libauthsrv/_asgetpakkey.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <authsrv.h>
|
||||
|
||||
int
|
||||
_asgetpakkey(int fd, Ticketreq *tr, Authkey *a)
|
||||
{
|
||||
uchar y[PAKYLEN];
|
||||
PAKpriv p;
|
||||
int type;
|
||||
|
||||
type = tr->type;
|
||||
tr->type = AuthPAK;
|
||||
if(_asrequest(fd, tr) != 0){
|
||||
tr->type = type;
|
||||
return -1;
|
||||
}
|
||||
tr->type = type;
|
||||
authpak_new(&p, a, y, 1);
|
||||
if(write(fd, y, PAKYLEN) != PAKYLEN
|
||||
|| _asrdresp(fd, (char*)y, PAKYLEN) != PAKYLEN){
|
||||
memset(&p, 0, sizeof(p));
|
||||
return -1;
|
||||
}
|
||||
return authpak_finish(&p, a, y);
|
||||
}
|
|
@ -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)
|
||||
strcpy(err, "AS protocol botch");
|
||||
errstr(err, ERRMAX);
|
||||
|
||||
if(_asrdresp(fd, buf, 0) < 0)
|
||||
return -1;
|
||||
|
||||
m = convM2T(tbuf, n, t, k);
|
||||
if(m <= 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
214
sys/src/libauthsrv/authpak.c
Normal file
214
sys/src/libauthsrv/authpak.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <mp.h>
|
||||
#include <libsec.h>
|
||||
#include <authsrv.h>
|
||||
|
||||
#include "msqrt.mpc"
|
||||
#include "decaf.mpc"
|
||||
#include "edwards.mpc"
|
||||
#include "elligator2.mpc"
|
||||
#include "spake2ee.mpc"
|
||||
#include "ed448.mpc"
|
||||
|
||||
typedef struct PAKcurve PAKcurve;
|
||||
struct PAKcurve
|
||||
{
|
||||
Lock;
|
||||
mpint *P;
|
||||
mpint *A;
|
||||
mpint *D;
|
||||
mpint *X;
|
||||
mpint *Y;
|
||||
};
|
||||
|
||||
static PAKcurve*
|
||||
authpak_curve(void)
|
||||
{
|
||||
static PAKcurve a;
|
||||
|
||||
lock(&a);
|
||||
if(a.P == nil){
|
||||
a.P = mpnew(0);
|
||||
a.A = mpnew(0);
|
||||
a.D = mpnew(0);
|
||||
a.X = mpnew(0);
|
||||
a.Y = mpnew(0);
|
||||
ed448_curve(a.P, a.A, a.D, a.X, a.Y);
|
||||
a.P = mpfield(a.P);
|
||||
}
|
||||
unlock(&a);
|
||||
return &a;
|
||||
}
|
||||
|
||||
void
|
||||
authpak_hash(Authkey *k, char *u)
|
||||
{
|
||||
static char info[] = "Plan 9 AuthPAK hash";
|
||||
uchar *bp, salt[SHA2_256dlen], h[2*PAKSLEN];
|
||||
mpint *H, *PX,*PY,*PZ,*PT;
|
||||
PAKcurve *c;
|
||||
|
||||
H = mpnew(0);
|
||||
PX = mpnew(0);
|
||||
PY = mpnew(0);
|
||||
PZ = mpnew(0);
|
||||
PT = mpnew(0);
|
||||
|
||||
sha2_256((uchar*)u, strlen(u), salt, nil);
|
||||
|
||||
hkdf_x( salt, SHA2_256dlen,
|
||||
(uchar*)info, sizeof(info)-1,
|
||||
k->aes, AESKEYLEN,
|
||||
h, sizeof(h),
|
||||
hmac_sha2_256, SHA2_256dlen);
|
||||
|
||||
c = authpak_curve();
|
||||
|
||||
betomp(h + 0*PAKSLEN, PAKSLEN, H); /* HM */
|
||||
spake2ee_h2P(c->P,c->A,c->D, H, PX,PY,PZ,PT); /* PM */
|
||||
|
||||
bp = k->pakhash;
|
||||
mptober(PX, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PY, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PZ, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PT, bp, PAKSLEN), bp += PAKSLEN;
|
||||
|
||||
betomp(h + 1*PAKSLEN, PAKSLEN, H); /* HN */
|
||||
spake2ee_h2P(c->P,c->A,c->D, H, PX,PY,PZ,PT); /* PN */
|
||||
|
||||
mptober(PX, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PY, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PZ, bp, PAKSLEN), bp += PAKSLEN;
|
||||
mptober(PT, bp, PAKSLEN);
|
||||
|
||||
mpfree(PX);
|
||||
mpfree(PY);
|
||||
mpfree(PZ);
|
||||
mpfree(PT);
|
||||
mpfree(H);
|
||||
}
|
||||
|
||||
void
|
||||
authpak_new(PAKpriv *p, Authkey *k, uchar y[PAKYLEN], int isclient)
|
||||
{
|
||||
mpint *PX,*PY,*PZ,*PT, *X, *Y;
|
||||
PAKcurve *c;
|
||||
uchar *bp;
|
||||
|
||||
memset(p, 0, sizeof(PAKpriv));
|
||||
p->isclient = isclient != 0;
|
||||
|
||||
X = mpnew(0);
|
||||
Y = mpnew(0);
|
||||
|
||||
PX = mpnew(0);
|
||||
PY = mpnew(0);
|
||||
PZ = mpnew(0);
|
||||
PT = mpnew(0);
|
||||
|
||||
PX->flags |= MPtimesafe;
|
||||
PY->flags |= MPtimesafe;
|
||||
PZ->flags |= MPtimesafe;
|
||||
PT->flags |= MPtimesafe;
|
||||
|
||||
bp = k->pakhash + PAKPLEN*(p->isclient == 0);
|
||||
betomp(bp, PAKSLEN, PX), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PY), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PZ), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PT);
|
||||
|
||||
c = authpak_curve();
|
||||
|
||||
X->flags |= MPtimesafe;
|
||||
mpnrand(c->P, genrandom, X);
|
||||
|
||||
spake2ee_1(c->P,c->A,c->D, X, c->X,c->Y, PX,PY,PZ,PT, Y);
|
||||
|
||||
mptober(X, p->x, PAKXLEN);
|
||||
mptober(Y, p->y, PAKYLEN);
|
||||
|
||||
memmove(y, p->y, PAKYLEN);
|
||||
|
||||
mpfree(PX);
|
||||
mpfree(PY);
|
||||
mpfree(PZ);
|
||||
mpfree(PT);
|
||||
|
||||
mpfree(X);
|
||||
mpfree(Y);
|
||||
}
|
||||
|
||||
int
|
||||
authpak_finish(PAKpriv *p, Authkey *k, uchar y[PAKYLEN])
|
||||
{
|
||||
static char info[] = "Plan 9 AuthPAK key";
|
||||
uchar *bp, z[PAKSLEN], salt[SHA2_256dlen];
|
||||
mpint *PX,*PY,*PZ,*PT, *X, *Y, *Z, *ok;
|
||||
DigestState *s;
|
||||
PAKcurve *c;
|
||||
int ret;
|
||||
|
||||
X = mpnew(0);
|
||||
Y = mpnew(0);
|
||||
Z = mpnew(0);
|
||||
ok = mpnew(0);
|
||||
|
||||
PX = mpnew(0);
|
||||
PY = mpnew(0);
|
||||
PZ = mpnew(0);
|
||||
PT = mpnew(0);
|
||||
|
||||
PX->flags |= MPtimesafe;
|
||||
PY->flags |= MPtimesafe;
|
||||
PZ->flags |= MPtimesafe;
|
||||
PT->flags |= MPtimesafe;
|
||||
|
||||
bp = k->pakhash + PAKPLEN*(p->isclient != 0);
|
||||
betomp(bp, PAKSLEN, PX), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PY), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PZ), bp += PAKSLEN;
|
||||
betomp(bp, PAKSLEN, PT);
|
||||
|
||||
Z->flags |= MPtimesafe;
|
||||
X->flags |= MPtimesafe;
|
||||
betomp(p->x, PAKXLEN, X);
|
||||
|
||||
betomp(y, PAKYLEN, Y);
|
||||
|
||||
c = authpak_curve();
|
||||
spake2ee_2(c->P,c->A,c->D, PX,PY,PZ,PT, X, Y, ok, Z);
|
||||
|
||||
if(mpcmp(ok, mpzero) == 0){
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mptober(Z, z, sizeof(z));
|
||||
|
||||
s = sha2_256(p->isclient ? p->y : y, PAKYLEN, nil, nil);
|
||||
sha2_256(p->isclient ? y : p->y, PAKYLEN, salt, s);
|
||||
|
||||
hkdf_x( salt, SHA2_256dlen,
|
||||
(uchar*)info, sizeof(info)-1,
|
||||
z, sizeof(z),
|
||||
k->pakkey, PAKKEYLEN,
|
||||
hmac_sha2_256, SHA2_256dlen);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
memset(z, 0, sizeof(z));
|
||||
memset(p, 0, sizeof(PAKpriv));
|
||||
|
||||
mpfree(PX);
|
||||
mpfree(PY);
|
||||
mpfree(PZ);
|
||||
mpfree(PT);
|
||||
|
||||
mpfree(X);
|
||||
mpfree(Y);
|
||||
mpfree(Z);
|
||||
mpfree(ok);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -2,26 +2,35 @@
|
|||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 @@ convM2TR(char *ap, int n, Ticketreq *f)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -2,29 +2,33 @@
|
|||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,39 @@
|
|||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 @@ convTR2M(Ticketreq *f, char *ap, int n)
|
|||
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;
|
||||
}
|
||||
|
|
49
sys/src/libauthsrv/decaf.mp
Normal file
49
sys/src/libauthsrv/decaf.mp
Normal file
|
@ -0,0 +1,49 @@
|
|||
# negate r when n > (p-1)/2
|
||||
decaf_neg(p, n, r) {
|
||||
mod(p) m = -r;
|
||||
r = n > (p-1)>>1 ? m : r;
|
||||
}
|
||||
|
||||
# field F_p
|
||||
# curve a*x**2+y**2==1+d*x**2*y**2
|
||||
# input X,Y,Z,T (extended coordinates)
|
||||
decaf_encode(p,a,d, X,Y,Z,T, s) mod(p) {
|
||||
r = misqrt((a-d)*(Z+Y)*(Z-Y), p);
|
||||
u = (a-d)*r;
|
||||
decaf_neg(p, -2*u*Z, r);
|
||||
s = u*(r*(a*Z*X-d*Y*T)+Y)/a;
|
||||
decaf_neg(p, s, s);
|
||||
}
|
||||
|
||||
# field F_p
|
||||
# curve a*x**2+y**2==1+d*x**2*y**2
|
||||
# input s
|
||||
# output in extended coordinates
|
||||
decaf_decode(p,a,d, s, ok,X,Y,Z,T) {
|
||||
if(s > (p-1)>>1){
|
||||
ok = 0;
|
||||
} else mod(p) {
|
||||
ss = s^2;
|
||||
Z = 1+a*ss;
|
||||
u = Z^2 - 4*d*ss;
|
||||
v = u*ss;
|
||||
if(v == 0)
|
||||
ok = 1;
|
||||
else {
|
||||
ok = msqrt(v, p);
|
||||
if(ok != 0){
|
||||
v = 1/ok;
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
if(ok != 0) {
|
||||
decaf_neg(p, u*v, v);
|
||||
w = v * s * (2-Z);
|
||||
if(s == 0)
|
||||
w = w + 1;
|
||||
X = 2*s;
|
||||
Y = w * Z;
|
||||
T = w * X;
|
||||
}
|
||||
}
|
||||
}
|
11
sys/src/libauthsrv/ed448.mp
Normal file
11
sys/src/libauthsrv/ed448.mp
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Edwards Curve Ed448-Goldilocks
|
||||
|
||||
# x^2+y^2 = 1-39081x^2y^2
|
||||
# modulo p = 2^448 - 1^224 - 1
|
||||
ed448_curve(p,a,d,x,y) {
|
||||
p = (1<<448) - (1<<224) - 1;
|
||||
a = 1;
|
||||
d = -39081;
|
||||
x = 117812161263436946737282484343310064665180535357016373416879082147939404277809514858788439644911793978499419995990477371552926308078495;
|
||||
y = 19;
|
||||
}
|
40
sys/src/libauthsrv/edwards.mp
Normal file
40
sys/src/libauthsrv/edwards.mp
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Edwards curve arithmetic
|
||||
edwards_add(p,a,d, X1,Y1,Z1,T1, X2,Y2,Z2,T2, X3,Y3,Z3,T3) mod(p) {
|
||||
A = X1*X2;
|
||||
B = Y1*Y2;
|
||||
C = d*T1*T2;
|
||||
D = Z1*Z2;
|
||||
E = (X1+Y1)*(X2+Y2);
|
||||
E = E - A - B;
|
||||
F = D - C;
|
||||
G = D + C;
|
||||
H = B - a*A;
|
||||
X3 = E*F;
|
||||
Y3 = G*H;
|
||||
Z3 = F*G;
|
||||
T3 = E*H;
|
||||
}
|
||||
edwards_sel(s, X1,Y1,Z1,T1, X2,Y2,Z2,T2, X3,Y3,Z3,T3){
|
||||
X3 = s != 0 ? X1 : X2;
|
||||
Y3 = s != 0 ? Y1 : Y2;
|
||||
Z3 = s != 0 ? Z1 : Z2;
|
||||
T3 = s != 0 ? T1 : T2;
|
||||
}
|
||||
edwards_new(x,y,z,t, X,Y,Z,T) {
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
T = t;
|
||||
}
|
||||
edwards_scale(p,a,d, s, X1,Y1,Z1,T1, X3,Y3,Z3,T3) {
|
||||
X2,Y2,Z2,T2 = edwards_new(X1,Y1,Z1,T1);
|
||||
X4,Y4,Z4,T4 = edwards_new( 0, 1, 1, 0);
|
||||
X3,Y3,Z3,T3 = edwards_sel(s % 2, X2,Y2,Z2,T2, X4,Y4,Z4,T4);
|
||||
k = s >> 1; j = p >> 1;
|
||||
while(j != 0){
|
||||
X2,Y2,Z2,T2 = edwards_add(p,a,d, X2,Y2,Z2,T2, X2,Y2,Z2,T2);
|
||||
X4,Y4,Z4,T4 = edwards_add(p,a,d, X2,Y2,Z2,T2, X3,Y3,Z3,T3);
|
||||
X3,Y3,Z3,T3 = edwards_sel(k % 2, X4,Y4,Z4,T4, X3,Y3,Z3,T3);
|
||||
k = k >> 1; j = j >> 1;
|
||||
}
|
||||
}
|
30
sys/src/libauthsrv/elligator2.mp
Normal file
30
sys/src/libauthsrv/elligator2.mp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#elligator2:
|
||||
# curve a*x^2+y^2==1+d*x^2*y^2
|
||||
# input r0
|
||||
# n is any non-square
|
||||
#
|
||||
elligator2(p,a,d, n, r0, X,Y,Z,T) mod(p) {
|
||||
r = n*r0*r0;
|
||||
D = (d*r+a-d)*(d*r-a*r-d);
|
||||
N = (r+1)*(a-2*d);
|
||||
ND = N*D;
|
||||
if(ND == 0) {
|
||||
c = 1;
|
||||
e = 0;
|
||||
} else {
|
||||
e = msqrt(ND, p);
|
||||
if(e != 0) {
|
||||
c = 1;
|
||||
e = 1/e;
|
||||
} else {
|
||||
c = -1;
|
||||
e = n*r0*misqrt(n*ND, p);
|
||||
}
|
||||
}
|
||||
s = c*N*e;
|
||||
t = -c*N*(r-1)*((a-2*d)*e)^2-1;
|
||||
X = 2*s*t;
|
||||
Y = (1-a*s*s)*(1+a*s*s);
|
||||
Z = (1+a*s*s)*t;
|
||||
T = (2*s)*(1-a*s*s);
|
||||
}
|
90
sys/src/libauthsrv/form1.c
Normal file
90
sys/src/libauthsrv/form1.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <authsrv.h>
|
||||
#include <libsec.h>
|
||||
|
||||
/*
|
||||
* new ticket format: the reply protector/type is replaced by a
|
||||
* 8 byte signature and a 4 byte counter forming the 12 byte
|
||||
* nonce for chacha20/poly1305 encryption. a 16 byte poly1305
|
||||
* authentication tag is appended for message authentication.
|
||||
* the counter is needed for the AuthPass message which uses
|
||||
* the same key for several messages.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
char num;
|
||||
char sig[8];
|
||||
} form1sig[] = {
|
||||
AuthPass, "form1 PR", /* password change request encrypted with ticket key */
|
||||
AuthTs, "form1 Ts", /* ticket encrypted with server's key */
|
||||
AuthTc, "form1 Tc", /* ticket encrypted with client's key */
|
||||
AuthAs, "form1 As", /* server generated authenticator */
|
||||
AuthAc, "form1 Ac", /* client generated authenticator */
|
||||
AuthTp, "form1 Tp", /* ticket encrypted with client's key for password change */
|
||||
AuthHr, "form1 Hr", /* http reply */
|
||||
};
|
||||
|
||||
int
|
||||
form1check(char *ap, int n)
|
||||
{
|
||||
if(n < 8)
|
||||
return -1;
|
||||
|
||||
for(n=0; n<nelem(form1sig); n++)
|
||||
if(memcmp(form1sig[n].sig, ap, 8) == 0)
|
||||
return form1sig[n].num;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
form1B2M(char *ap, int n, uchar key[32])
|
||||
{
|
||||
static u32int counter;
|
||||
Chachastate s;
|
||||
uchar *p;
|
||||
int i;
|
||||
|
||||
for(i=nelem(form1sig)-1; i>=0; i--)
|
||||
if(form1sig[i].num == *ap)
|
||||
break;
|
||||
if(i < 0)
|
||||
abort();
|
||||
|
||||
p = (uchar*)ap + 12;
|
||||
memmove(p, ap+1, --n);
|
||||
|
||||
/* nonce[12] = sig[8] | counter[4] */
|
||||
memmove(ap, form1sig[i].sig, 8);
|
||||
i = counter++;
|
||||
ap[8] = i, ap[9] = i>>8, ap[10] = i>>16, ap[11] = i>>24;
|
||||
|
||||
setupChachastate(&s, key, 32, (uchar*)ap, 12, 20);
|
||||
ccpoly_encrypt(p, n, nil, 0, p+n, &s);
|
||||
return 12+16 + n;
|
||||
}
|
||||
|
||||
int
|
||||
form1M2B(char *ap, int n, uchar key[32])
|
||||
{
|
||||
Chachastate s;
|
||||
uchar *p;
|
||||
int num;
|
||||
|
||||
num = form1check(ap, n);
|
||||
if(num < 0)
|
||||
return -1;
|
||||
n -= 12+16;
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
|
||||
p = (uchar*)ap + 12;
|
||||
setupChachastate(&s, key, 32, (uchar*)ap, 12, 20);
|
||||
if(ccpoly_decrypt(p, n, nil, 0, p+n, &s))
|
||||
return -1;
|
||||
|
||||
memmove(ap+1, p, n);
|
||||
ap[0] = num;
|
||||
return n+1;
|
||||
}
|
|
@ -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 @@ OFILES=\
|
|||
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
|
||||
|
|
100
sys/src/libauthsrv/msqrt.mp
Normal file
100
sys/src/libauthsrv/msqrt.mp
Normal file
|
@ -0,0 +1,100 @@
|
|||
# derived from: http://eli.thegreenplace.net/2009/03/07/computing-square-roots-in-python
|
||||
|
||||
# Compute the Legendre symbol a|p using Euler's criterion.
|
||||
# p is a prime, a is relatively prime to p (if p divides a,
|
||||
# then a|p = 0)
|
||||
legendresymbol(a, p, r) {
|
||||
pm1 = p-1;
|
||||
mod(p) r = a^(pm1>>1);
|
||||
if(r == pm1)
|
||||
r = -1;
|
||||
}
|
||||
|
||||
# Find a quadratic residue (mod p) of 'a'. p must be an
|
||||
# odd prime.
|
||||
#
|
||||
# Solve the congruence of the form:
|
||||
# x^2 = a (mod p)
|
||||
# And returns x. Node that p - x is also a root.
|
||||
#
|
||||
# 0 is returned if no square root exists for these
|
||||
# a and p.
|
||||
#
|
||||
# The Tonelli-Shanks algorithm is used (except
|
||||
# for some simple cases in which the solution is known
|
||||
# from an identity).
|
||||
msqrt(a, p, r) {
|
||||
if(legendresymbol(a, p) != 1)
|
||||
r = 0;
|
||||
else if(a == 0)
|
||||
r = 0;
|
||||
else if(p == 2)
|
||||
r = a;
|
||||
else if(p%4 == 3){
|
||||
e = p+1 >> 2;
|
||||
mod(p) r = a^e;
|
||||
} else {
|
||||
# Partition p-1 to s * 2^e for an odd s (i.e.
|
||||
# reduce all the powers of 2 from p-1)
|
||||
s = p-1;
|
||||
e = 0;
|
||||
while(s%2 == 0){
|
||||
s = s >> 1;
|
||||
e = e + 1;
|
||||
}
|
||||
|
||||
# Find some 'n' with a legendre symbol n|p = -1.
|
||||
# Shouldn't take long.
|
||||
n = 2;
|
||||
while(legendresymbol(n, p) != -1)
|
||||
n = n + 1;
|
||||
|
||||
# x is a guess of the square root that gets better
|
||||
# with each iteration.
|
||||
# b is the "fudge factor" - by now much we're off
|
||||
# with the guess. The invariant x^2 == a*b (mod p)
|
||||
# is maintained throughout the loop.
|
||||
# g is used for successive powers of n to update
|
||||
# both a and b
|
||||
# e is the exponent - decreases with each update
|
||||
mod(p){
|
||||
x = a^(s+1 >> 1);
|
||||
b = a^s;
|
||||
g = n^s;
|
||||
}
|
||||
while(1==1){
|
||||
t = b;
|
||||
m = 0;
|
||||
while(m < e){
|
||||
if(t == 1)
|
||||
break;
|
||||
t = t*t % p;
|
||||
m = m + 1;
|
||||
}
|
||||
if(m == 0){
|
||||
r = x;
|
||||
break;
|
||||
}
|
||||
t = 2^(e-m-1);
|
||||
mod(p){
|
||||
gs = g^t;
|
||||
g = gs*gs;
|
||||
x = x*gs;
|
||||
b = b*g;
|
||||
}
|
||||
e = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# modular inverse square-root
|
||||
misqrt(a, p, r) {
|
||||
if((p % 4) == 3){
|
||||
e = ((p-3)>>2);
|
||||
mod(p) r = a^e;
|
||||
} else {
|
||||
r = msqrt(a, p);
|
||||
if(r != 0)
|
||||
mod(p) r = 1/r;
|
||||
}
|
||||
}
|
|
@ -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,17 +32,17 @@ passtodeskey(char *key, char *p)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
35
sys/src/libauthsrv/spake2ee.mp
Normal file
35
sys/src/libauthsrv/spake2ee.mp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# this implements a variant of SPAKE2 Elligator edition described in:
|
||||
# https://www.mail-archive.com/curves@moderncrypto.org/msg00412.html
|
||||
#
|
||||
|
||||
# derive points PM or PN from a (password) hash
|
||||
spake2ee_h2P(p,a,d, h, PX,PY,PZ,PT){
|
||||
# find a small non-square for elligator
|
||||
n = 2;
|
||||
while(legendresymbol(n, p) != -1)
|
||||
n = n + 1;
|
||||
PX,PY,PZ,PT = elligator2(p,a,d, n, h%p);
|
||||
}
|
||||
|
||||
# Ya = xa*G+PM, Yb = xb*G+PN
|
||||
spake2ee_1(p,a,d, x, GX,GY, PX,PY,PZ,PT, y){
|
||||
mod(p) X,Y,Z,T = edwards_scale(p,a,d, x, GX,GY,1,GX*GY);
|
||||
X,Y,Z,T = edwards_add(p,a,d, X,Y,Z,T, PX,PY,PZ,PT);
|
||||
y = decaf_encode(p,a,d, X,Y,Z,T);
|
||||
}
|
||||
|
||||
# Z = xa*(Yb-PN)
|
||||
# = xa*(xb*G+PN-PN)
|
||||
# = xa*xb*G
|
||||
# = xb*xa*G
|
||||
# = xb*(xa*G+PM-PM)
|
||||
# = xb*(Ya-PM)
|
||||
spake2ee_2(p,a,d, PX,PY,PZ,PT, x, y, ok, z){
|
||||
ok, X,Y,Z,T = decaf_decode(p,a,d, y);
|
||||
if(ok != 0){
|
||||
mod(p) X,Y,Z,T = edwards_add(p,a,d, X,Y,Z,T, -PX,PY,PZ,-PT);
|
||||
X,Y,Z,T = edwards_scale(p,a,d, x, X,Y,Z,T);
|
||||
z = decaf_encode(p,a,d, X,Y,Z,T);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue