|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <mp.h> | 
|  | #include <libsec.h> | 
|  | #include <auth.h> | 
|  | #include <thread.h> | 
|  | #include <9pclient.h> | 
|  | #include <bio.h> | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: 9 dsasign [-i id] [-v] key <data\n"); | 
|  | threadexitsall("usage"); | 
|  | } | 
|  |  | 
|  | static void doVerify(void); | 
|  | static char *getline(int*); | 
|  |  | 
|  | char *id; | 
|  | Biobuf b; | 
|  | int nid; | 
|  | char *key; | 
|  |  | 
|  | void | 
|  | threadmain(int argc, char **argv) | 
|  | { | 
|  | int n, verify; | 
|  | char *text, *p; | 
|  | uchar digest[SHA1dlen]; | 
|  | AuthRpc *rpc; | 
|  | Fmt fmt; | 
|  |  | 
|  | fmtinstall('[', encodefmt); | 
|  | fmtinstall('H', encodefmt); | 
|  |  | 
|  | verify = 0; | 
|  | id = ""; | 
|  | ARGBEGIN{ | 
|  | case 'i': | 
|  | id = EARGF(usage()); | 
|  | break; | 
|  | case 'v': | 
|  | verify = 1; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | }ARGEND | 
|  |  | 
|  | if(argc != 1) | 
|  | usage(); | 
|  | key = argv[0]; | 
|  | nid = strlen(id); | 
|  |  | 
|  | Binit(&b, 0, OREAD); | 
|  | if(verify) { | 
|  | doVerify(); | 
|  | threadexitsall(nil); | 
|  | } | 
|  |  | 
|  | if((rpc = auth_allocrpc()) == nil){ | 
|  | fprint(2, "dsasign: auth_allocrpc: %r\n"); | 
|  | threadexits("rpc"); | 
|  | } | 
|  | key = smprint("proto=dsa role=sign %s", key); | 
|  | if(auth_rpc(rpc, "start", key, strlen(key)) != ARok){ | 
|  | fprint(2, "dsasign: auth 'start' failed: %r\n"); | 
|  | auth_freerpc(rpc); | 
|  | threadexits("rpc"); | 
|  | } | 
|  |  | 
|  | print("+%s\n", id); | 
|  |  | 
|  | Binit(&b, 0, OREAD); | 
|  | fmtstrinit(&fmt); | 
|  | while((p = getline(&n)) != nil) { | 
|  | if(p[0] == '-' || p[0] == '+') | 
|  | print("+"); | 
|  | print("%s\n", p); | 
|  | fmtprint(&fmt, "%s\n", p); | 
|  | } | 
|  | text = fmtstrflush(&fmt); | 
|  | sha1((uchar*)text, strlen(text), digest, nil); | 
|  |  | 
|  | if(auth_rpc(rpc, "write", digest, SHA1dlen) != ARok) | 
|  | sysfatal("auth write in sign failed: %r"); | 
|  | if(auth_rpc(rpc, "read", nil, 0) != ARok) | 
|  | sysfatal("auth read in sign failed: %r"); | 
|  |  | 
|  | print("-%s %.*H\n", id, rpc->narg, rpc->arg); | 
|  | threadexits(nil); | 
|  | } | 
|  |  | 
|  | static mpint* | 
|  | keytomp(Attr *a, char *name) | 
|  | { | 
|  | char *p; | 
|  | mpint *m; | 
|  |  | 
|  | p = _strfindattr(a, name); | 
|  | if(p == nil) | 
|  | sysfatal("missing key attribute %s", name); | 
|  | m = strtomp(p, nil, 16, nil); | 
|  | if(m == nil) | 
|  | sysfatal("malformed key attribute %s=%s", name, p); | 
|  | return m; | 
|  | } | 
|  |  | 
|  | static void | 
|  | doVerify(void) | 
|  | { | 
|  | char *p; | 
|  | int n, nsig; | 
|  | Fmt fmt; | 
|  | uchar digest[SHA1dlen], sig[1024]; | 
|  | char *text; | 
|  | Attr *a; | 
|  | DSAsig dsig; | 
|  | DSApub dkey; | 
|  |  | 
|  | a = _parseattr(key); | 
|  | if(a == nil) | 
|  | sysfatal("invalid key"); | 
|  | dkey.alpha = keytomp(a, "alpha"); | 
|  | dkey.key = keytomp(a, "key"); | 
|  | dkey.p = keytomp(a, "p"); | 
|  | dkey.q = keytomp(a, "q"); | 
|  | if(!probably_prime(dkey.p, 20) && !probably_prime(dkey.q, 20)) | 
|  | sysfatal("p or q not prime"); | 
|  |  | 
|  | while((p = getline(&n)) != nil) | 
|  | if(p[0] == '+' && strcmp(p+1, id) == 0) | 
|  | goto start; | 
|  | sysfatal("no message found"); | 
|  |  | 
|  | start: | 
|  | fmtstrinit(&fmt); | 
|  | while((p = getline(&n)) != nil) { | 
|  | if(n >= 1+nid+1+16 && p[0] == '-' && strncmp(p+1, id, nid) == 0 && p[1+nid] == ' ') { | 
|  | if((nsig = dec16(sig, sizeof sig, p+1+nid+1, n-(1+nid+1))) != 20+20) | 
|  | sysfatal("malformed signture"); | 
|  | goto end; | 
|  | } | 
|  | if(p[0] == '+') | 
|  | p++; | 
|  | fmtprint(&fmt, "%s\n", p); | 
|  | } | 
|  | sysfatal("did not find end of message"); | 
|  | return; // silence clang warning | 
|  |  | 
|  | end: | 
|  | text = fmtstrflush(&fmt); | 
|  | sha1((uchar*)text, strlen(text), digest, nil); | 
|  |  | 
|  | if(nsig != 40) | 
|  | sysfatal("malformed signature"); | 
|  | dsig.r = betomp(sig, 20, nil); | 
|  | dsig.s = betomp(sig+20, 20, nil); | 
|  |  | 
|  | if(dsaverify(&dkey, &dsig, betomp(digest, sizeof digest, nil)) < 0) | 
|  | sysfatal("signature failed to verify: %r"); | 
|  |  | 
|  | write(1, text, strlen(text)); | 
|  | threadexitsall(0); | 
|  | } | 
|  |  | 
|  | char* | 
|  | getline(int *np) | 
|  | { | 
|  | char *p; | 
|  | int n; | 
|  |  | 
|  | if((p = Brdline(&b, '\n')) == nil) | 
|  | return nil; | 
|  | n = Blinelen(&b); | 
|  | while(n > 0 && (p[n-1] == '\n' || p[n-1] == ' ' || p[n-1] == '\t')) | 
|  | n--; | 
|  | p[n] = '\0'; | 
|  | *np = n; | 
|  | return p; | 
|  | } |