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