introduce AES key into nvram and keyfs
This commit is contained in:
parent
e48a5832b2
commit
63b18e7925
10 changed files with 366 additions and 245 deletions
|
@ -20,6 +20,7 @@ enum
|
|||
AERRLEN= 64, /* errstr max size in previous proto */
|
||||
DOMLEN= 48, /* authentication domain name length */
|
||||
DESKEYLEN= 7, /* encrypt/decrypt des key length */
|
||||
AESKEYLEN= 16,
|
||||
CHALLEN= 8, /* plan9 sk1 challenge length */
|
||||
NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
|
||||
CONFIGLEN= 14,
|
||||
|
@ -115,6 +116,7 @@ struct OMSchapreply
|
|||
struct Authkey
|
||||
{
|
||||
char des[DESKEYLEN];
|
||||
uchar aes[AESKEYLEN];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -132,7 +134,7 @@ extern int convM2PR(char*, int, Passwordreq*, Ticket*);
|
|||
/*
|
||||
* convert ascii password to DES key
|
||||
*/
|
||||
extern int passtokey(Authkey*, char*);
|
||||
extern void passtokey(Authkey*, char*);
|
||||
|
||||
/*
|
||||
* Nvram interface
|
||||
|
@ -147,7 +149,7 @@ enum {
|
|||
/* storage layout */
|
||||
struct Nvrsafe
|
||||
{
|
||||
char machkey[DESKEYLEN]; /* was file server's authid's des key */
|
||||
char machkey[DESKEYLEN]; /* file server's authid's des key */
|
||||
uchar machsum;
|
||||
char authkey[DESKEYLEN]; /* authid's des key from password */
|
||||
uchar authsum;
|
||||
|
@ -159,8 +161,11 @@ struct Nvrsafe
|
|||
uchar configsum;
|
||||
char authid[ANAMELEN]; /* auth userid, e.g., bootes */
|
||||
uchar authidsum;
|
||||
char authdom[DOMLEN]; /* auth domain, e.g., cs.bell-labs.com */
|
||||
char authdom[DOMLEN]; /* auth domain, e.g., cs.bell-labs.com */
|
||||
uchar authdomsum;
|
||||
|
||||
uchar aesmachkey[AESKEYLEN];
|
||||
uchar aesmachsum;
|
||||
};
|
||||
|
||||
extern uchar nvcsum(void*, int);
|
||||
|
|
|
@ -15,7 +15,7 @@ authdial, passtokey, nvcsum, readnvram, convT2M, convM2T, convTR2M, convM2TR, co
|
|||
int authdial(char *netroot, char *ad);
|
||||
.PP
|
||||
.B
|
||||
int passtokey(Authkey *key, char *password)
|
||||
void passtokey(Authkey *key, char *password)
|
||||
.PP
|
||||
.B
|
||||
uchar nvcsum(void *mem, int len)
|
||||
|
@ -109,10 +109,6 @@ into a set of cryptographic keys and stores them in the
|
|||
.I Authkey
|
||||
structure
|
||||
.IR key .
|
||||
It returns 0 if
|
||||
.I password
|
||||
could not be converted,
|
||||
and 1 otherwise.
|
||||
.PP
|
||||
.I Readnvram
|
||||
reads authentication information into the structure:
|
||||
|
|
|
@ -41,7 +41,7 @@ reads and decrypts file
|
|||
.I keyfile
|
||||
(default
|
||||
.BR /adm/keys )
|
||||
using the DES key,
|
||||
using the DES or AES key,
|
||||
which is by default read from
|
||||
.B #r/nvram
|
||||
(see
|
||||
|
@ -51,13 +51,14 @@ With option
|
|||
.I keyfs
|
||||
prompts for a password from which the key is derived.
|
||||
.I Keyfile
|
||||
holds a 41-byte record for each user in the database.
|
||||
Each record is encrypted separately
|
||||
and contains the user's name,
|
||||
holds a 41-byte (57-byte for AES) record for each user in the database.
|
||||
Each record contains the user's name,
|
||||
DES key,
|
||||
status,
|
||||
host status,
|
||||
and expiration date.
|
||||
warning status,
|
||||
expiration date,
|
||||
secret password
|
||||
and AES key.
|
||||
The name is a
|
||||
null-terminated
|
||||
.SM UTF
|
||||
|
@ -67,14 +68,18 @@ bytes long.
|
|||
The status is a byte containing
|
||||
binary 0 if the account is enabled,
|
||||
1 if it is disabled.
|
||||
Host status is a byte containing
|
||||
binary 1 if the user is a host,
|
||||
0 otherwise.
|
||||
Warning status is a byte containing
|
||||
the number of user expiration notifications.
|
||||
The expiration date is four-byte little-endian integer
|
||||
which represents the time in seconds since the epoch
|
||||
(see
|
||||
.IR date (1))
|
||||
at which the account will expire.
|
||||
The secret password is a null-terminated
|
||||
.SM UTF
|
||||
string
|
||||
.B SECRETLEN
|
||||
bytes long.
|
||||
If any changes are made to the database that affect the information stored in
|
||||
.IR keyfile ,
|
||||
a new version of the file is written.
|
||||
|
@ -111,6 +116,8 @@ does not allow duplicate names when creating or renaming user entries.
|
|||
.PP
|
||||
All files in the user directories except for
|
||||
.B key
|
||||
and
|
||||
.B aeskey
|
||||
contain
|
||||
.SM UTF
|
||||
strings with a trailing newline when read,
|
||||
|
@ -121,6 +128,10 @@ strings with or without a trailing newline.
|
|||
contains the
|
||||
.BR DESKEYLEN -byte
|
||||
encryption key for the user.
|
||||
.B Aeskey
|
||||
contains the
|
||||
.BR AESKEYLEN -byte
|
||||
encryption key.
|
||||
.PP
|
||||
The following files appear in the user directories.
|
||||
.TF expire
|
||||
|
@ -133,6 +144,12 @@ Writing
|
|||
.I key
|
||||
changes the key in the database.
|
||||
.TP
|
||||
.B aeskey
|
||||
The AES encryption key for the user.
|
||||
.TP
|
||||
.B secret
|
||||
The secret password.
|
||||
.TP
|
||||
.B log
|
||||
The number of consecutive failed authentication attempts for the user.
|
||||
Writing the string
|
||||
|
|
|
@ -7,7 +7,7 @@ changeuser, convkeys, convkeys2, printnetkey, status, enable, disable, authsrv,
|
|||
.I user
|
||||
.PP
|
||||
.B auth/convkeys
|
||||
.RB [ -p ]
|
||||
.RB [ -pa ]
|
||||
.I keyfile
|
||||
.PP
|
||||
.B auth/convkeys2
|
||||
|
@ -151,6 +151,9 @@ The
|
|||
forces
|
||||
.I convkeys
|
||||
to also prompt for the old password.
|
||||
The
|
||||
.B -a
|
||||
option converts the file into AES format.
|
||||
The format of
|
||||
.I keyfile
|
||||
is described in
|
||||
|
|
|
@ -7,18 +7,21 @@
|
|||
#include <bio.h>
|
||||
#include "authcmdlib.h"
|
||||
|
||||
Authkey authkey;
|
||||
Authkey okey, nkey;
|
||||
|
||||
int verb;
|
||||
int usepass;
|
||||
int convaes;
|
||||
|
||||
int convert(char*, Authkey*, int);
|
||||
uchar zeros[16];
|
||||
|
||||
int convert(char**, int);
|
||||
void usage(void);
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Dir *d;
|
||||
Authkey key;
|
||||
char *p, *file;
|
||||
int fd, len;
|
||||
|
||||
|
@ -29,6 +32,9 @@ main(int argc, char *argv[])
|
|||
case 'v':
|
||||
verb = 1;
|
||||
break;
|
||||
case 'a':
|
||||
convaes = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
@ -40,12 +46,13 @@ main(int argc, char *argv[])
|
|||
/* get original key */
|
||||
if(usepass){
|
||||
print("enter password file is encoded with\n");
|
||||
getpass(&authkey, nil, 0, 1);
|
||||
} else
|
||||
getauthkey(&authkey);
|
||||
getpass(&okey, nil, 0, 1);
|
||||
} else {
|
||||
getauthkey(&okey);
|
||||
}
|
||||
if(!verb){
|
||||
print("enter password to reencode with\n");
|
||||
getpass(&key, nil, 0, 1);
|
||||
getpass(&nkey, nil, 0, 1);
|
||||
}
|
||||
|
||||
fd = open(file, ORDWR);
|
||||
|
@ -56,17 +63,15 @@ main(int argc, char *argv[])
|
|||
error("can't stat %s: %r\n", file);
|
||||
len = d->length;
|
||||
p = malloc(len);
|
||||
if(!p)
|
||||
if(p == nil)
|
||||
error("out of memory");
|
||||
if(read(fd, p, len) != len)
|
||||
error("can't read key file: %r\n");
|
||||
len = convert(p, &key, len);
|
||||
if(verb)
|
||||
exits(0);
|
||||
len = convert(&p, len);
|
||||
if(pwrite(fd, p, len, 0) != len)
|
||||
error("can't write key file: %r\n");
|
||||
close(fd);
|
||||
exits(0);
|
||||
exits(nil);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -76,7 +81,7 @@ randombytes(uchar *p, int len)
|
|||
|
||||
fd = open("/dev/random", OREAD);
|
||||
if(fd < 0){
|
||||
fprint(2, "convkeys: can't open /dev/random, using rand()\n");
|
||||
fprint(2, "%s: can't open /dev/random, using rand()\n", argv0);
|
||||
srand(time(0));
|
||||
for(i = 0; i < len; i++)
|
||||
p[i] = rand();
|
||||
|
@ -86,34 +91,7 @@ randombytes(uchar *p, int len)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
oldCBCencrypt(char *key7, char *p, int len)
|
||||
{
|
||||
uchar ivec[8];
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
memset(ivec, 0, 8);
|
||||
des56to64((uchar*)key7, key);
|
||||
setupDESstate(&s, key, ivec);
|
||||
desCBCencrypt((uchar*)p, len, &s);
|
||||
}
|
||||
|
||||
void
|
||||
oldCBCdecrypt(char *key7, char *p, int len)
|
||||
{
|
||||
uchar ivec[8];
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
memset(ivec, 0, 8);
|
||||
des56to64((uchar*)key7, key);
|
||||
setupDESstate(&s, key, ivec);
|
||||
desCBCdecrypt((uchar*)p, len, &s);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
badname(char *s)
|
||||
{
|
||||
int n;
|
||||
|
@ -128,35 +106,102 @@ badname(char *s)
|
|||
}
|
||||
|
||||
int
|
||||
convert(char *p, Authkey *key, int len)
|
||||
convert(char **db, int len)
|
||||
{
|
||||
int i;
|
||||
int i, nu, keydblen, keydboff, keydbaes;
|
||||
char *p = *db;
|
||||
|
||||
len -= KEYDBOFF;
|
||||
if(len % KEYDBLEN){
|
||||
fprint(2, "convkeys: file odd length; not converting %d bytes\n",
|
||||
len % KEYDBLEN);
|
||||
len -= len % KEYDBLEN;
|
||||
keydblen = KEYDBLEN;
|
||||
keydboff = KEYDBOFF;
|
||||
keydbaes = len > 24 && memcmp(p, "AES KEYS", 8) == 0;
|
||||
if(keydbaes){
|
||||
keydblen += AESKEYLEN;
|
||||
keydboff = 8+16; /* signature[8] + iv[16] */
|
||||
}
|
||||
len += KEYDBOFF;
|
||||
oldCBCdecrypt(authkey.des, p, len);
|
||||
for(i = KEYDBOFF; i < len; i += KEYDBLEN)
|
||||
if (badname(&p[i])) {
|
||||
print("bad name %.30s... - aborting\n", &p[i]);
|
||||
return 0;
|
||||
}
|
||||
if(verb)
|
||||
for(i = KEYDBOFF; i < len; i += KEYDBLEN)
|
||||
print("%s\n", &p[i]);
|
||||
|
||||
randombytes((uchar*)p, 8);
|
||||
oldCBCencrypt(key->des, p, len);
|
||||
len -= keydboff;
|
||||
if(len % keydblen){
|
||||
fprint(2, "%s: file odd length; not converting %d bytes\n", argv0, len % keydblen);
|
||||
len -= len % keydblen;
|
||||
}
|
||||
len += keydboff;
|
||||
|
||||
if(keydbaes){
|
||||
AESstate s;
|
||||
|
||||
/* make sure we have aes key for decryption */
|
||||
if(memcmp(okey.aes, zeros, AESKEYLEN) == 0){
|
||||
fprint(2, "%s: no aes key in NVRAM\n", argv0);
|
||||
exits("no aes key");
|
||||
}
|
||||
setupAESstate(&s, okey.aes, AESKEYLEN, zeros);
|
||||
aesCBCdecrypt((uchar*)p+8, len-8, &s);
|
||||
} else {
|
||||
DESstate s;
|
||||
uchar k[8];
|
||||
|
||||
des56to64((uchar*)okey.des, k);
|
||||
setupDESstate(&s, k, zeros);
|
||||
desCBCdecrypt((uchar*)p, len, &s);
|
||||
}
|
||||
|
||||
nu = 0;
|
||||
for(i = keydboff; i < len; i += keydblen) {
|
||||
if (badname(&p[i])) {
|
||||
fprint(2, "%s: bad name %.30s... - aborting\n", argv0, &p[i]);
|
||||
exits("bad name");
|
||||
}
|
||||
nu++;
|
||||
}
|
||||
|
||||
if(verb){
|
||||
for(i = keydboff; i < len; i += keydblen)
|
||||
print("%s\n", &p[i]);
|
||||
exits(nil);
|
||||
}
|
||||
|
||||
if(convaes && !keydbaes){
|
||||
char *s, *d;
|
||||
|
||||
keydboff = 8+16;
|
||||
keydblen += AESKEYLEN;
|
||||
len = keydboff + keydblen*nu;
|
||||
p = realloc(p, len);
|
||||
if(p == nil)
|
||||
error("out of memory");
|
||||
*db = p;
|
||||
s = p + KEYDBOFF + nu*KEYDBLEN;
|
||||
d = p + keydboff + nu*keydblen;
|
||||
for(i=0; i<nu; i++){
|
||||
s -= KEYDBLEN;
|
||||
d -= keydblen;
|
||||
memmove(d, s, KEYDBLEN);
|
||||
memset(d + KEYDBLEN, 0, keydblen-KEYDBLEN);
|
||||
}
|
||||
keydbaes = 1;
|
||||
}
|
||||
|
||||
randombytes((uchar*)p, keydboff);
|
||||
if(keydbaes){
|
||||
AESstate s;
|
||||
|
||||
memmove(p, "AES KEYS", 8);
|
||||
setupAESstate(&s, nkey.aes, AESKEYLEN, zeros);
|
||||
aesCBCencrypt((uchar*)p+8, len-8, &s);
|
||||
} else {
|
||||
DESstate s;
|
||||
uchar k[8];
|
||||
|
||||
des56to64((uchar*)nkey.des, k);
|
||||
setupDESstate(&s, k, zeros);
|
||||
desCBCencrypt((uchar*)p, len, &s);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: convkeys keyfile\n");
|
||||
fprint(2, "usage: %s [-pva] keyfile\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#pragma varargck type "W" char*
|
||||
|
||||
Authkey authkey;
|
||||
int keydbaes;
|
||||
uchar zeros[16];
|
||||
|
||||
typedef struct Fid Fid;
|
||||
typedef struct User User;
|
||||
|
@ -22,6 +24,7 @@ enum {
|
|||
Qroot,
|
||||
Quser,
|
||||
Qkey,
|
||||
Qaeskey,
|
||||
Qsecret,
|
||||
Qlog,
|
||||
Qstatus,
|
||||
|
@ -52,6 +55,7 @@ struct Fid {
|
|||
struct User {
|
||||
char *name;
|
||||
char key[DESKEYLEN];
|
||||
uchar aeskey[AESKEYLEN];
|
||||
char secret[SECRETLEN];
|
||||
ulong expire; /* 0 == never */
|
||||
uchar status;
|
||||
|
@ -68,6 +72,7 @@ char *qinfo[Qmax] = {
|
|||
[Qroot] "keys",
|
||||
[Quser] ".",
|
||||
[Qkey] "key",
|
||||
[Qaeskey] "aeskey",
|
||||
[Qsecret] "secret",
|
||||
[Qlog] "log",
|
||||
[Qexpire] "expire",
|
||||
|
@ -85,8 +90,7 @@ User *users[Nuser];
|
|||
char *userkeys;
|
||||
int nuser;
|
||||
ulong uniq = 1;
|
||||
Fcall rhdr,
|
||||
thdr;
|
||||
Fcall rhdr, thdr;
|
||||
int usepass;
|
||||
char *warnarg;
|
||||
uchar mdata[8192 + IOHDRSZ];
|
||||
|
@ -102,6 +106,7 @@ void insertuser(User*);
|
|||
void writeusers(void);
|
||||
void io(int, int);
|
||||
void *emalloc(ulong);
|
||||
char *estrdup(char*);
|
||||
Qid mkqid(User*, ulong);
|
||||
int dostat(User*, ulong, void*, int);
|
||||
int newkeys(void);
|
||||
|
@ -136,6 +141,12 @@ usage(void)
|
|||
exits("usage");
|
||||
}
|
||||
|
||||
static int
|
||||
haveaeskey(void)
|
||||
{
|
||||
return memcmp(authkey.aes, zeros, 16) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -169,11 +180,22 @@ main(int argc, char *argv[])
|
|||
if(pipe(p) < 0)
|
||||
error("can't make pipe: %r");
|
||||
|
||||
if(usepass) {
|
||||
if(usepass)
|
||||
getpass(&authkey, nil, 0, 0);
|
||||
} else {
|
||||
else {
|
||||
if(!getauthkey(&authkey))
|
||||
print("keyfs: warning: can't read NVRAM\n");
|
||||
fprint(2, "keyfs: warning: can't read NVRAM\n");
|
||||
}
|
||||
|
||||
keydbaes = 0;
|
||||
if(!newkeys() || !readusers()){
|
||||
if(!keydbaes)
|
||||
keydbaes = haveaeskey();
|
||||
else if(!haveaeskey()){
|
||||
fprint(2, "keyfs: no aes key in NVRAM\n");
|
||||
getpass(&authkey, nil, 0, 0);
|
||||
readusers();
|
||||
}
|
||||
}
|
||||
|
||||
switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
|
||||
|
@ -209,7 +231,7 @@ Attach(Fid *f)
|
|||
{
|
||||
if(f->busy)
|
||||
Clunk(f);
|
||||
f->user = 0;
|
||||
f->user = nil;
|
||||
f->qtype = Qroot;
|
||||
f->busy = 1;
|
||||
thdr.qid = mkqid(f->user, f->qtype);
|
||||
|
@ -272,7 +294,7 @@ Walk(Fid *f)
|
|||
if(strcmp(name, "..") == 0)
|
||||
goto Accept;
|
||||
user = finduser(name);
|
||||
if(!user)
|
||||
if(user == nil)
|
||||
goto Out;
|
||||
qtype = Quser;
|
||||
|
||||
|
@ -283,7 +305,7 @@ Walk(Fid *f)
|
|||
case Quser:
|
||||
if(strcmp(name, "..") == 0) {
|
||||
qtype = Qroot;
|
||||
user = 0;
|
||||
user = nil;
|
||||
goto Accept;
|
||||
}
|
||||
max = Qmax;
|
||||
|
@ -314,14 +336,16 @@ Walk(Fid *f)
|
|||
if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){
|
||||
nf->busy = 1;
|
||||
nf->qtype = qtype;
|
||||
if(nf->user = user)
|
||||
nf->user->ref++;
|
||||
nf->user = user;
|
||||
if(user != nil)
|
||||
user->ref++;
|
||||
}else if(nf == nil && rhdr.nwname > 0){ /* walk without clone (rare) */
|
||||
Clunk(f);
|
||||
f->busy = 1;
|
||||
f->qtype = qtype;
|
||||
if(f->user = user)
|
||||
f->user->ref++;
|
||||
f->user = user;
|
||||
if(user != nil)
|
||||
user->ref++;
|
||||
}
|
||||
|
||||
thdr.nwqid = i;
|
||||
|
@ -332,12 +356,12 @@ char *
|
|||
Clunk(Fid *f)
|
||||
{
|
||||
f->busy = 0;
|
||||
if(f->user && --f->user->ref == 0 && f->user->removed) {
|
||||
if(f->user != nil && --f->user->ref == 0 && f->user->removed) {
|
||||
free(f->user->name);
|
||||
free(f->user);
|
||||
}
|
||||
f->user = 0;
|
||||
return 0;
|
||||
f->user = nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
char *
|
||||
|
@ -350,6 +374,8 @@ Open(Fid *f)
|
|||
mode = rhdr.mode;
|
||||
if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
|
||||
return "user already exists";
|
||||
if(f->qtype == Qaeskey && !keydbaes)
|
||||
return "keyfile not in aes format";
|
||||
thdr.qid = mkqid(f->user, f->qtype);
|
||||
thdr.iounit = messagesize - IOHDRSZ;
|
||||
return 0;
|
||||
|
@ -364,7 +390,7 @@ Create(Fid *f)
|
|||
if(!f->busy)
|
||||
return "create of unused fid";
|
||||
name = rhdr.name;
|
||||
if(f->user){
|
||||
if(f->user != nil){
|
||||
return "permission denied";
|
||||
}else{
|
||||
perm = rhdr.perm;
|
||||
|
@ -374,7 +400,7 @@ Create(Fid *f)
|
|||
return "empty file name";
|
||||
if(strlen(name) >= Namelen)
|
||||
return "file name too long";
|
||||
if(finduser(name))
|
||||
if(finduser(name) != nil)
|
||||
return "user already exists";
|
||||
f->user = installuser(name);
|
||||
f->user->ref++;
|
||||
|
@ -404,7 +430,7 @@ Read(Fid *f)
|
|||
case Qroot:
|
||||
j = 0;
|
||||
for(i = 0; i < Nuser; i++)
|
||||
for(u = users[i]; u; j += m, u = u->link){
|
||||
for(u = users[i]; u != nil; j += m, u = u->link){
|
||||
m = dostat(u, Quser, data, n);
|
||||
if(m <= BIT16SZ)
|
||||
break;
|
||||
|
@ -431,19 +457,7 @@ Read(Fid *f)
|
|||
thdr.count = data - thdr.data;
|
||||
return 0;
|
||||
case Qkey:
|
||||
if(f->user->status != Sok)
|
||||
return "user disabled";
|
||||
if(f->user->purgatory > time(0))
|
||||
return "user in purgatory";
|
||||
if(f->user->expire != 0 && f->user->expire < time(0))
|
||||
return "user expired";
|
||||
if(off != 0)
|
||||
return 0;
|
||||
if(n > DESKEYLEN)
|
||||
n = DESKEYLEN;
|
||||
memmove(thdr.data, f->user->key, n);
|
||||
thdr.count = n;
|
||||
return 0;
|
||||
case Qaeskey:
|
||||
case Qsecret:
|
||||
if(f->user->status != Sok)
|
||||
return "user disabled";
|
||||
|
@ -451,57 +465,52 @@ Read(Fid *f)
|
|||
return "user in purgatory";
|
||||
if(f->user->expire != 0 && f->user->expire < time(0))
|
||||
return "user expired";
|
||||
if(off != 0)
|
||||
return 0;
|
||||
if(n > strlen(f->user->secret))
|
||||
n = strlen(f->user->secret);
|
||||
memmove(thdr.data, f->user->secret, n);
|
||||
m = 0;
|
||||
switch(f->qtype){
|
||||
case Qkey:
|
||||
data = f->user->key;
|
||||
m = DESKEYLEN;
|
||||
break;
|
||||
case Qaeskey:
|
||||
data = (char*)f->user->aeskey;
|
||||
m = AESKEYLEN;
|
||||
break;
|
||||
case Qsecret:
|
||||
data = f->user->secret;
|
||||
Readstr:
|
||||
m = strlen(data);
|
||||
break;
|
||||
}
|
||||
if(off >= m)
|
||||
n = 0;
|
||||
else {
|
||||
data += off;
|
||||
m -= off;
|
||||
if(n > m)
|
||||
n = m;
|
||||
}
|
||||
if(data != thdr.data)
|
||||
memmove(thdr.data, data, n);
|
||||
thdr.count = n;
|
||||
return 0;
|
||||
case Qstatus:
|
||||
if(off != 0){
|
||||
thdr.count = 0;
|
||||
return 0;
|
||||
}
|
||||
if(f->user->status == Sok && f->user->expire && f->user->expire < time(0))
|
||||
sprint(thdr.data, "expired\n");
|
||||
sprint(data, "expired\n");
|
||||
else
|
||||
sprint(thdr.data, "%s\n", status[f->user->status]);
|
||||
thdr.count = strlen(thdr.data);
|
||||
return 0;
|
||||
sprint(data, "%s\n", status[f->user->status]);
|
||||
goto Readstr;
|
||||
case Qexpire:
|
||||
if(off != 0){
|
||||
thdr.count = 0;
|
||||
return 0;
|
||||
}
|
||||
if(!f->user->expire)
|
||||
strcpy(data, "never\n");
|
||||
else
|
||||
sprint(data, "%lud\n", f->user->expire);
|
||||
if(n > strlen(data))
|
||||
n = strlen(data);
|
||||
thdr.count = n;
|
||||
return 0;
|
||||
goto Readstr;
|
||||
case Qlog:
|
||||
if(off != 0){
|
||||
thdr.count = 0;
|
||||
return 0;
|
||||
}
|
||||
sprint(data, "%lud\n", f->user->bad);
|
||||
if(n > strlen(data))
|
||||
n = strlen(data);
|
||||
thdr.count = n;
|
||||
return 0;
|
||||
goto Readstr;
|
||||
case Qwarnings:
|
||||
if(off != 0){
|
||||
thdr.count = 0;
|
||||
return 0;
|
||||
}
|
||||
sprint(data, "%ud\n", f->user->warnings);
|
||||
if(n > strlen(data))
|
||||
n = strlen(data);
|
||||
thdr.count = n;
|
||||
return 0;
|
||||
goto Readstr;
|
||||
default:
|
||||
return "permission denied: unknown qid";
|
||||
}
|
||||
|
@ -525,11 +534,17 @@ Write(Fid *f)
|
|||
memmove(f->user->key, data, DESKEYLEN);
|
||||
thdr.count = DESKEYLEN;
|
||||
break;
|
||||
case Qaeskey:
|
||||
if(n != AESKEYLEN)
|
||||
return "garbled write data";
|
||||
memmove(f->user->aeskey, data, AESKEYLEN);
|
||||
thdr.count = AESKEYLEN;
|
||||
break;
|
||||
case Qsecret:
|
||||
if(n >= SECRETLEN)
|
||||
return "garbled write data";
|
||||
memmove(f->user->secret, data, n);
|
||||
f->user->secret[n] = 0;
|
||||
f->user->secret[n] = '\0';
|
||||
thdr.count = n;
|
||||
break;
|
||||
case Qstatus:
|
||||
|
@ -639,9 +654,7 @@ Wstat(Fid *f)
|
|||
if(!removeuser(f->user))
|
||||
return "user previously removed";
|
||||
free(f->user->name);
|
||||
f->user->name = strdup(d.name);
|
||||
if(f->user->name == nil)
|
||||
error("wstat: malloc failed: %r");
|
||||
f->user->name = estrdup(d.name);
|
||||
insertuser(f->user);
|
||||
writeusers();
|
||||
return 0;
|
||||
|
@ -683,17 +696,6 @@ dostat(User *user, ulong qtype, void *p, int n)
|
|||
return convD2M(&d, p, n);
|
||||
}
|
||||
|
||||
int
|
||||
passline(Biobuf *b, void *vbuf)
|
||||
{
|
||||
char *buf = vbuf;
|
||||
|
||||
if(Bread(b, buf, KEYDBLEN) != KEYDBLEN)
|
||||
return 0;
|
||||
decrypt(authkey.des, buf, KEYDBLEN);
|
||||
buf[Namelen-1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
randombytes(uchar *p, int len)
|
||||
|
@ -712,58 +714,36 @@ randombytes(uchar *p, int len)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
oldCBCencrypt(char *key7, uchar *p, int len)
|
||||
{
|
||||
uchar ivec[8];
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
memset(ivec, 0, 8);
|
||||
des56to64((uchar*)key7, key);
|
||||
setupDESstate(&s, key, ivec);
|
||||
desCBCencrypt((uchar*)p, len, &s);
|
||||
}
|
||||
|
||||
void
|
||||
oldCBCdecrypt(char *key7, uchar *p, int len)
|
||||
{
|
||||
uchar ivec[8];
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
memset(ivec, 0, 8);
|
||||
des56to64((uchar*)key7, key);
|
||||
setupDESstate(&s, key, ivec);
|
||||
desCBCdecrypt((uchar*)p, len, &s);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
writeusers(void)
|
||||
{
|
||||
int keydblen, keydboff;
|
||||
int fd, i, nu;
|
||||
User *u;
|
||||
uchar *p, *buf;
|
||||
ulong expire;
|
||||
|
||||
/* what format to use */
|
||||
keydblen = KEYDBLEN;
|
||||
keydboff = KEYDBOFF;
|
||||
if(keydbaes){
|
||||
keydblen += AESKEYLEN;
|
||||
keydboff = 8+16; /* segnature[8] + iv[16] */
|
||||
}
|
||||
|
||||
/* count users */
|
||||
nu = 0;
|
||||
for(i = 0; i < Nuser; i++)
|
||||
for(u = users[i]; u; u = u->link)
|
||||
for(u = users[i]; u != nil; u = u->link)
|
||||
nu++;
|
||||
|
||||
/* pack into buffer */
|
||||
buf = malloc(KEYDBOFF + nu*KEYDBLEN);
|
||||
if(buf == 0){
|
||||
fprint(2, "keyfs: can't write keys file, out of memory\n");
|
||||
return;
|
||||
}
|
||||
buf = emalloc(keydboff + nu*keydblen);
|
||||
p = buf;
|
||||
randombytes(p, KEYDBOFF);
|
||||
p += KEYDBOFF;
|
||||
randombytes(p, keydboff);
|
||||
p += keydboff;
|
||||
for(i = 0; i < Nuser; i++)
|
||||
for(u = users[i]; u; u = u->link){
|
||||
for(u = users[i]; u != nil; u = u->link){
|
||||
strncpy((char*)p, u->name, Namelen);
|
||||
p += Namelen;
|
||||
memmove(p, u->key, DESKEYLEN);
|
||||
|
@ -777,10 +757,27 @@ writeusers(void)
|
|||
*p++ = expire >> 24;
|
||||
memmove(p, u->secret, SECRETLEN);
|
||||
p += SECRETLEN;
|
||||
if(keydbaes){
|
||||
memmove(p, u->aeskey, AESKEYLEN);
|
||||
p += AESKEYLEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt */
|
||||
oldCBCencrypt(authkey.des, buf, p - buf);
|
||||
if(keydbaes){
|
||||
AESstate s;
|
||||
|
||||
memmove(buf, "AES KEYS", 8);
|
||||
setupAESstate(&s, authkey.aes, AESKEYLEN, zeros);
|
||||
aesCBCencrypt(buf+8, (p - (buf+8)), &s);
|
||||
} else {
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
des56to64((uchar*)authkey.des, key);
|
||||
setupDESstate(&s, key, zeros);
|
||||
desCBCencrypt(buf, p - buf, &s);
|
||||
}
|
||||
|
||||
/* write file */
|
||||
fd = create(userkeys, OWRITE, 0660);
|
||||
|
@ -858,6 +855,7 @@ userok(char *user, int nu)
|
|||
int
|
||||
readusers(void)
|
||||
{
|
||||
int keydblen, keydboff;
|
||||
int fd, i, n, nu;
|
||||
uchar *p, *buf, *ep;
|
||||
User *u;
|
||||
|
@ -872,12 +870,7 @@ readusers(void)
|
|||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
buf = malloc(d->length);
|
||||
if(buf == 0){
|
||||
close(fd);
|
||||
free(d);
|
||||
return 0;
|
||||
}
|
||||
buf = emalloc(d->length);
|
||||
n = readn(fd, buf, d->length);
|
||||
close(fd);
|
||||
free(d);
|
||||
|
@ -886,18 +879,41 @@ readusers(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
keydblen = KEYDBLEN;
|
||||
keydboff = KEYDBOFF;
|
||||
keydbaes = n > 24 && memcmp(buf, "AES KEYS", 8) == 0;
|
||||
|
||||
/* decrypt */
|
||||
n -= n % KEYDBLEN;
|
||||
oldCBCdecrypt(authkey.des, buf, n);
|
||||
if(keydbaes){
|
||||
AESstate s;
|
||||
|
||||
/* make sure we have AES encryption key */
|
||||
if(!haveaeskey()){
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
keydblen += AESKEYLEN;
|
||||
keydboff = 8+16; /* signature[8] + iv[16] */
|
||||
setupAESstate(&s, authkey.aes, AESKEYLEN, zeros);
|
||||
aesCBCdecrypt(buf+8, n-8, &s);
|
||||
} else {
|
||||
uchar key[8];
|
||||
DESstate s;
|
||||
|
||||
des56to64((uchar*)authkey.des, key);
|
||||
setupDESstate(&s, key, zeros);
|
||||
desCBCdecrypt(buf, n, &s);
|
||||
}
|
||||
|
||||
/* unpack */
|
||||
nu = 0;
|
||||
for(i = KEYDBOFF; i < n; i += KEYDBLEN){
|
||||
ep = buf + i;
|
||||
if(userok((char*)ep, i/KEYDBLEN) < 0)
|
||||
n = (n - keydboff) / keydblen;
|
||||
ep = buf + keydboff;
|
||||
for(i = 0; i < n; ep += keydblen, i++){
|
||||
if(userok((char*)ep, i) < 0)
|
||||
continue;
|
||||
u = finduser((char*)ep);
|
||||
if(u == 0)
|
||||
if(u == nil)
|
||||
u = installuser((char*)ep);
|
||||
memmove(u->key, ep + Namelen, DESKEYLEN);
|
||||
p = ep + Namelen + DESKEYLEN;
|
||||
|
@ -909,11 +925,14 @@ readusers(void)
|
|||
p += 4;
|
||||
memmove(u->secret, p, SECRETLEN);
|
||||
u->secret[SECRETLEN-1] = 0;
|
||||
p += SECRETLEN;
|
||||
if(keydbaes)
|
||||
memmove(u->aeskey, p, AESKEYLEN);
|
||||
nu++;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
print("%d keys read\n", nu);
|
||||
print("%d keys read in %s foarmat\n", nu, keydbaes ? "AES" : "DES");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -925,9 +944,7 @@ installuser(char *name)
|
|||
|
||||
h = hash(name);
|
||||
u = emalloc(sizeof *u);
|
||||
u->name = strdup(name);
|
||||
if(u->name == nil)
|
||||
error("malloc failed: %r");
|
||||
u->name = estrdup(name);
|
||||
u->removed = 0;
|
||||
u->ref = 0;
|
||||
u->purgatory = 0;
|
||||
|
@ -946,10 +963,10 @@ finduser(char *name)
|
|||
{
|
||||
User *u;
|
||||
|
||||
for(u = users[hash(name)]; u; u = u->link)
|
||||
for(u = users[hash(name)]; u != nil; u = u->link)
|
||||
if(strcmp(name, u->name) == 0)
|
||||
return u;
|
||||
return 0;
|
||||
return nil;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -961,7 +978,7 @@ removeuser(User *user)
|
|||
user->removed = 1;
|
||||
name = user->name;
|
||||
last = &users[hash(name)];
|
||||
for(u = *last; u; u = *last){
|
||||
for(u = *last; u != nil; u = *last){
|
||||
if(strcmp(name, u->name) == 0){
|
||||
*last = u->link;
|
||||
return 1;
|
||||
|
@ -998,20 +1015,20 @@ findfid(int fid)
|
|||
{
|
||||
Fid *f, *ff;
|
||||
|
||||
ff = 0;
|
||||
for(f = fids; f; f = f->next)
|
||||
ff = nil;
|
||||
for(f = fids; f != nil; f = f->next)
|
||||
if(f->fid == fid)
|
||||
return f;
|
||||
else if(!ff && !f->busy)
|
||||
ff = f;
|
||||
if(ff){
|
||||
if(ff != nil){
|
||||
ff->fid = fid;
|
||||
return ff;
|
||||
}
|
||||
f = emalloc(sizeof *f);
|
||||
f->fid = fid;
|
||||
f->busy = 0;
|
||||
f->user = 0;
|
||||
f->user = nil;
|
||||
f->next = fids;
|
||||
fids = f;
|
||||
return f;
|
||||
|
@ -1088,10 +1105,24 @@ emalloc(ulong n)
|
|||
{
|
||||
void *p;
|
||||
|
||||
if(p = malloc(n))
|
||||
if((p = malloc(n)) != nil){
|
||||
memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
error("out of memory");
|
||||
return 0; /* not reached */
|
||||
return nil; /* not reached */
|
||||
}
|
||||
|
||||
char *
|
||||
estrdup(char *s)
|
||||
{
|
||||
char *d;
|
||||
int n;
|
||||
|
||||
n = strlen(s)+1;
|
||||
d = emalloc(n);
|
||||
memmove(d, s, n);
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
#include "authcmdlib.h"
|
||||
|
||||
static int
|
||||
getkey(char *authkey)
|
||||
getkey(Authkey *authkey)
|
||||
{
|
||||
Nvrsafe safe;
|
||||
|
||||
if(readnvram(&safe, 0) < 0)
|
||||
return -1;
|
||||
memmove(authkey, safe.machkey, DESKEYLEN);
|
||||
memmove(authkey->des, safe.machkey, DESKEYLEN);
|
||||
memmove(authkey->aes, safe.aesmachkey, AESKEYLEN);
|
||||
memset(&safe, 0, sizeof safe);
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,7 +21,7 @@ int
|
|||
getauthkey(Authkey *authkey)
|
||||
{
|
||||
memset(authkey, 0, sizeof(Authkey));
|
||||
if(getkey(authkey->des) == 0)
|
||||
if(getkey(authkey) == 0)
|
||||
return 1;
|
||||
print("can't read NVRAM, please enter machine key\n");
|
||||
getpass(authkey, nil, 0, 1);
|
||||
|
|
|
@ -22,15 +22,12 @@ getpass(Authkey *key, char *pass, int check, int confirm)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if(!passtokey(key, pass)){
|
||||
print("bad password, try again\n");
|
||||
continue;
|
||||
}
|
||||
if(check)
|
||||
if(err = okpasswd(pass)){
|
||||
print("%s, try again\n", err);
|
||||
continue;
|
||||
}
|
||||
passtokey(key, pass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <authsrv.h>
|
||||
#include <libsec.h>
|
||||
|
||||
int
|
||||
passtokey(Authkey *key, char *p)
|
||||
static void
|
||||
passtodeskey(char *key, char *p)
|
||||
{
|
||||
uchar buf[ANAMELEN], *t;
|
||||
int i, n;
|
||||
|
@ -15,18 +16,33 @@ passtokey(Authkey *key, char *p)
|
|||
t = buf;
|
||||
strncpy((char*)t, p, n);
|
||||
t[n] = 0;
|
||||
memset(key, 0, sizeof(Authkey));
|
||||
memset(key, 0, DESKEYLEN);
|
||||
for(;;){
|
||||
for(i = 0; i < DESKEYLEN; i++)
|
||||
key->des[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
|
||||
key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
|
||||
if(n <= 8)
|
||||
return 1;
|
||||
return;
|
||||
n -= 8;
|
||||
t += 8;
|
||||
if(n < 8){
|
||||
t -= 8 - n;
|
||||
n = 8;
|
||||
}
|
||||
encrypt(key->des, t, 8);
|
||||
encrypt(key, t, 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
passtoaeskey(uchar *key, char *p)
|
||||
{
|
||||
static char salt[] = "Plan 9 key derivation";
|
||||
pbkdf2_hmac_sha1((uchar*)p, strlen(p), (uchar*)salt, sizeof(salt)-1, 9001, key, AESKEYLEN);
|
||||
}
|
||||
|
||||
void
|
||||
passtokey(Authkey *key, char *p)
|
||||
{
|
||||
memset(key, 0, sizeof(Authkey));
|
||||
passtodeskey(key->des, p);
|
||||
passtoaeskey(key->aes, p);
|
||||
}
|
||||
|
|
|
@ -268,13 +268,22 @@ readnvram(Nvrsafe *safep, int flag)
|
|||
|
||||
/* verify data read */
|
||||
err |= check(safe->machkey, DESKEYLEN, safe->machsum,
|
||||
"bad nvram key");
|
||||
// err |= check(safe->config, CONFIGLEN, safe->configsum,
|
||||
// "bad secstore key");
|
||||
"bad nvram des key");
|
||||
err |= check(safe->authid, ANAMELEN, safe->authidsum,
|
||||
"bad authentication id");
|
||||
err |= check(safe->authdom, DOMLEN, safe->authdomsum,
|
||||
"bad authentication domain");
|
||||
if(0){
|
||||
err |= check(safe->config, CONFIGLEN, safe->configsum,
|
||||
"bad secstore key");
|
||||
err |= check(safe->aesmachkey, AESKEYLEN, safe->aesmachsum,
|
||||
"bad nvram aes key");
|
||||
} else {
|
||||
if(nvcsum(safe->config, CONFIGLEN) != safe->configsum)
|
||||
memset(safe->config, 0, CONFIGLEN);
|
||||
if(nvcsum(safe->aesmachkey, AESKEYLEN) != safe->aesmachsum)
|
||||
memset(safe->aesmachkey, 0, AESKEYLEN);
|
||||
}
|
||||
if(err == 0)
|
||||
if(safe->authid[0]==0 || safe->authdom[0]==0){
|
||||
fprint(2, "empty nvram authid or authdom\n");
|
||||
|
@ -296,18 +305,19 @@ readnvram(Nvrsafe *safep, int flag)
|
|||
|
||||
if(readcons("password", nil, 1, in, sizeof in) == nil)
|
||||
goto Out;
|
||||
if(passtokey(&k, in)){
|
||||
memmove(safe->machkey, k.des, DESKEYLEN);
|
||||
break;
|
||||
}
|
||||
passtokey(&k, in);
|
||||
memmove(safe->machkey, k.des, DESKEYLEN);
|
||||
memmove(safe->aesmachkey, k.aes, AESKEYLEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// safe->authsum = nvcsum(safe->authkey, DESKEYLEN);
|
||||
safe->machsum = nvcsum(safe->machkey, DESKEYLEN);
|
||||
// safe->authsum = nvcsum(safe->authkey, DESKEYLEN);
|
||||
safe->configsum = nvcsum(safe->config, CONFIGLEN);
|
||||
safe->authidsum = nvcsum(safe->authid, sizeof safe->authid);
|
||||
safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom);
|
||||
safe->aesmachsum = nvcsum(safe->aesmachkey, AESKEYLEN);
|
||||
|
||||
*(Nvrsafe*)buf = *safe;
|
||||
if(loc.fd < 0
|
||||
|
|
Loading…
Reference in a new issue