diff --git a/cmd/taler-auditor-offline-signing/main.go b/cmd/taler-auditor-offline-signing/main.go index 8b21be8..fdb632a 100644 --- a/cmd/taler-auditor-offline-signing/main.go +++ b/cmd/taler-auditor-offline-signing/main.go @@ -49,6 +49,7 @@ type Input struct { ReserveClosingDelay RelativeTime `json:"reserve_closing_delay"` Signkeys []SignKey `json:"signkeys"` Denoms []DenomKey `json:"denoms"` + Auditors []Auditor `json:"auditors"` // Recoup []??? `json:"recoup"` } `json:"arguments"` } @@ -75,6 +76,31 @@ type DenomKey struct { MasterSig EdDSASignature `json:"master_sig"` } +type Auditor struct { + AuditorName string `json:"auditor_name"` + AuditorPub EdDSAPublicKey `json:"auditor_pub"` + AuditorUrl string `json:"auditor_url"` + DenominationKeys []struct { + DenomPubH SHA512Hash `json:"denom_pub_h"` + AuditorSig EdDSASignature `json:"auditor_sig"` + } `json:"denomination_keys"` +} + +func (in *Input) checkAuditor(url string, local EdDSAPublicKey) (e error) { + + for _, au := range in.Arguments.Auditors { + if au.AuditorUrl == url && au.AuditorPub.Equal(ed25519.PublicKey(local)) { + return nil + } else if au.AuditorUrl == url { + return fmt.Errorf("Public key mismatch for auditor %q! Local: %s, JSON: %s\n", url, local, au.AuditorPub) + } else if au.AuditorPub.Equal(ed25519.PublicKey(local)) { + return fmt.Errorf("URL mismatch auditor with pub-key %s! Local: %v, JSON: %v\n", au.AuditorPub, url, au.AuditorUrl) + } + } + + return fmt.Errorf("No such auditor found! URL: %q, PubKey: %v\n", url, local) +} + type AbsoluteTime struct { // TODO: en-/decode "never" TMs uint64 `json:"t_ms"` @@ -87,6 +113,10 @@ type RelativeTime struct { type EdDSAPublicKey ed25519.PublicKey +func (ep *EdDSAPublicKey) Equal(p ed25519.PublicKey) bool { + return ((*ed25519.PublicKey)(ep)).Equal(p) +} + func (ep *EdDSAPublicKey) UnmarshalJSON(in []byte) (e error) { var buf []byte // decode crockford.base32 @@ -112,6 +142,14 @@ func (ep *EdDSAPublicKey) MarshalJSON() ([]byte, error) { return buf, nil } +func (ep EdDSAPublicKey) String() string { + enc, err := crockfordEncode([]byte(ep)) + if err != nil { + return fmt.Sprintf("[error crockfordEncode:%v] pub:%v", err, []byte(ep)) + } + return string(enc) +} + const CURRENCY_LEN = 12 type Amount struct { @@ -442,6 +480,17 @@ type SignOperation struct { type SHA512Hash [sha512.Size]byte +func (h *SHA512Hash) UnmarshalJSON(in []byte) (e error) { + var buf []byte + // decode crockford.base32 + if buf, e = crockfordDecode(bytes.Trim(in, `"`)); e != nil { + return fmt.Errorf("couldn't decode SHA512 as crockford.base32: %v (%v)", e, string(in)) + } + + copy([]byte(h[:]), buf[:sha512.Size]) + return nil +} + func (h *SHA512Hash) MarshalJSON() ([]byte, error) { enc, err := crockfordEncode((*h)[:]) if err != nil { @@ -483,7 +532,7 @@ func Verify(denom *DenomKey, master *EdDSAPublicKey, sig []byte) bool { 4 + // purpose ed25519.PublicKeySize + // master 4*8 + // start and expire* - 5*(8+4+len(denom.Value.Currency)) + // value and fee* + 5*(8+4+CURRENCY_LEN) + // value and fee* sha512.Size // denomHash buf := make([]byte, size) @@ -503,13 +552,14 @@ func Verify(denom *DenomKey, master *EdDSAPublicKey, sig []byte) bool { be.PutUint64(buf[n:], v*1000) // milli -> micro n += 8 } - for _, v := range [][]byte{ - denom.Value.Binary(), - denom.FeeWithdraw.Binary(), - denom.FeeDeposit.Binary(), - denom.FeeRefresh.Binary(), - denom.FeeRefund.Binary(), + for _, f := range [](func() []byte){ + denom.Value.Binary, + denom.FeeWithdraw.Binary, + denom.FeeDeposit.Binary, + denom.FeeRefresh.Binary, + denom.FeeRefund.Binary, } { + v := f() copy(buf[n:], v) n += len(v) } @@ -551,7 +601,7 @@ func SignDenom(denom *DenomKey, ahash SHA512Hash, master *EdDSAPublicKey, pk *ed sha512.Size + // auditor_url_hash ed25519.PublicKeySize + // master 4*8 + // start and expire* - 5*(8+4+len(denom.Value.Currency)) + // value and fee* + 5*(8+4+CURRENCY_LEN) + // value and fee* sha512.Size // denomHash buf := make([]byte, size) @@ -573,17 +623,21 @@ func SignDenom(denom *DenomKey, ahash SHA512Hash, master *EdDSAPublicKey, pk *ed be.PutUint64(buf[n:], v*1000) // milli -> micro n += 8 } - for _, v := range [][]byte{ - denom.Value.Binary(), - denom.FeeWithdraw.Binary(), - denom.FeeDeposit.Binary(), - denom.FeeRefresh.Binary(), - denom.FeeRefund.Binary(), + for _, f := range [](func() []byte){ + denom.Value.Binary, + denom.FeeWithdraw.Binary, + denom.FeeDeposit.Binary, + denom.FeeRefresh.Binary, + denom.FeeRefund.Binary, } { + v := f() copy(buf[n:], v) n += len(v) } bin := denom.DenomPub.Binary() + // Future: + // bin = append(bin, 0, 0, 0, 0) // age mask + // bin = append(bin, 0, 0, 0, 1) // cipher == RSA hash := sha512.Sum512(bin) copy(buf[n:], hash[:]) @@ -649,7 +703,7 @@ func main() { var dec *json.Decoder input := new(Input) - if *injson == "-" { + if *injson == "-" || *injson == "" { dec = json.NewDecoder(os.Stdin) } else { f, e := os.Open(*injson) @@ -665,6 +719,11 @@ func main() { log.Fatal(e) } + e = input.checkAuditor(*url, EdDSAPublicKey(pub)) + if e != nil { + log.Fatal(e) + } + output, err := Sign(input, *url, pk) if err != nil { log.Fatalf("error signing: %v", err)