5d9af8e2aa42658035191e9f3ef85aa7cf75ac87
[epoint] / pkg / server / server.go
1 package server
2
3 // main transfer logic
4
5 import (
6         "bytes"
7         "crypto/openpgp"
8         "epoint/document"
9         "epoint/key"
10         "epoint/store"
11         "fmt"
12         "time"
13 )
14
15 // TODO: do in docs?
16 const IntLimit = 1e15
17
18 var db *store.Conn
19
20 func StoreSk(sk *openpgp.Entity) (err error) {
21         // TODO: initkey should save serverkey in db
22         b := new(bytes.Buffer)
23         err = sk.Serialize(b)
24         if err != nil {
25                 return
26         }
27         return db.Set("key", fmt.Sprintf("%X", sk.PrimaryKey.Fingerprint), b.Bytes())
28 }
29
30 func GetKeys(fpr string) (es openpgp.EntityList, err error) {
31         b, err := db.Get("key", fpr)
32         if err != nil {
33                 return
34         }
35         es, err = openpgp.ReadKeyRing(bytes.NewBuffer(b))
36         if err != nil {
37                 // internal error: pubkey cannot be parsed
38                 return
39         }
40         return
41 }
42
43 func AddKeys(d []byte) (err error) {
44         entities, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
45         if err != nil {
46                 return
47         }
48         // TODO: allow multiple key uploads at once?
49         if len(entities) > 100 {
50                 err = fmt.Errorf("expected at most 100 keys; got %d", len(entities))
51                 return
52         }
53         for _, e := range entities {
54                 // TODO: various checks..
55                 isIssuer, issuer, denom, err1 := key.CheckEntity(e)
56                 err = err1
57                 if err != nil {
58                         // TODO..
59                         continue
60                 }
61                 if !isIssuer {
62                         es, err := GetKeys(issuer)
63                         if err != nil {
64                                 // TODO..
65                                 continue
66                         }
67                         ok, _, den, err := key.CheckEntity(es[0])
68                         if !ok || err != nil || den != denom {
69                                 // TODO..
70                                 continue
71                         }
72                 }
73                 b := new(bytes.Buffer)
74                 err = e.Serialize(b)
75                 if err != nil {
76                         return
77                 }
78                 fpr := fmt.Sprintf("%X", e.PrimaryKey.Fingerprint)
79                 err = db.Set("key", fpr, b.Bytes())
80                 if err != nil {
81                         return
82                 }
83                 err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
84                 if err != nil {
85                         return
86                 }
87                 err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
88                 if err != nil {
89                         return
90                 }
91         }
92         return
93 }
94
95 func CertByDraft(draftid string) (d []byte, err error) {
96         certid, err := db.Get("certby/draft", draftid)
97         if err != nil {
98                 // TODO: we have the draft but the cert is not ready
99                 return
100         }
101         d, err = db.Get("cert", string(certid))
102         if err != nil {
103                 // shouldn't happen, cert is not available
104                 return
105         }
106         return
107 }
108
109 func CertByDebitCert(debitid string) (d []byte, err error) {
110         creditid, err := db.Get("certby/debit", debitid)
111         if err != nil {
112                 // TODO: we have the debit cert but the credit cert is not ready
113                 return
114         }
115         d, err = db.Get("cert", string(creditid))
116         if err != nil {
117                 // shouldn't happen, cert is not available
118                 return
119         }
120         return
121 }
122
123 // parse clear signed draft and verify it
124 func ParseDraft(d []byte) (draft *document.Draft, draftid string, err error) {
125         iv, signed, err := document.Parse(d)
126         if err != nil {
127                 return
128         }
129         draft, ok := iv.(*document.Draft)
130         if !ok {
131                 err = fmt.Errorf("ParseDraft: expected a draft docuent")
132                 return
133         }
134         draftid = document.Id(signed)
135
136         k, err := db.Get("key", draft.Drawer)
137         if err != nil {
138                 return
139         }
140         kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
141         if err != nil {
142                 // internal error: pubkey cannot be parsed
143                 return
144         }
145         err = document.Verify(signed, kr)
146         if err != nil {
147                 return
148         }
149         _, issuer, denom, err := key.CheckEntity(kr[0])
150         if err != nil {
151                 return
152         }
153         k, err = db.Get("key", draft.Beneficiary)
154         if err != nil {
155                 return
156         }
157         kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
158         if err != nil {
159                 // internal error: pubkey cannot be parsed
160                 return
161         }
162         _, issuer2, denom2, err := key.CheckEntity(kr[0])
163         if err != nil {
164                 return
165         }
166         if draft.Issuer != issuer ||
167                 draft.Issuer != issuer2 ||
168                 draft.Denomination != denom ||
169                 draft.Denomination != denom2 {
170                 err = fmt.Errorf("Issuer or denomination mismatch")
171                 return
172         }
173
174         // TODO: do various format checks (AuthorizedBy check etc)
175         if draft.Amount <= 0 || draft.Amount >= IntLimit {
176                 err = fmt.Errorf("draft amount is invalid: %d", draft.Amount)
177                 return
178         }
179         return
180 }
181
182 func ParseDebitCert(d []byte) (cert *document.DebitCert, certid string, err error) {
183         iv, signed, err := document.Parse(d)
184         if err != nil {
185                 return
186         }
187         cert, ok := iv.(*document.DebitCert)
188         if !ok {
189                 err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
190                 return
191         }
192
193         k, err := db.Get("key", cert.AuthorizedBy)
194         if err != nil {
195                 return
196         }
197         // TODO: keep our key at hand
198         kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
199         if err != nil {
200                 // internal error: pubkey cannot be parsed
201                 return
202         }
203         // must clean up to make sure the hash is ok
204         err = document.Verify(signed, kr)
205         if err != nil {
206                 return
207         }
208
209         certid = document.Id(signed)
210         return
211 }
212
213 func NewDebitCert(draftid string, draft *document.Draft) (*document.DebitCert, error) {
214         cert := new(document.DebitCert)
215         cert.Holder = draft.Drawer
216         cert.Date = time.Seconds()
217         cert.Denomination = "epoint"
218         cert.Issuer = draft.Issuer
219         cert.AuthorizedBy = draft.AuthorizedBy
220         cert.Difference = -draft.Amount
221         cert.Draft = draftid
222         cert.Beneficiary = draft.Beneficiary
223
224         oid, err := db.Get("certby/key", draft.Drawer)
225         oldcertid := string(oid)
226         if err != nil {
227                 // first cert: drawer is issuer
228                 if draft.Drawer != draft.Issuer {
229                         return nil, fmt.Errorf("drawer must be the issuer when drawing an empty account")
230                 }
231                 cert.Serial = 1
232                 cert.Balance = cert.Difference
233                 cert.LastDebitSerial = 0
234                 cert.LastCreditSerial = 0
235         } else {
236                 d, err := db.Get("cert", oldcertid)
237                 if err != nil {
238                         return nil, err
239                 }
240                 iv, _, err := document.Parse(d)
241                 if err != nil {
242                         // internal error
243                         return nil, err
244                 }
245                 // TODO: this is a hack
246                 oldcert, err := document.ToCert(iv)
247                 if err != nil {
248                         // internal error
249                         return nil, err
250                 }
251                 // TODO: sanity checks? oldcert.Holder == draft.Drawer
252                 cert.Serial = oldcert.Serial + 1
253                 cert.Balance = oldcert.Balance + cert.Difference
254                 if cert.Balance <= -IntLimit {
255                         return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
256                 }
257                 if oldcert.Balance > 0 && cert.Balance < 0 {
258                         return nil, fmt.Errorf("insufficient funds: %d", oldcert.Balance)
259                 }
260                 cert.LastDebitSerial = oldcert.LastDebitSerial
261                 cert.LastCreditSerial = oldcert.LastCreditSerial
262                 if _,ok := iv.(*document.DebitCert); ok {
263                         cert.LastDebitSerial = oldcert.Serial
264                 } else {
265                         cert.LastCreditSerial = oldcert.Serial
266                 }
267                 cert.LastCert = &oldcertid
268         }
269         return cert, nil
270 }
271
272 func NewCreditCert(draftid string, draft *document.Draft, dcertid string, dcert *document.DebitCert) (*document.CreditCert, error) {
273         cert := new(document.CreditCert)
274         // TODO: get from old cert instead?
275         cert.Holder = dcert.Beneficiary
276         cert.Date = time.Seconds()
277         // TODO: get these from the cert holder pubkey
278         cert.Denomination = "epoint"
279         cert.Issuer = draft.Issuer
280         cert.AuthorizedBy = dcert.AuthorizedBy // TODO: draft vs dcert vs serverside decision
281         cert.Difference = -dcert.Difference
282         cert.Draft = draftid
283         cert.Drawer = dcert.Holder
284         cert.DebitCert = dcertid
285
286         oid, err := db.Get("certby/key", dcert.Beneficiary)
287         oldcertid := string(oid)
288         if err != nil {
289                 // this is the first cert
290                 cert.Serial = 1
291                 cert.Balance = cert.Difference
292                 cert.LastDebitSerial = 0
293                 cert.LastCreditSerial = 0
294         } else {
295                 d, err := db.Get("cert", oldcertid)
296                 if err != nil {
297                         // internal error
298                         return nil, err
299                 }
300                 iv, _, err := document.Parse(d)
301                 if err != nil {
302                         // internal error
303                         return nil, err
304                 }
305                 // TODO: this is a hack
306                 oldcert, err := document.ToCert(iv)
307                 if err != nil {
308                         // internal error
309                         return nil, err
310                 }
311                 cert.Serial = oldcert.Serial + 1
312                 cert.Balance = oldcert.Balance + cert.Difference
313                 if cert.Balance >= IntLimit {
314                         return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
315                 }
316                 cert.LastDebitSerial = oldcert.LastDebitSerial
317                 cert.LastCreditSerial = oldcert.LastCreditSerial
318                 if _,ok := iv.(*document.DebitCert); ok {
319                         cert.LastDebitSerial = oldcert.Serial
320                 } else {
321                         cert.LastCreditSerial = oldcert.Serial
322                 }
323                 cert.LastCert = &oldcertid
324         }
325         return cert, nil
326 }
327
328 func EvalDraft(d []byte, sk *openpgp.Entity) (r []byte, err error) {
329         draft, draftid, err := ParseDraft(d)
330         if err != nil {
331                 return
332         }
333         _, err = db.Get("draft", draftid)
334         if err == nil {
335                 // found
336                 // TODO: certby/draft might not be ready even if draft is there
337                 return CertByDraft(draftid)
338         }
339         // if draft is ok we save it
340         err = db.Set("draft", draftid, d)
341         if err != nil {
342                 // internal error
343                 return
344         }
345         // TODO: db.Insert: fails if key exists
346         s := fmt.Sprintf("%s.%s", draft.Drawer, draft.Nonce)
347         _, err = db.Get("draftby/key.nonce", s)
348         if err == nil {
349                 err = fmt.Errorf("draft nonce is not unique")
350                 return
351         }
352         err = db.Set("draftby/key.nonce", s, d)
353         if err != nil {
354                 // internal error
355                 return
356         }
357
358         // debit cert
359         cert, err := NewDebitCert(draftid, draft)
360         if err != nil {
361                 return
362         }
363         r, signed, err := document.Format(cert, sk)
364         certid := document.Id(signed)
365         err = db.Set("cert", certid, r)
366         if err != nil {
367                 // internal error
368                 return
369         }
370         err = db.Set("certby/draft", draftid, []byte(certid))
371         if err != nil {
372                 // internal error
373                 return
374         }
375         err = db.Set("certby/key", cert.Holder, []byte(certid))
376         if err != nil {
377                 // internal error
378                 return
379         }
380         // TODO: append?
381         err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
382         if err != nil {
383                 // internal error
384                 return
385         }
386         return
387 }
388
389 func EvalDebitCert(d []byte, sk *openpgp.Entity) (r []byte, err error) {
390         dcert, dcertid, err := ParseDebitCert(d)
391         if err != nil {
392                 return
393         }
394         r, err = CertByDebitCert(dcertid)
395         if err == nil {
396                 // found
397                 return
398         }
399         // TODO: we only need the draft to know the issuer (+beneficiary)
400         // it should be in the pubkey
401         d, err = db.Get("draft", dcert.Draft)
402         if err != nil {
403                 // internal error
404                 return
405         }
406         iv, _, err := document.Parse(d)
407         if err != nil {
408                 // internal error
409                 return
410         }
411         draft, ok := iv.(*document.Draft)
412         if !ok {
413                 // internal error
414                 err = fmt.Errorf("EvalDebitCert: expected draft from internal db")
415                 return
416         }
417
418         // credit side
419         // TODO: check pubkey etc
420         cert, err := NewCreditCert(dcert.Draft, draft, dcertid, dcert)
421         if err != nil {
422                 // internal error
423                 return
424         }
425         r, signed, err := document.Format(cert, sk)
426         if err != nil {
427                 // internal error
428                 return
429         }
430         certid := document.Id(signed)
431         err = db.Set("cert", certid, r)
432         if err != nil {
433                 // internal error
434                 return
435         }
436         err = db.Set("certby/debit", dcertid, []byte(certid))
437         if err != nil {
438                 // internal error
439                 return
440         }
441         err = db.Set("certby/key", cert.Holder, []byte(certid))
442         if err != nil {
443                 // internal error
444                 return
445         }
446         // TODO: append?
447         err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
448         if err != nil {
449                 // internal error
450                 return
451         }
452         return
453 }
454
455 func Init(rootdir string) (err error) {
456         db, err = store.Open(rootdir)
457         if err != nil {
458                 return
459         }
460         err = db.Ensure("key")
461         if err != nil {
462                 return
463         }
464         err = db.Ensure("cert")
465         if err != nil {
466                 return
467         }
468         err = db.Ensure("draft")
469         if err != nil {
470                 return
471         }
472         err = db.Ensure("certby/draft")
473         if err != nil {
474                 return
475         }
476         err = db.Ensure("certby/debit")
477         if err != nil {
478                 return
479         }
480         err = db.Ensure("certby/key")
481         if err != nil {
482                 return
483         }
484         err = db.Ensure("certby/key.serial")
485         if err != nil {
486                 return
487         }
488         err = db.Ensure("draftby/key.nonce")
489         if err != nil {
490                 return
491         }
492         err = db.Ensure("keysby/64")
493         if err != nil {
494                 return
495         }
496         err = db.Ensure("keysby/32")
497         if err != nil {
498                 return
499         }
500         return
501 }