URI:
       tp9sk1.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tp9sk1.c (7389B)
       ---
            1 /*
            2  * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
            3  * p9sk2 is an incomplete flawed variant of p9sk1.
            4  *
            5  * Client protocol:
            6  *        write challenge[challen]        (p9sk1 only)
            7  *        read tickreq[tickreqlen]
            8  *        write ticket[ticketlen]
            9  *        read authenticator[authentlen]
           10  *
           11  * Server protocol:
           12  *         read challenge[challen]        (p9sk1 only)
           13  *        write tickreq[tickreqlen]
           14  *        read ticket[ticketlen]
           15  *        write authenticator[authentlen]
           16  */
           17 
           18 #include "std.h"
           19 #include "dat.h"
           20 
           21 extern Proto p9sk1, p9sk2;
           22 static int gettickets(Ticketreq*, char*, Key*);
           23 
           24 #define max(a, b) ((a) > (b) ? (a) : (b))
           25 enum
           26 {
           27         MAXAUTH = max(TICKREQLEN, TICKETLEN+max(TICKETLEN, AUTHENTLEN))
           28 };
           29 
           30 static int
           31 p9skclient(Conv *c)
           32 {
           33         char *user;
           34         char cchal[CHALLEN];
           35         uchar secret[8];
           36         char buf[MAXAUTH];
           37         int speakfor, ret;
           38         Attr *a;
           39         Authenticator au;
           40         Key *k;
           41         Ticket t;
           42         Ticketreq tr;
           43 
           44         ret = -1;
           45         a = nil;
           46         k = nil;
           47 
           48         /* p9sk1: send client challenge */
           49         if(c->proto == &p9sk1){
           50                 c->state = "write challenge";
           51                 memrandom(cchal, CHALLEN);
           52                 if(convwrite(c, cchal, CHALLEN) < 0)
           53                         goto out;
           54         }
           55 
           56         /* read ticket request */
           57         c->state = "read tickreq";
           58         if(convread(c, buf, TICKREQLEN) < 0)
           59                 goto out;
           60         convM2TR(buf, &tr);
           61 
           62         /* p9sk2: use server challenge as client challenge */
           63         if(c->proto == &p9sk2)
           64                 memmove(cchal, tr.chal, CHALLEN);
           65 
           66         /*
           67          * find a key.
           68          *
           69          * if the user is the factotum owner, any key will do.
           70          * if not, then if we have a speakfor key,
           71          * we will only vouch for the user's local identity.
           72          *
           73          * this logic is duplicated in p9any.c
           74          */
           75         user = strfindattr(c->attr, "user");
           76         a = delattr(copyattr(c->attr), "role");
           77         a = addattr(a, "proto=p9sk1");
           78 
           79         if(strcmp(c->sysuser, owner) == 0){
           80                 speakfor = 0;
           81                 a = addattr(a, "proto=p9sk1 user? dom=%q", tr.authdom);
           82         }else if(user==nil || strcmp(c->sysuser, user)==0){
           83                 speakfor = 1;
           84                 a = delattr(a, "user");
           85                 a = addattr(a, "proto=p9sk1 user? dom=%q role=speakfor", tr.authdom);
           86         }else{
           87                 werrstr("will not authenticate for %q as %q", c->sysuser, user);
           88                 goto out;
           89         }
           90 
           91         for(;;){
           92                 c->state = "find key";
           93                 k = keyfetch(c, "%A", a);
           94                 if(k == nil)
           95                         goto out;
           96 
           97                 /* relay ticket request to auth server, get tickets */
           98                 strcpy(tr.hostid, strfindattr(k->attr, "user"));
           99                 if(speakfor)
          100                         strcpy(tr.uid, c->sysuser);
          101                 else
          102                         strcpy(tr.uid, tr.hostid);
          103 
          104                 c->state = "get tickets";
          105                 if(gettickets(&tr, buf, k) < 0)
          106                         goto out;
          107 
          108                 convM2T(buf, &t, k->priv);
          109                 if(t.num == AuthTc)
          110                         break;
          111 
          112                 /* we don't agree with the auth server about the key; try again */
          113                 c->state = "replace key";
          114                 if((k = keyreplace(c, k, "key mismatch with auth server")) == nil){
          115                         werrstr("key mismatch with auth server");
          116                         goto out;
          117                 }
          118         }
          119 
          120         /* send second ticket and authenticator to server */
          121         c->state = "write ticket+auth";
          122         memmove(buf, buf+TICKETLEN, TICKETLEN);
          123         au.num = AuthAc;
          124         memmove(au.chal, tr.chal, CHALLEN);
          125         au.id = 0;
          126         convA2M(&au, buf+TICKETLEN, t.key);
          127         if(convwrite(c, buf, TICKETLEN+AUTHENTLEN) < 0)
          128                 goto out;
          129 
          130         /* read authenticator from server */
          131         c->state = "read auth";
          132         if(convread(c, buf, AUTHENTLEN) < 0)
          133                 goto out;
          134         convM2A(buf, &au, t.key);
          135         if(au.num != AuthAs || memcmp(au.chal, cchal, CHALLEN) != 0 || au.id != 0){
          136                 werrstr("server lies through his teeth");
          137                 goto out;
          138         }
          139 
          140         /* success */
          141         c->attr = addcap(c->attr, c->sysuser, &t);
          142         flog("p9skclient success %A", c->attr);        /* before adding secret! */
          143         des56to64((uchar*)t.key, secret);
          144         c->attr = addattr(c->attr, "secret=%.8H", secret);
          145         ret = 0;
          146 
          147 out:
          148         if(ret < 0)
          149                 flog("p9skclient: %r");
          150         freeattr(a);
          151         keyclose(k);
          152         return ret;
          153 }
          154 
          155 static int
          156 p9skserver(Conv *c)
          157 {
          158         char cchal[CHALLEN], buf[MAXAUTH];
          159         uchar secret[8];
          160         int ret;
          161         Attr *a;
          162         Authenticator au;
          163         Key *k;
          164         Ticketreq tr;
          165         Ticket t;
          166 
          167         ret = -1;
          168 
          169         a = addattr(copyattr(c->attr), "user? dom?");
          170         a = addattr(a, "user? dom? proto=p9sk1");
          171         if((k = keyfetch(c, "%A", a)) == nil)
          172                 goto out;
          173 
          174         /* p9sk1: read client challenge */
          175         if(c->proto == &p9sk1){
          176                 if(convread(c, cchal, CHALLEN) < 0)
          177                         goto out;
          178         }
          179 
          180         /* send ticket request */
          181         memset(&tr, 0, sizeof tr);
          182         tr.type = AuthTreq;
          183         strcpy(tr.authid, strfindattr(k->attr, "user"));
          184         strcpy(tr.authdom, strfindattr(k->attr, "dom"));
          185         memrandom(tr.chal, sizeof tr.chal);
          186         convTR2M(&tr, buf);
          187         if(convwrite(c, buf, TICKREQLEN) < 0)
          188                 goto out;
          189 
          190         /* p9sk2: use server challenge as client challenge */
          191         if(c->proto == &p9sk2)
          192                 memmove(cchal, tr.chal, sizeof tr.chal);
          193 
          194         /* read ticket+authenticator */
          195         if(convread(c, buf, TICKETLEN+AUTHENTLEN) < 0)
          196                 goto out;
          197 
          198         convM2T(buf, &t, k->priv);
          199         if(t.num != AuthTs || memcmp(t.chal, tr.chal, CHALLEN) != 0){
          200                 /* BUG badkey */
          201                 werrstr("key mismatch with auth server");
          202                 goto out;
          203         }
          204 
          205         convM2A(buf+TICKETLEN, &au, t.key);
          206         if(au.num != AuthAc || memcmp(au.chal, tr.chal, CHALLEN) != 0 || au.id != 0){
          207                 werrstr("client lies through his teeth");
          208                 goto out;
          209         }
          210 
          211         /* send authenticator */
          212         au.num = AuthAs;
          213         memmove(au.chal, cchal, CHALLEN);
          214         convA2M(&au, buf, t.key);
          215         if(convwrite(c, buf, AUTHENTLEN) < 0)
          216                 goto out;
          217 
          218         /* success */
          219         c->attr = addcap(c->attr, c->sysuser, &t);
          220         flog("p9skserver success %A", c->attr);        /* before adding secret! */
          221         des56to64((uchar*)t.key, secret);
          222         c->attr = addattr(c->attr, "secret=%.8H", secret);
          223         ret = 0;
          224 
          225 out:
          226         if(ret < 0)
          227                 flog("p9skserver: %r");
          228         freeattr(a);
          229         keyclose(k);
          230         return ret;
          231 }
          232 
          233 int
          234 _asgetticket(int fd, char *trbuf, char *tbuf)
          235 {
          236         if(write(fd, trbuf, TICKREQLEN) < 0){
          237                 close(fd);
          238                 return -1;
          239         }
          240         return _asrdresp(fd, tbuf, 2*TICKETLEN);
          241 }
          242 static int
          243 getastickets(Ticketreq *tr, char *buf)
          244 {
          245         int asfd;
          246         int ret;
          247 
          248         if((asfd = xioauthdial(nil, tr->authdom)) < 0)
          249                 return -1;
          250         convTR2M(tr, buf);
          251         ret = xioasgetticket(asfd, buf, buf);
          252         xioclose(asfd);
          253         return ret;
          254 }
          255 
          256 static int
          257 mktickets(Ticketreq *tr, char *buf, Key *k)
          258 {
          259         Ticket t;
          260 
          261         if(strcmp(tr->authid, tr->hostid) != 0)
          262                 return -1;
          263 
          264         memset(&t, 0, sizeof t);
          265         memmove(t.chal, tr->chal, CHALLEN);
          266         strcpy(t.cuid, tr->uid);
          267         strcpy(t.suid, tr->uid);
          268         memrandom(t.key, DESKEYLEN);
          269         t.num = AuthTc;
          270         convT2M(&t, buf, k->priv);
          271         t.num = AuthTs;
          272         convT2M(&t, buf+TICKETLEN, k->priv);
          273         return 0;
          274 }
          275 
          276 static int
          277 gettickets(Ticketreq *tr, char *buf, Key *k)
          278 {
          279         if(getastickets(tr, buf) == 0)
          280                 return 0;
          281         if(mktickets(tr, buf, k) == 0)
          282                 return 0;
          283         werrstr("gettickets: %r");
          284         return -1;
          285 }
          286 
          287 static int
          288 p9sk1check(Key *k)
          289 {
          290         char *user, *dom, *pass;
          291         Ticketreq tr;
          292 
          293         user = strfindattr(k->attr, "user");
          294         dom = strfindattr(k->attr, "dom");
          295         if(user==nil || dom==nil){
          296                 werrstr("need user and dom attributes");
          297                 return -1;
          298         }
          299         if(strlen(user) >= sizeof tr.authid){
          300                 werrstr("user name too long");
          301                 return -1;
          302         }
          303         if(strlen(dom) >= sizeof tr.authdom){
          304                 werrstr("auth dom name too long");
          305                 return -1;
          306         }
          307 
          308         k->priv = emalloc(DESKEYLEN);
          309         if(pass = strfindattr(k->privattr, "!password"))
          310                 passtokey(k->priv, pass);
          311         else if(pass = strfindattr(k->privattr, "!hex")){
          312                 if(hexparse(pass, k->priv, 7) < 0){
          313                         werrstr("malformed !hex key data");
          314                         return -1;
          315                 }
          316         }else{
          317                 werrstr("need !password or !hex attribute");
          318                 return -1;
          319         }
          320 
          321         return 0;
          322 }
          323 
          324 static void
          325 p9sk1close(Key *k)
          326 {
          327         free(k->priv);
          328         k->priv = nil;
          329 }
          330 
          331 static Role
          332 p9sk1roles[] =
          333 {
          334         "client",        p9skclient,
          335         "server",        p9skserver,
          336         0
          337 };
          338 
          339 static Role
          340 p9sk2roles[] =
          341 {
          342         "client",        p9skclient,
          343         "server",        p9skserver,
          344         0
          345 };
          346 
          347 Proto p9sk1 = {
          348         "p9sk1",
          349         p9sk1roles,
          350         "user? dom? !password?",
          351         p9sk1check,
          352         p9sk1close
          353 };
          354 
          355 Proto p9sk2 = {
          356         "p9sk2",
          357         p9sk2roles
          358 };