dsasign.c (3478B)
1 #include <u.h> 2 #include <libc.h> 3 #include <mp.h> 4 #include <libsec.h> 5 #include <auth.h> 6 #include <thread.h> 7 #include <9pclient.h> 8 #include <bio.h> 9 10 void 11 usage(void) 12 { 13 fprint(2, "usage: 9 dsasign [-i id] [-v] key <data\n"); 14 threadexitsall("usage"); 15 } 16 17 static void doVerify(void); 18 static char *getline(int*); 19 20 char *id; 21 Biobuf b; 22 int nid; 23 char *key; 24 25 void 26 threadmain(int argc, char **argv) 27 { 28 int n, verify; 29 char *text, *p; 30 uchar digest[SHA1dlen]; 31 AuthRpc *rpc; 32 Fmt fmt; 33 34 fmtinstall('[', encodefmt); 35 fmtinstall('H', encodefmt); 36 37 verify = 0; 38 id = ""; 39 ARGBEGIN{ 40 case 'i': 41 id = EARGF(usage()); 42 break; 43 case 'v': 44 verify = 1; 45 break; 46 default: 47 usage(); 48 }ARGEND 49 50 if(argc != 1) 51 usage(); 52 key = argv[0]; 53 nid = strlen(id); 54 55 Binit(&b, 0, OREAD); 56 if(verify) { 57 doVerify(); 58 threadexitsall(nil); 59 } 60 61 if((rpc = auth_allocrpc()) == nil){ 62 fprint(2, "dsasign: auth_allocrpc: %r\n"); 63 threadexits("rpc"); 64 } 65 key = smprint("proto=dsa role=sign %s", key); 66 if(auth_rpc(rpc, "start", key, strlen(key)) != ARok){ 67 fprint(2, "dsasign: auth 'start' failed: %r\n"); 68 auth_freerpc(rpc); 69 threadexits("rpc"); 70 } 71 72 print("+%s\n", id); 73 74 Binit(&b, 0, OREAD); 75 fmtstrinit(&fmt); 76 while((p = getline(&n)) != nil) { 77 if(p[0] == '-' || p[0] == '+') 78 print("+"); 79 print("%s\n", p); 80 fmtprint(&fmt, "%s\n", p); 81 } 82 text = fmtstrflush(&fmt); 83 sha1((uchar*)text, strlen(text), digest, nil); 84 85 if(auth_rpc(rpc, "write", digest, SHA1dlen) != ARok) 86 sysfatal("auth write in sign failed: %r"); 87 if(auth_rpc(rpc, "read", nil, 0) != ARok) 88 sysfatal("auth read in sign failed: %r"); 89 90 print("-%s %.*H\n", id, rpc->narg, rpc->arg); 91 threadexits(nil); 92 } 93 94 static mpint* 95 keytomp(Attr *a, char *name) 96 { 97 char *p; 98 mpint *m; 99 100 p = _strfindattr(a, name); 101 if(p == nil) 102 sysfatal("missing key attribute %s", name); 103 m = strtomp(p, nil, 16, nil); 104 if(m == nil) 105 sysfatal("malformed key attribute %s=%s", name, p); 106 return m; 107 } 108 109 static void 110 doVerify(void) 111 { 112 char *p; 113 int n, nsig; 114 Fmt fmt; 115 uchar digest[SHA1dlen], sig[1024]; 116 char *text; 117 Attr *a; 118 DSAsig dsig; 119 DSApub dkey; 120 121 a = _parseattr(key); 122 if(a == nil) 123 sysfatal("invalid key"); 124 dkey.alpha = keytomp(a, "alpha"); 125 dkey.key = keytomp(a, "key"); 126 dkey.p = keytomp(a, "p"); 127 dkey.q = keytomp(a, "q"); 128 if(!probably_prime(dkey.p, 20) && !probably_prime(dkey.q, 20)) 129 sysfatal("p or q not prime"); 130 131 while((p = getline(&n)) != nil) 132 if(p[0] == '+' && strcmp(p+1, id) == 0) 133 goto start; 134 sysfatal("no message found"); 135 136 start: 137 fmtstrinit(&fmt); 138 while((p = getline(&n)) != nil) { 139 if(n >= 1+nid+1+16 && p[0] == '-' && strncmp(p+1, id, nid) == 0 && p[1+nid] == ' ') { 140 if((nsig = dec16(sig, sizeof sig, p+1+nid+1, n-(1+nid+1))) != 20+20) 141 sysfatal("malformed signture"); 142 goto end; 143 } 144 if(p[0] == '+') 145 p++; 146 fmtprint(&fmt, "%s\n", p); 147 } 148 sysfatal("did not find end of message"); 149 return; // silence clang warning 150 151 end: 152 text = fmtstrflush(&fmt); 153 sha1((uchar*)text, strlen(text), digest, nil); 154 155 if(nsig != 40) 156 sysfatal("malformed signature"); 157 dsig.r = betomp(sig, 20, nil); 158 dsig.s = betomp(sig+20, 20, nil); 159 160 if(dsaverify(&dkey, &dsig, betomp(digest, sizeof digest, nil)) < 0) 161 sysfatal("signature failed to verify: %r"); 162 163 write(1, text, strlen(text)); 164 threadexitsall(0); 165 } 166 167 char* 168 getline(int *np) 169 { 170 char *p; 171 int n; 172 173 if((p = Brdline(&b, '\n')) == nil) 174 return nil; 175 n = Blinelen(&b); 176 while(n > 0 && (p[n-1] == '\n' || p[n-1] == ' ' || p[n-1] == '\t')) 177 n--; 178 p[n] = '\0'; 179 *np = n; 180 return p; 181 }