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  }