github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/merkle_reset_chain.go (about) 1 package libkb 2 3 import ( 4 sha512 "crypto/sha512" 5 json "encoding/json" 6 fmt "fmt" 7 8 keybase1 "github.com/keybase/client/go/protocol/keybase1" 9 jsonw "github.com/keybase/go-jsonw" 10 ) 11 12 type resetLinkAndHash struct { 13 link keybase1.ResetLink 14 hash keybase1.SHA512 15 } 16 17 type unverifiedResetChain []resetLinkAndHash 18 19 func importResetLinkAndHash(s string) (ret *resetLinkAndHash, err error) { 20 b := []byte(s) 21 hash := sha512.Sum512(b) 22 var link keybase1.ResetLink 23 err = json.Unmarshal(b, &link) 24 if err != nil { 25 return nil, err 26 } 27 ret = &resetLinkAndHash{ 28 hash: hash[:], 29 link: link, 30 } 31 return ret, nil 32 } 33 34 func importResetChainFromServer(m MetaContext, jw *jsonw.Wrapper) (urc unverifiedResetChain, err error) { 35 defer m.VTrace(VLog1, "importResetChainFromServer", &err)() 36 if jw == nil || jw.IsNil() { 37 return nil, nil 38 } 39 var ret unverifiedResetChain 40 chainLen, err := jw.Len() 41 if err != nil { 42 return nil, err 43 } 44 for i := 0; i < chainLen; i++ { 45 s, err := jw.AtIndex(i).GetString() 46 if err != nil { 47 return nil, err 48 } 49 link, err := importResetLinkAndHash(s) 50 if err != nil { 51 return nil, err 52 } 53 ret = append(ret, *link) 54 } 55 return ret, nil 56 } 57 58 func parseV2LeafResetChainTail(jw *jsonw.Wrapper) (*MerkleResets, error) { 59 if jw == nil || jw.IsNil() { 60 return nil, nil 61 } 62 l, err := jw.Len() 63 if err != nil { 64 return nil, err 65 } 66 if l == 0 { 67 return nil, nil 68 } 69 if l != 2 { 70 return nil, MerkleClientError{m: "bad reset chain tail; expecting 2 items", t: merkleErrorBadResetChain} 71 } 72 var ct MerkleResetChainTail 73 if err := jw.AtIndex(0).UnmarshalAgain(&ct.Seqno); err != nil { 74 return nil, err 75 } 76 if err := jw.AtIndex(1).UnmarshalAgain(&ct.Hash); err != nil { 77 return nil, err 78 } 79 ret := &MerkleResets{chainTail: ct} 80 return ret, nil 81 } 82 83 type MerkleResetChainTail struct { 84 Seqno keybase1.Seqno 85 Hash keybase1.SHA512 86 } 87 88 type MerkleResets struct { 89 chainTail MerkleResetChainTail 90 chain []keybase1.ResetLink 91 } 92 93 func (mr *MerkleResets) verifyAndLoad(m MetaContext, urc unverifiedResetChain) (err error) { 94 95 // Don't even bother to do a CVTrace if the user hasn't reset at all 96 if mr == nil { 97 return nil 98 } 99 100 defer m.VTrace(VLog1, "MerkleResets#verifyAndLoad", &err)() 101 102 mkerr := func(f string, a ...interface{}) error { 103 return MerkleClientError{m: fmt.Sprintf(f, a...), t: merkleErrorBadResetChain} 104 } 105 106 hashEq := func(a, b keybase1.SHA512) bool { 107 if a == nil || b == nil { 108 return (a == nil && b == nil) 109 } 110 return a.Eq(b) 111 } 112 113 if int(mr.chainTail.Seqno) != len(urc) { 114 err = mkerr("bad reset chain length: %d != %d", int(mr.chainTail.Seqno), len(urc)) 115 return err 116 } 117 118 // Verify the chain starting at the tail and going to the front. 119 curr := mr.chainTail.Hash 120 last := true 121 foundDelete := false 122 lastWasDelete := false 123 124 for i := len(urc) - 1; i >= 0; i-- { 125 resetSeqno := i + 1 126 link := urc[i].link 127 hash := urc[i].hash 128 if !hashEq(curr, hash) { 129 err = mkerr("hash chain mismatch at seqno %d", resetSeqno) 130 return err 131 } 132 if int(link.ResetSeqno) != resetSeqno { 133 err = mkerr("wrong seqno at seqno %d", resetSeqno) 134 return err 135 } 136 if link.Type == keybase1.ResetType_DELETE { 137 if last { 138 lastWasDelete = true 139 } 140 foundDelete = true 141 } 142 curr = link.Prev.Reset 143 last = false 144 } 145 146 // NOTE(max) 2018-03-19 147 // We should have checked that deletes were only visible at the end of the reset chain. 148 // However, there was a bug in the migrate script, and if you had an account that did 149 // several resets and then a delete, all were marked as deletes! This check isn't ideal, but 150 // it's good enough -- we just want to make sure that a delete is indeed a tombstone, 151 // and that if there are any deletes in the chain, then the last must be a delete. 152 if foundDelete && !lastWasDelete { 153 err = mkerr("found a delete that didn't tombstone the user") 154 return err 155 } 156 157 if curr != nil { 158 err = mkerr("expected first link in reset chain to have a null prev") 159 return err 160 } 161 162 // It all verified, now load it up, going front to back. 163 for _, e := range urc { 164 mr.chain = append(mr.chain, e.link) 165 } 166 167 return nil 168 }