epoint-client: 1M input limit
[epoint] / cmd / epoint-client / epoint-client.go
1 package main
2
3 import (
4         "bytes"
5         "crypto/openpgp"
6         "crypto/openpgp/armor"
7         "crypto/rand"
8         "epoint/document"
9         "epoint/key"
10         "epoint/store"
11         "fmt"
12         "io"
13         "log"
14         "net/http"
15         "net/url"
16         "os"
17         "strconv"
18 )
19
20 // TODO: store documents, query document by id, easy submit
21
22 var db *store.Conn
23
24 const usage = `usage: ./epoint-client [i|h|d|r|q|s|v|c] [args..] < [seed|document]
25 server is http://localhost:8080 by default
26
27 i - make issuer key, use seed for generation, args: denomination
28 h - make holder key, use seed for generation, args: issuer
29 d - make draft, use seed for signing key, args: targetid value
30 r - sign raw document, use seed for signing key, args: document
31 q - query document, args: k|d|c id [server]
32 s - submit a (key|draft|cert) document, args: k|d|c [server]
33 v - verify a document (prints body of the document if ok)
34 c - connect to server and get server key, args: [server]
35 `
36
37 func rnd(n int) (r []byte, err error) {
38         r = make([]byte, n)
39         _, err = io.ReadFull(rand.Reader, r)
40         return
41 }
42
43 func k(r []byte, cmd, arg string) (err error) {
44         var e *openpgp.Entity
45
46         if cmd == "i" {
47                 e, err = key.Issuer(r, arg)
48         } else {
49                 s, err1 := db.Get("key", arg)
50                 err = err1
51                 if err != nil {
52                         return
53                 }
54                 ie, err1 := key.Parse(s)
55                 err = err1
56                 if err != nil {
57                         return
58                 }
59                 isIssuer, _, denom, err1 := key.Check(ie)
60                 err = err1
61                 if err != nil {
62                         return
63                 }
64                 if !isIssuer {
65                         err = fmt.Errorf("Not an issuer key: %s", arg)
66                         return
67                 }
68                 e, err = key.Holder(r, arg, denom)
69         }
70         if err != nil {
71                 return
72         }
73         log.Printf("generated key %s", key.Id(e))
74         d, err := db.Get("key", key.Id(e))
75         if err == nil {
76                 // TODO: issuer, denom check (remove keys from store if they are not sent to server?)
77                 log.Printf("key %s was found in store", key.Id(e))
78         } else {
79                 out := new(bytes.Buffer)
80                 w, err1 := armor.Encode(out, openpgp.PublicKeyType, nil)
81                 err = err1
82                 if err != nil {
83                         return
84                 }
85                 // TODO: maybe Serialize should do this internally
86                 for _, ident := range e.Identities {
87                         err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
88                         if err != nil {
89                                 return
90                         }
91                 }
92                 for _, subkey := range e.Subkeys {
93                         err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
94                         if err != nil {
95                                 return
96                         }
97                 }
98                 err = e.Serialize(w)
99                 if err != nil {
100                         return
101                 }
102                 err = w.Close()
103                 if err != nil {
104                         return
105                 }
106                 _, err = out.Write([]byte{'\n'})
107                 if err != nil {
108                         return
109                 }
110                 d = out.Bytes()
111                 err = db.Insert("key", key.Id(e), d)
112                 if err != nil {
113                         return
114                 }
115         }
116         _, err = os.Stdout.Write(d)
117         return
118 }
119
120 func d(r []byte, target, value string) (err error) {
121         v, err := strconv.ParseInt(value, 10, 64)
122         if err != nil {
123                 return
124         }
125         e, err := key.Holder(r, "", "")
126         if err != nil {
127                 return
128         }
129         log.Printf("drawer: %s", key.Id(e))
130         if key.Id(e) == target {
131                 err = fmt.Errorf("Drawer and beneficiary are the same")
132                 return
133         }
134         b, err := db.Get("key", key.Id(e))
135         if err != nil {
136                 return
137         }
138         e1, err := key.Parse(b)
139         if err != nil {
140                 return
141         }
142         _, issuer, denom, err := key.Check(e1)
143         if err != nil {
144                 return
145         }
146         // TODO: store server id as well?
147         b, err = db.Get("", "serverkey")
148         if err != nil {
149                 return
150         }
151         sk, err := key.Parse(b)
152         if err != nil {
153                 return
154         }
155         // TODO: check beneficiary (check value?)
156         draft := new(document.Draft)
157         draft.Drawer = key.Id(e)
158         draft.Beneficiary = target
159         draft.Amount = v
160         draft.Denomination = denom
161         draft.Issuer = issuer
162         draft.AuthorizedBy = key.Id(sk)
163         nonce, err := rnd(10)
164         if err != nil {
165                 return
166         }
167         draft.Nonce = fmt.Sprintf("%X", nonce)
168         s, c, err := document.Format(draft, e)
169         if err != nil {
170                 return
171         }
172         log.Printf("draft id: %s", document.Id(c))
173         _, err = os.Stdout.Write(s)
174         return
175 }
176
177 // TODO: document.Sign does not handle dash escape
178 func raw(r []byte, name string) (err error) {
179         e, err := key.Holder(r, "", "")
180         if err != nil {
181                 return
182         }
183         log.Printf("signer: %s", key.Id(e))
184         f, err := os.Open(name)
185         if err != nil {
186                 return
187         }
188         doc, err := readall(f)
189         if err != nil {
190                 return
191         }
192         d, err := document.Sign(doc, e)
193         if err != nil {
194                 return
195         }
196         s, err := document.FormatSigned(d)
197         if err != nil {
198                 return
199         }
200         _, err = os.Stdout.Write(s)
201         return
202 }
203
204 func q(cmd, id, server string) (err error) {
205         log.Printf("document id: %s, server: %s", id, server)
206         m := map[string]string{
207                 "k": "key",
208                 "d": "draft",
209                 "c": "cert",
210         }
211         k, ok := m[cmd]
212         if !ok {
213                 err = fmt.Errorf("unknown query command: %s", cmd)
214                 return
215         }
216         d, err := db.Get(k, id)
217         if err != nil {
218                 if _, ok := err.(store.NotFoundError); !ok {
219                         return
220                 }
221         } else {
222                 _, err = os.Stdout.Write(d)
223                 log.Printf("found %s in local store", id)
224                 return
225         }
226         resp, err := http.Get(server+"/"+k+"/"+id)
227         if err != nil {
228                 return
229         }
230         d, err = readall(resp.Body)
231         if err != nil {
232                 return
233         }
234         err = resp.Body.Close()
235         if err != nil {
236                 return
237         }
238         _, err = os.Stdout.Write(d)
239         if resp.StatusCode != 200 {
240                 err = fmt.Errorf("request failed: %s", resp.Status)
241                 return
242         }
243         if err != nil {
244                 return
245         }
246         log.Printf("got %s from the server", id)
247         switch cmd {
248         case "k":
249                 e, err1 := key.Parse(d)
250                 err = err1
251                 if err != nil {
252                         return
253                 }
254                 if id != key.Id(e) {
255                         err = fmt.Errorf("id mismatch, expected %s, got %s", id, key.Id(e))
256                         return
257                 }
258                 err = db.Set("key", id, d)
259         case "d":
260                 i, s, err1 := document.Parse(d)
261                 err = err1
262                 if err != nil {
263                         return
264                 }
265                 if id != document.Id(s) {
266                         err = fmt.Errorf("id mismatch, expected %s, got %s", id, document.Id(s))
267                         return
268                 }
269                 draft := i.(*document.Draft)
270                 b, err1 := db.Get("key", draft.Drawer)
271                 err = err1
272                 if err != nil {
273                         return
274                 }
275                 e, err1 := key.Parse(b)
276                 err = err1
277                 if err != nil {
278                         return
279                 }
280                 err = document.Verify(s, openpgp.EntityList{e})
281                 if err != nil {
282                         return
283                 }
284                 err = db.Set("draft", id, d)
285         case "c":
286                 i, s, err1 := document.Parse(d)
287                 err = err1
288                 if err != nil {
289                         return
290                 }
291                 if id != document.Id(s) {
292                         err = fmt.Errorf("id mismatch, expected %s, got %s", id, document.Id(s))
293                         return
294                 }
295                 cert, err1 := document.ToCert(i)
296                 err = err1
297                 if err != nil {
298                         return
299                 }
300                 // TODO: check serverkey
301                 b, err1 := db.Get("key", cert.AuthorizedBy)
302                 err = err1
303                 if err != nil {
304                         return
305                 }
306                 e, err1 := key.Parse(b)
307                 err = err1
308                 if err != nil {
309                         return
310                 }
311                 err = document.Verify(s, openpgp.EntityList{e})
312                 if err != nil {
313                         return
314                 }
315                 err = db.Set("cert", id, d)
316         }
317         return
318 }
319
320 func s(d []byte, cmd, server string) (err error) {
321         m := map[string]string{
322                 "k": "key",
323                 "d": "draft",
324                 "c": "debit",
325         }
326         k, ok := m[cmd]
327         if !ok {
328                 err = fmt.Errorf("unknown submit command: %s", cmd)
329                 return
330         }
331         id := ""
332         switch cmd {
333         case "k":
334                 e, err1 := key.Parse(d)
335                 err = err1
336                 if err != nil {
337                         return
338                 }
339                 id = key.Id(e)
340                 err = db.Set("key", id, d)
341         case "d":
342                 _, s, err1 := document.Parse(d)
343                 err = err1
344                 if err != nil {
345                         return
346                 }
347                 id = document.Id(s)
348                 err = db.Set("draft", id, d)
349         case "c":
350                 _, s, err1 := document.Parse(d)
351                 err = err1
352                 if err != nil {
353                         return
354                 }
355                 id = document.Id(s)
356                 err = db.Set("cert", id, d)
357         }
358         if err != nil {
359                 return
360         }
361         log.Printf("document id: %s, server: %s", id, server)
362         resp, err := http.PostForm(server+"/submit", url.Values{k: {string(d)}})
363         if err != nil {
364                 return
365         }
366         if resp.StatusCode != 200 {
367                 log.Printf("request failed: %s", resp.Status)
368         }
369         // TODO: store result
370         b, err := readall(resp.Body)
371         defer resp.Body.Close()
372         if err != nil {
373                 return
374         }
375         _, err = os.Stdout.Write(b)
376         if err != nil {
377                 return
378         }
379         cert, s, err := document.Parse(b)
380         if err != nil {
381                 return
382         }
383         d, err = db.Get("", "serverkey")
384         if err != nil {
385                 return
386         }
387         e, err := key.Parse(d)
388         if err != nil {
389                 return
390         }
391         err = document.Verify(s, openpgp.EntityList{e})
392         if err != nil {
393                 return
394         }
395         log.Printf("response type: %T, response id: %s", cert, document.Id(s))
396         err = db.Set("cert", document.Id(s), b)
397         return
398 }
399
400 func v(d []byte) (err error) {
401         // handle armored pubkey
402         if bytes.Index(d, []byte(openpgp.PublicKeyType)) >= 0 {
403                 es, err1 := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
404                 if err1 != nil {
405                         err = err1
406                         return
407                 }
408                 for _, e := range es {
409                         isIssuer, issuer, denom, err1 := key.Check(e)
410                         if err1 != nil {
411                                 if err != nil {
412                                         log.Println(err)
413                                 }
414                                 err = err1
415                                 continue
416                         }
417                         if isIssuer {
418                                 fmt.Println("Issuer key")
419                         } else {
420                                 fmt.Println("Holder key")
421                         }
422                         fmt.Printf("Issuer: %s\nDenomination: %s\nId: %s\n", issuer, denom, key.Id(e))
423                 }
424                 return
425         }
426         _, s, err := document.Parse(d)
427         if err != nil {
428                 return
429         }
430         _, err = os.Stdout.Write(s.Body)
431         return
432 }
433
434 func c(server string) (err error) {
435         resp, err := http.Get(server + "/serverkey")
436         if err != nil {
437                 return
438         }
439         if resp.StatusCode != 200 {
440                 log.Printf("request failed: %s\n", resp.Status)
441         }
442         b, err := readall(resp.Body)
443         if err != nil {
444                 return
445         }
446         err = resp.Body.Close()
447         if err != nil {
448                 return
449         }
450         e, err := key.Parse(b)
451         if err != nil {
452                 return
453         }
454         log.Printf("got server key %s", key.Id(e))
455         err = db.Set("key", key.Id(e), b)
456         if err != nil {
457                 return
458         }
459         err = db.Set("", "serverkey", b)
460         return
461 }
462
463 // TODO: commmon code with server
464 func initstore(dir string) (db *store.Conn, err error) {
465         log.Printf("using root dir %s", dir)
466         db, err = store.Open(dir)
467         if err != nil {
468                 return
469         }
470         err = db.Ensure("key")
471         if err != nil {
472                 return
473         }
474         err = db.Ensure("cert")
475         if err != nil {
476                 return
477         }
478         err = db.Ensure("draft")
479         if err != nil {
480                 return
481         }
482         err = db.Ensure("certby/draft")
483         if err != nil {
484                 return
485         }
486         err = db.Ensure("certby/debit")
487         if err != nil {
488                 return
489         }
490         err = db.Ensure("certby/key")
491         if err != nil {
492                 return
493         }
494         err = db.Ensure("certby/key.serial")
495         if err != nil {
496                 return
497         }
498         return
499 }
500
501 func storedir() string {
502         dir := os.Getenv("HOME")
503         if dir == "" {
504                 dir = "/var/cache/epoint"
505         } else {
506                 dir += "/.epoint-client"
507         }
508         return dir
509 }
510
511 // read all but at most 1M from r
512 func readall(r io.Reader) ([]byte, error) {
513         b := make([]byte, 1<<20)
514         n, err := io.ReadFull(r, b)
515         if err != io.ErrUnexpectedEOF {
516                 if err == nil {
517                         err = fmt.Errorf("too much input")
518                 }
519                 return nil, err
520         }
521         return b[:n], nil
522 }
523
524 func read() []byte {
525         b, err := readall(os.Stdin)
526         if err != nil {
527                 log.Fatal(err)
528         }
529         return b
530 }
531
532 func main() {
533         if len(os.Args) < 2 {
534                 log.Fatal(usage)
535         }
536
537         var err error
538         db, err = initstore(storedir())
539         server := "http://localhost:8080"
540         switch os.Args[1] {
541         case "h", "i":
542                 if len(os.Args) != 3 {
543                         log.Fatal(usage)
544                 }
545                 err = k(read(), os.Args[1], os.Args[2])
546         case "d":
547                 if len(os.Args) != 4 {
548                         log.Fatal(usage)
549                 }
550                 err = d(read(), os.Args[2], os.Args[3])
551         case "r":
552                 if len(os.Args) != 3 {
553                         log.Fatal(usage)
554                 }
555                 err = raw(read(), os.Args[2])
556         case "q":
557                 cmd := ""
558                 id := ""
559                 if len(os.Args) == 5 {
560                         cmd = os.Args[2]
561                         id = os.Args[3]
562                         server = os.Args[4]
563                 } else if len(os.Args) == 4 {
564                         cmd = os.Args[2]
565                         id = os.Args[3]
566                 } else {
567                         log.Fatal(usage)
568                 }
569                 err = q(cmd, id, server)
570         case "s":
571                 cmd := ""
572                 if len(os.Args) == 4 {
573                         cmd = os.Args[2]
574                         server = os.Args[3]
575                 } else if len(os.Args) == 3 {
576                         cmd = os.Args[2]
577                 } else {
578                         log.Fatal(usage)
579                 }
580                 err = s(read(), cmd, server)
581         case "v":
582                 if len(os.Args) != 2 {
583                         log.Fatal(usage)
584                 }
585                 err = v(read())
586         case "c":
587                 if len(os.Args) == 3 {
588                         server = os.Args[2]
589                 } else if len(os.Args) != 2 {
590                         log.Fatal(usage)
591                 }
592                 err = c(server)
593         default:
594                 log.Fatal(usage)
595         }
596         if err != nil {
597                 log.Fatal(err)
598         }
599 }