github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/chain_link.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/sha256"
     9  	"encoding/hex"
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"strconv"
    14  	"time"
    15  
    16  	"github.com/buger/jsonparser"
    17  	"github.com/keybase/client/go/jsonparserw"
    18  	"github.com/keybase/client/go/msgpack"
    19  	pkgerrors "github.com/pkg/errors"
    20  
    21  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    22  	jsonw "github.com/keybase/go-jsonw"
    23  )
    24  
    25  const (
    26  	LinkIDLen = 32
    27  )
    28  
    29  type LinkID []byte
    30  
    31  func GetLinkID(w *jsonw.Wrapper) (LinkID, error) {
    32  	if w.IsNil() {
    33  		return nil, nil
    34  	}
    35  	s, err := w.GetString()
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	ret, err := LinkIDFromHex(s)
    40  	return ret, err
    41  }
    42  
    43  func ImportLinkID(i keybase1.LinkID) (LinkID, error) {
    44  	return LinkIDFromHex(string(i))
    45  }
    46  
    47  func GetLinkIDVoid(w *jsonw.Wrapper, l *LinkID, e *error) {
    48  	ret, err := GetLinkID(w)
    49  	if err != nil {
    50  		*e = err
    51  	} else {
    52  		*l = ret
    53  	}
    54  }
    55  
    56  func (l *LinkID) UnmarshalJSON(b []byte) error {
    57  	lid, err := LinkIDFromHex(keybase1.Unquote(b))
    58  	if err != nil {
    59  		return err
    60  	}
    61  	*l = make([]byte, len(lid))
    62  	copy((*l)[:], lid[:])
    63  	return nil
    64  }
    65  
    66  func (l *LinkID) MarshalJSON() ([]byte, error) {
    67  	return keybase1.Quote(l.String()), nil
    68  }
    69  
    70  func LinkIDFromHex(s string) (LinkID, error) {
    71  	bv, err := hex.DecodeString(s)
    72  	if err == nil && len(bv) != LinkIDLen {
    73  		err = fmt.Errorf("Bad link ID; wrong length: %d", len(bv))
    74  		bv = nil
    75  	}
    76  	var ret LinkID
    77  	if bv != nil {
    78  		ret = LinkID(bv)
    79  	}
    80  	return ret, err
    81  }
    82  
    83  func (l LinkID) String() string {
    84  	return hex.EncodeToString(l)
    85  }
    86  
    87  func (l LinkID) Eq(i2 LinkID) bool {
    88  	if l == nil && i2 == nil {
    89  		return true
    90  	} else if l == nil || i2 == nil {
    91  		return false
    92  	} else {
    93  		return FastByteArrayEq(l[:], i2[:])
    94  	}
    95  }
    96  
    97  type ChainLinkUnpacked struct {
    98  	prev                               LinkID
    99  	seqno                              keybase1.Seqno
   100  	highSkip                           *HighSkip
   101  	seqType                            keybase1.SeqType
   102  	ignoreIfUnsupported                SigIgnoreIfUnsupported
   103  	payloadLocal                       []byte // local track payloads
   104  	payloadV2                          []byte
   105  	ctime, etime                       int64
   106  	pgpFingerprint                     *PGPFingerprint
   107  	kid                                keybase1.KID
   108  	eldestKID                          keybase1.KID
   109  	sig                                string
   110  	sigID                              keybase1.SigID
   111  	uid                                keybase1.UID
   112  	username                           string
   113  	typ                                string
   114  	proofText                          string
   115  	outerLinkV2                        *OuterLinkV2WithMetadata
   116  	sigVersion                         SigVersion // what the server hints is the sig version (must be verified)
   117  	stubbed                            bool
   118  	firstAppearedMerkleSeqnoUnverified keybase1.Seqno
   119  	payloadHash                        []byte
   120  	sigDropped                         bool
   121  	hasRevocations                     bool
   122  	merkleSeqno                        keybase1.Seqno
   123  	merkleHashMeta                     keybase1.HashMeta
   124  }
   125  
   126  // A template for some of the reasons in badChainLinks below.
   127  const badAkalin = "Link %d of akalin's sigchain, which was accidentally added by an old client in development on 23 Mar 2015 20:02 GMT."
   128  const badJamGregory = "Link %d of jamgregory's sigchain, which had a bad PGP keypin"
   129  const badDens = "Link 8 of dens's sigchain, which signs in a revoked PGP key"
   130  const badAjar = "Link 98 of ajar's sigchain allowed a PGP update with a broken PGP key"
   131  const badJaccarmac = "Link 46 of jaccarmac's sigchain, which signs in a revoked PGP key (key later removed in link 46)"
   132  
   133  const akalin = keybase1.UID("ebbe1d99410ab70123262cf8dfc87900")
   134  const jamGregory = keybase1.UID("e8767e19a3ed9c7350847b7b040de319")
   135  const dens = keybase1.UID("ca9e948f6f7a4a19e02058ad626f6c19")
   136  const ajar = keybase1.UID("d1d94b3131e493dfee738802843f7719")
   137  const jaccarmac = keybase1.UID("bfd01fc0a2d5ee0462aaa3c598210b00")
   138  
   139  type SpecialChainLink struct {
   140  	UID    keybase1.UID
   141  	Seqno  keybase1.Seqno
   142  	Reason string
   143  }
   144  
   145  // A map from SigIDs of bad chain links that should be ignored to the
   146  // reasons why they're ignored.
   147  var badChainLinks = map[keybase1.LinkID]SpecialChainLink{
   148  	// Links 22-25 of akalin's sigchain, which was accidentally
   149  	// added by an old client in development on 3/23/2015, 9:02am.
   150  	// Links 17-19 of jamGregory's sigchain, which referred to a corrupted
   151  	// PGP key. See https://github.com/keybase/client/issues/1908
   152  	// Link 8 of dens's sigchain is to a revoked PGP key, which wasn't
   153  	// properly checked for on the server side.
   154  	// See: https://github.com/keybase/client/issues/4754
   155  	// Link 98 of ajar's sigchain is a PGP update with a broken PGP key,
   156  	// that doesn't have a valid cross-sig on a signing key. It was a server
   157  	// bug to allow it be uploaded.
   158  	// Link 46 of jaccarmac's sigchain is a PGP delegation with a revoked PGP
   159  	// key. The self signature is invalid (revoked key signs over itself, and
   160  	// that signature cannot be verified, because the key is revoked). That
   161  	// wasn't properly rejected on the server because of the same bug as in
   162  	// "Link 8 of den's sigchain".
   163  	// See: https://github.com/keybase/client/issues/24176
   164  	"694ed7166cee72449964e97bcd4be58243877718425c4dc655d2d80832bd5cdf": {UID: akalin, Seqno: keybase1.Seqno(22), Reason: fmt.Sprintf(badAkalin, 22)},
   165  	"27bc88059a768a82b1a21dcc1c46f7fc61c2d2b80c445eb2d18fed3a5bb42e49": {UID: akalin, Seqno: keybase1.Seqno(23), Reason: fmt.Sprintf(badAkalin, 23)},
   166  	"12b594e44d9289349283f8b14a6f83ad144a17a3025a758e17d4eca70fbdc923": {UID: akalin, Seqno: keybase1.Seqno(24), Reason: fmt.Sprintf(badAkalin, 24)},
   167  	"ce162011e380c954de15f30db28f8b7b358866d2721143d9d0d4424166ce5ed8": {UID: akalin, Seqno: keybase1.Seqno(25), Reason: fmt.Sprintf(badAkalin, 25)},
   168  	"bf914e6d4cf9b4eb7c88c2a8a6f5650e969ade9a97cf1605c1eb8cae97d5d278": {UID: jamGregory, Seqno: keybase1.Seqno(17), Reason: fmt.Sprintf(badJamGregory, 17)},
   169  	"e56f492c1b519905d04ce51368e87794963906dd6dacb63fbeab7ad23596af29": {UID: jamGregory, Seqno: keybase1.Seqno(18), Reason: fmt.Sprintf(badJamGregory, 18)},
   170  	"51e46dad8b71a1a7204368f9cb4931257a32eed92cf3b97a08190c12912739dd": {UID: jamGregory, Seqno: keybase1.Seqno(19), Reason: fmt.Sprintf(badJamGregory, 19)},
   171  	"6d527d776cb28ea980c6e0474286fe745377e116fd5d07b44928d165ae4b7c97": {UID: dens, Seqno: keybase1.Seqno(8), Reason: badDens},
   172  	"9b3b3a3d973449ca3238bf59b7407186dc80242b917c158cba5e374595257dd0": {UID: ajar, Seqno: keybase1.Seqno(98), Reason: badAjar},
   173  	"496b0328664a7c8115449f3fb17d137990c52712797730ede9c4b8ceb942e6ea": {UID: jaccarmac, Seqno: keybase1.Seqno(46), Reason: badJaccarmac},
   174  }
   175  
   176  // Some chainlinks are broken and need a small whitespace addition to match their payload
   177  // hash in subsequent chainlinks.  Caused by bad code on 15 Sep 2015.
   178  const whitespaceIssue20150915 = "Bad whitespace stripping on 15 Sep 2015"
   179  
   180  var badWhitespaceChainLinks = map[keybase1.LinkID]string{
   181  	"ac3ecaa2aa1d638867026f0c54a1d895777f366d02bfef37403275aa0d4f8322": whitespaceIssue20150915,
   182  	"94fde9d49c29cba59c949b35dd424de3a0daccf8a04ba443833e3328d495b9d8": whitespaceIssue20150915,
   183  	"b9f188d0c6638e3bef3dfc3476c04078bb2aef2a9249cc77b6f009692967388a": whitespaceIssue20150915,
   184  	"f5f324e91a94c073fdc936b50d56250133dc19415ae592d2c7cb99db9e980e1b": whitespaceIssue20150915,
   185  	"03fb1e2c0e61e3715c41515045d89d2f788dbcc7eb671b94ac12ee5f805bbe70": whitespaceIssue20150915,
   186  	"e449b1cd1d6f2a86a0f800c47e7d1ad26bbb6c76b983bd78154972c51f77e960": whitespaceIssue20150915,
   187  	"d380d18672da3c18f0804baf6b28f5efda76d64220a152c000f2b3f9af8b6603": whitespaceIssue20150915,
   188  	"5957f583bec18cc6f381355843c21f903fe47d584a9816e072f3f102f1f488be": whitespaceIssue20150915,
   189  	"2c11a140d8f231af6d69543474138a503191486ae6b5739892c5e0c6c0c4c348": whitespaceIssue20150915,
   190  	"6f3d73ddf575f2033a48268a564575e40edbb5111cc057984f51f463d4e8ed58": whitespaceIssue20150915,
   191  	"b23dfd34e58a814543e1f8368b9d07922abec213afca6d2b76722825794acffa": whitespaceIssue20150915,
   192  	"2efe839231d6b03f85ab3c542e870e7062329a8c5e384f1289b00be7c7afb8ab": whitespaceIssue20150915,
   193  	"18688c45cbe05ee2b72567acc696b3856f9876dff0ec3ea927ad7632a3f48fe6": whitespaceIssue20150915,
   194  	"2cf8b9ffa500089b6db873acbabdba771e8e897c0a899a01f8967a7280cfd0da": whitespaceIssue20150915,
   195  	"acf150b2d57a3aa65574bc2bb97e224413ce3f5344fd24fc7c3282da48cc2f3d": whitespaceIssue20150915,
   196  	"371f9ae63d56ec853fa53941e79d29abbb4cd11aa926715d354d18d687b0ca71": whitespaceIssue20150915,
   197  	"4948115615d7dceb90bcdd818f69b66b5899339a2b747b5e6dc0f6987abbcbd0": whitespaceIssue20150915,
   198  	"4c3f7855eb307aa5620962e15de84b2cfe3f728a9722c43906b12e0f3082cb87": whitespaceIssue20150915,
   199  	"9db59496652a1587ed56ec6ae15917b6d0ef4ac9a14dda97bfa4d2427a80e2b8": whitespaceIssue20150915,
   200  	"43f21601ffaeae70eca2f585949f42c67e85e93cf2a6847d6c20ffd81a9ff890": whitespaceIssue20150915,
   201  	"7560f896c19457365225f48be0217b8a00519f1daccefee4c097dd1b4594dd66": whitespaceIssue20150915,
   202  	"09527db7672bf23a9681ac86c70826cdc01ed1e467252a76ca4bf4ad0964efd7": whitespaceIssue20150915,
   203  	"3803be27ec0c61b3fdcd8b9b7c78de3df73766736ef00727267858d34a039c7d": whitespaceIssue20150915,
   204  	"740f9140a7901defaaaec10042722b30d2fee457337b7ae8e9de3b9fc05d109f": whitespaceIssue20150915,
   205  	"32f5dd2643eabf3828f7f03ccded07d8d8a29e352df6130c3a4232104398d819": whitespaceIssue20150915,
   206  	"7d97355e5917c5bcc14ba3a1994398b3fa36416768b663c1454069de84a4fca2": whitespaceIssue20150915,
   207  	"720b80b7c15cb9a3d21a2eec228bceb5db6f0ef54df2d0aef08aec5ed1632257": whitespaceIssue20150915,
   208  	"12c9203c98fe0b1c80a551f8933b2c870fcc3754a8ea05591e43a4d528fadc68": whitespaceIssue20150915,
   209  	"9644d4db6a4928ad1075a22b4473d1efa47c99a1a2a779450d4cd67d9115b9ba": whitespaceIssue20150915,
   210  	"605525686fef18180be692df6106c13dae39abb2799dc9e8bed1e2bb64e9b886": whitespaceIssue20150915,
   211  	"374f1da46fd8238ab9f288183cb78f3c6a59732f4b19705763c9d6ac356015ef": whitespaceIssue20150915,
   212  	"893567013c77f45755279bf1138fecbb54cd3a55bf5814504cf0406acbe4bfeb": whitespaceIssue20150915,
   213  	"3ca5ef6a6115a8a86d7d94cb3565f43f05f7975d66015455dd6cc32b73936177": whitespaceIssue20150915,
   214  	"3cdd165df44ba7f8331b89213f213dab36482ef513d023c5d2b0f6bfd11d5678": whitespaceIssue20150915,
   215  	"36328ab1cf15cc3dd2ba4c771ca1066b2d44714780ad8e83894611e2a2642003": whitespaceIssue20150915,
   216  	"61e9f4b437fccac8abd396acfc96b17558c9c355b57f4a5f2f3698e78f19532f": whitespaceIssue20150915,
   217  	"14ef90159164e19228ff21c909b764e239f27f0fff49f86414a2dde9b719845f": whitespaceIssue20150915,
   218  	"b74b420f49b771ec04e656101f86c9729cf328b0fd32f5082d04d3c39f8ccea7": whitespaceIssue20150915,
   219  	"7772c99774570202a2c5ac017eefc8296f613e64c8d4adff4ba7991b553431f5": whitespaceIssue20150915,
   220  	"d7ae76e4fdae7034b07e515d5684adcd51afea5a22b8520d2c61d31f5028fc6e": whitespaceIssue20150915,
   221  	"33a61f19c0ca52257214f97524ef10441cf85215ff171868f53561dfd7b14c81": whitespaceIssue20150915,
   222  	"616d9710b3a594ab00292d3d414e6e141929935a133bfa9a25ec4a155a403e5c": whitespaceIssue20150915,
   223  	"8d7c1a0c99186f972afc5d3624aca2f88ddc3a5dbf84e826ef0b520c31a78aa3": whitespaceIssue20150915,
   224  	"9f8c0a29a6ba3a521db2cd4d3e2ae15223dbcd5d5d1201e33ebb2dee1b61342f": whitespaceIssue20150915,
   225  	"a9efa00bc479cb40ac0521749520f5a7a38a4ba4e698ee03355a85a8464b3840": whitespaceIssue20150915,
   226  	"f1509495f4f1d46e43dcdd341156b975f7ad19aefeb250a80fd2b236c517a891": whitespaceIssue20150915,
   227  	"da99975f9ae8cdeb9e3a42a1166617dbf6afbcf841919dcf05145a73a7026cc2": whitespaceIssue20150915,
   228  }
   229  
   230  type ChainLink struct {
   231  	Contextified
   232  	parent            *SigChain
   233  	id                LinkID
   234  	diskVersion       int
   235  	hashVerified      bool
   236  	sigVerified       bool
   237  	payloadVerified   bool
   238  	chainVerified     bool
   239  	highChainVerified bool
   240  	storedLocally     bool
   241  	revoked           bool
   242  	dirty             bool
   243  	revocationsCache  *[]keybase1.SigID
   244  	computedHighSkip  *HighSkip
   245  
   246  	unpacked *ChainLinkUnpacked
   247  	cki      *ComputedKeyInfos
   248  
   249  	typed                  TypedChainLink
   250  	isOwnNewLinkFromServer bool
   251  }
   252  
   253  // See NCC-KB2018-006
   254  func (c ChainLink) checkSpecialLinksTable(tab map[keybase1.LinkID]SpecialChainLink, uid keybase1.UID, why string) (found bool, reason string, err error) {
   255  	var scl SpecialChainLink
   256  
   257  	// The truthiness of hashVerified should ensure that this link
   258  	// is only considered here after all prevs have been successfully checked.
   259  	if !c.canTrustID() {
   260  		return false, "", ChainLinkError{fmt.Sprintf("cannot check if a link is %q without a verified link ID (linkID=%s, uid=%s, hash=%v, chain=%v, diskVersion=%d)", why, c.id, uid, c.hashVerified, c.chainVerified, c.diskVersion)}
   261  	}
   262  
   263  	scl, found = tab[c.LinkID().Export()]
   264  	if !found {
   265  		return false, "", nil
   266  	}
   267  	if !c.GetSeqno().Eq(scl.Seqno) {
   268  		return false, "", NewChainLinkWrongSeqnoError(fmt.Sprintf("malicious bad link in from server has wrong seqno in %q check: %d != %d", why, c.GetSeqno(), scl.Seqno))
   269  	}
   270  	if !scl.UID.Equal(uid) {
   271  		return false, "", NewUIDMismatchError(fmt.Sprintf("malicious bad link from server in %q check; UID %s != %s", why, scl.UID, uid))
   272  	}
   273  	return true, scl.Reason, nil
   274  }
   275  
   276  func (c *ChainLink) IsBad() (isBad bool, reason string, err error) {
   277  	return c.checkSpecialLinksTable(badChainLinks, c.parent.uid, "bad chain links")
   278  }
   279  
   280  func (c *ChainLink) Parent() *SigChain {
   281  	return c.parent
   282  }
   283  
   284  func (c *ChainLink) SetParent(parent *SigChain) {
   285  	if c.parent != nil {
   286  		c.G().Log.Warning("changing ChainLink parent")
   287  	}
   288  	c.parent = parent
   289  }
   290  
   291  func (c *ChainLink) getPrevFromPayload() LinkID {
   292  	return c.unpacked.prev
   293  }
   294  
   295  func (c *ChainLink) getSeqTypeFromPayload() keybase1.SeqType {
   296  	return c.unpacked.seqType
   297  }
   298  
   299  func (c *ChainLink) getIgnoreIfUnsupportedFromPayload() SigIgnoreIfUnsupported {
   300  	return c.unpacked.ignoreIfUnsupported
   301  }
   302  
   303  func (c *ChainLink) GetIgnoreIfSupported() SigIgnoreIfUnsupported {
   304  	return c.getIgnoreIfUnsupportedFromPayload()
   305  }
   306  
   307  func (c *ChainLink) getHighSkipFromPayload() *HighSkip {
   308  	return c.unpacked.highSkip
   309  }
   310  
   311  func (c *ChainLink) IsStubbed() bool {
   312  	return c.unpacked.stubbed
   313  }
   314  
   315  func (c *ChainLink) IsEldest() bool {
   316  	if c.unpacked == nil {
   317  		return false
   318  	}
   319  	if c.unpacked.outerLinkV2 != nil {
   320  		return c.unpacked.outerLinkV2.LinkType == SigchainV2TypeEldest
   321  	}
   322  	if c.unpacked.typ == string(DelegationTypeEldest) {
   323  		return true
   324  	}
   325  	return false
   326  }
   327  
   328  func (c *ChainLink) GetPrev() LinkID {
   329  	return c.unpacked.prev
   330  }
   331  
   332  func (c *ChainLink) GetCTime() time.Time {
   333  	if c.IsStubbed() {
   334  		return time.Time{}
   335  	}
   336  
   337  	return time.Unix(c.unpacked.ctime, 0)
   338  }
   339  
   340  func (c *ChainLink) GetETime() time.Time {
   341  	if c.IsStubbed() {
   342  		return time.Time{}
   343  	}
   344  	return UnixToTimeMappingZero(c.unpacked.etime)
   345  }
   346  
   347  func (c *ChainLink) GetFirstAppearedMerkleSeqnoUnverified() keybase1.Seqno {
   348  	if c.IsStubbed() {
   349  		return keybase1.Seqno(0)
   350  	}
   351  	return c.unpacked.firstAppearedMerkleSeqnoUnverified
   352  }
   353  
   354  func (c *ChainLink) GetUID() keybase1.UID {
   355  	return c.unpacked.uid
   356  }
   357  
   358  func (c *ChainLink) UnmarshalPayloadJSON() *jsonw.Wrapper {
   359  	jw, err := c.G().PayloadCache.GetOrPrime(c)
   360  	if err != nil {
   361  		// Any unmarshal error here would already have
   362  		// happened in Unpack
   363  		return nil
   364  	}
   365  	return jw
   366  }
   367  
   368  func (c *ChainLink) ToSigChainLocation() keybase1.SigChainLocation {
   369  	return keybase1.SigChainLocation{
   370  		Seqno: c.GetSeqno(),
   371  		// This code is meant only for user chains
   372  		SeqType: keybase1.SeqType_PUBLIC,
   373  	}
   374  }
   375  
   376  const chainLinkDiskVersion = 1
   377  
   378  func (c *ChainLink) canTrustID() bool {
   379  	return c.hashVerified || (c.storedLocally && c.diskVersion < 2)
   380  }
   381  
   382  func (c *ChainLink) Pack() (*jsonw.Wrapper, error) {
   383  	p := jsonw.NewDictionary()
   384  
   385  	if c.IsStubbed() {
   386  		err := p.SetKey("s2", jsonw.NewString(c.unpacked.outerLinkV2.EncodeStubbed()))
   387  		if err != nil {
   388  			return nil, err
   389  		}
   390  	} else {
   391  		// store the payload for v2 links and local tracks
   392  		if c.unpacked.sigVersion == KeybaseSignatureV2 {
   393  			err := p.SetKey("payload_json", jsonw.NewString(string(c.unpacked.payloadV2)))
   394  			if err != nil {
   395  				return nil, err
   396  			}
   397  		} else if len(c.unpacked.payloadLocal) > 0 {
   398  			err := p.SetKey("payload_json", jsonw.NewString(string(c.unpacked.payloadLocal)))
   399  			if err != nil {
   400  				return nil, err
   401  			}
   402  		}
   403  
   404  		err := p.SetKey("sig", jsonw.NewString(c.unpacked.sig))
   405  		if err != nil {
   406  			return nil, err
   407  		}
   408  		err = p.SetKey("sig_id", jsonw.NewString(string(c.unpacked.sigID)))
   409  		if err != nil {
   410  			return nil, err
   411  		}
   412  		err = p.SetKey("kid", c.unpacked.kid.ToJsonw())
   413  		if err != nil {
   414  			return nil, err
   415  		}
   416  		err = p.SetKey("ctime", jsonw.NewInt64(c.unpacked.ctime))
   417  		if err != nil {
   418  			return nil, err
   419  		}
   420  		if c.unpacked.pgpFingerprint != nil {
   421  			err := p.SetKey("fingerprint", jsonw.NewString(c.unpacked.pgpFingerprint.String()))
   422  			if err != nil {
   423  				return nil, err
   424  			}
   425  		}
   426  		err = p.SetKey("sig_verified", jsonw.NewBool(c.sigVerified))
   427  		if err != nil {
   428  			return nil, err
   429  		}
   430  		err = p.SetKey("chain_verified", jsonw.NewBool(c.chainVerified))
   431  		if err != nil {
   432  			return nil, err
   433  		}
   434  		err = p.SetKey("hash_verified", jsonw.NewBool(c.hashVerified))
   435  		if err != nil {
   436  			return nil, err
   437  		}
   438  		err = p.SetKey("payload_verified", jsonw.NewBool(c.payloadVerified))
   439  		if err != nil {
   440  			return nil, err
   441  		}
   442  		err = p.SetKey("proof_text_full", jsonw.NewString(c.unpacked.proofText))
   443  		if err != nil {
   444  			return nil, err
   445  		}
   446  		err = p.SetKey("sig_version", jsonw.NewInt(int(c.unpacked.sigVersion)))
   447  		if err != nil {
   448  			return nil, err
   449  		}
   450  		err = p.SetKey("merkle_seqno", jsonw.NewInt64(int64(c.unpacked.firstAppearedMerkleSeqnoUnverified)))
   451  		if err != nil {
   452  			return nil, err
   453  		}
   454  		err = p.SetKey("disk_version", jsonw.NewInt(chainLinkDiskVersion))
   455  		if err != nil {
   456  			return nil, err
   457  		}
   458  	}
   459  
   460  	if c.cki != nil {
   461  		err := p.SetKey("computed_key_infos", jsonw.NewWrapper(*c.cki))
   462  		if err != nil {
   463  			return nil, err
   464  		}
   465  	}
   466  
   467  	return p, nil
   468  }
   469  
   470  func (c *ChainLink) GetMerkleSeqno() keybase1.Seqno {
   471  	if c.IsStubbed() {
   472  		return 0
   473  	}
   474  	return c.unpacked.merkleSeqno
   475  }
   476  
   477  func (c *ChainLink) GetMerkleHashMeta() (keybase1.HashMeta, error) {
   478  	if c.IsStubbed() {
   479  		return nil, nil
   480  	}
   481  	return c.unpacked.merkleHashMeta, nil
   482  }
   483  
   484  func (c *ChainLink) HasRevocations() bool {
   485  	if c.IsStubbed() {
   486  		return false
   487  	}
   488  	if c.unpacked != nil {
   489  		return c.unpacked.hasRevocations
   490  	}
   491  	return false
   492  }
   493  
   494  func (tmp *ChainLinkUnpacked) HasRevocations(payload []byte) bool {
   495  	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "sig_id"); err == nil {
   496  		return true
   497  	}
   498  	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "sig_ids", "[0]"); err == nil {
   499  		return true
   500  	}
   501  	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "kid"); err == nil {
   502  		return true
   503  	}
   504  	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "kids", "[0]"); err == nil {
   505  		return true
   506  	}
   507  	return false
   508  }
   509  
   510  func (c *ChainLink) GetRevocations() []keybase1.SigID {
   511  	if c.IsStubbed() {
   512  		return nil
   513  	}
   514  	if c.revocationsCache != nil {
   515  		return *c.revocationsCache
   516  	}
   517  	payload, err := c.unpacked.Payload()
   518  	if err != nil {
   519  		return nil
   520  	}
   521  	var ret []keybase1.SigID
   522  	if !bytes.Contains(payload, []byte("revoke")) {
   523  		c.revocationsCache = &ret
   524  		return nil
   525  	}
   526  	if s, err := jsonparserw.GetString(payload, "body", "revoke", "sig_id"); err == nil {
   527  		if sigID, err := keybase1.SigIDFromString(s); err == nil {
   528  			ret = append(ret, sigID)
   529  		}
   530  	}
   531  
   532  	_, _ = jsonparserw.ArrayEach(payload, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
   533  		if s, err := keybase1.SigIDFromString(string(value)); err == nil {
   534  			ret = append(ret, s)
   535  		}
   536  	}, "body", "revoke", "sig_ids")
   537  
   538  	c.revocationsCache = &ret
   539  	return ret
   540  }
   541  
   542  func (c *ChainLink) GetRevokeKids() []keybase1.KID {
   543  	if c.IsStubbed() {
   544  		return nil
   545  	}
   546  
   547  	payload, err := c.unpacked.Payload()
   548  	if err != nil {
   549  		return nil
   550  	}
   551  	var ret []keybase1.KID
   552  	if s, err := jsonparserw.GetString(payload, "body", "revoke", "kid"); err == nil {
   553  		ret = append(ret, keybase1.KIDFromString(s))
   554  	}
   555  
   556  	_, _ = jsonparserw.ArrayEach(payload, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
   557  		ret = append(ret, keybase1.KIDFromString(string(value)))
   558  	}, "body", "revoke", "kids")
   559  
   560  	return ret
   561  }
   562  
   563  func (c *ChainLink) checkAgainstMerkleTree(t *MerkleTriple) (found bool, err error) {
   564  	if c.IsStubbed() {
   565  		return false, ChainLinkError{"cannot check stubbed link against the merkle tree"}
   566  	}
   567  	found = false
   568  	if t != nil && c.GetSeqno() == t.Seqno {
   569  		c.G().Log.Debug("| Found chain tail advertised in Merkle tree @%d", int(t.Seqno))
   570  		found = true
   571  		if !c.id.Eq(t.LinkID) {
   572  			err = fmt.Errorf("Bad chain ID at seqno=%d", int(t.Seqno))
   573  		}
   574  	}
   575  	return
   576  }
   577  
   578  func getSigVersionFromPayload(payload []byte) (SigVersion, error) {
   579  	var err error
   580  	var i int64
   581  	if i, err = jsonparserw.GetInt(payload, "body", "version"); err != nil {
   582  		return KeybaseNullSigVersion, ChainLinkError{"link is missing a version field"}
   583  	}
   584  	return SigVersion(int(i)), nil
   585  }
   586  
   587  func (tmp *ChainLinkUnpacked) parseHighSkipFromPayload(payload []byte) (*HighSkip, error) {
   588  	hs, dataType, _, err := jsonparserw.Get(payload, "high_skip")
   589  	// high_skip is optional, but must be an object if it exists
   590  	if err != nil {
   591  		switch pkgerrors.Cause(err) {
   592  		case jsonparser.KeyPathNotFoundError:
   593  			return nil, nil
   594  		default:
   595  			return nil, err
   596  		}
   597  	}
   598  
   599  	if dataType != jsonparser.Object {
   600  		return nil, ChainLinkError{fmt.Sprintf("When provided, expected high_skip to be a JSON object, was %v.", dataType)}
   601  	}
   602  
   603  	highSkipSeqnoInt, err := jsonparserw.GetInt(hs, "seqno")
   604  	if err != nil {
   605  		return nil, err
   606  	}
   607  
   608  	// highSkipHash can either be null (zero-value of a LinkID) or a hexstring.
   609  	// We call GetString first instead of Get so we only parse the value
   610  	// twice for the first link.
   611  	highSkipHashStr, err := jsonparserw.GetString(hs, "hash")
   612  	var highSkipHash LinkID
   613  	if err != nil {
   614  		// If there was an error parsing as a string, make sure the value is null.
   615  		_, dataType, _, getErr := jsonparserw.Get(hs, "hash")
   616  		if getErr != nil {
   617  			return nil, getErr
   618  		}
   619  		if dataType != jsonparser.Null {
   620  			return nil, ChainLinkError{
   621  				fmt.Sprintf("high_skip.hash was neither a valid string (%v) nor null.", err.Error()),
   622  			}
   623  		}
   624  	} else {
   625  		highSkipHash, err = LinkIDFromHex(highSkipHashStr)
   626  		if err != nil {
   627  			return nil, err
   628  		}
   629  	}
   630  
   631  	highSkip := NewHighSkip(keybase1.Seqno(highSkipSeqnoInt), highSkipHash)
   632  	return &highSkip, nil
   633  }
   634  
   635  func (tmp *ChainLinkUnpacked) unpackPayloadJSON(g *GlobalContext, payload []byte, linkID LinkID) error {
   636  
   637  	if !isJSONObject(payload, linkID) {
   638  		return ChainLinkError{"chain link is not a valid JSON object as expected; found leading junk"}
   639  	}
   640  
   641  	if s, err := jsonparserw.GetString(payload, "body", "key", "fingerprint"); err == nil {
   642  		if tmp.pgpFingerprint, err = PGPFingerprintFromHex(s); err != nil {
   643  			return err
   644  		}
   645  	}
   646  	if s, err := jsonparserw.GetString(payload, "body", "key", "kid"); err == nil {
   647  		tmp.kid = keybase1.KIDFromString(s)
   648  	}
   649  	if s, err := jsonparserw.GetString(payload, "body", "key", "eldest_kid"); err == nil {
   650  		tmp.eldestKID = keybase1.KIDFromString(s)
   651  	}
   652  
   653  	var err error
   654  	tmp.username, err = jsonparserw.GetString(payload, "body", "key", "username")
   655  	if err != nil {
   656  		return err
   657  	}
   658  	suid, err := jsonparserw.GetString(payload, "body", "key", "uid")
   659  	if err != nil {
   660  		return err
   661  	}
   662  	if tmp.uid, err = UIDFromHex(suid); err != nil {
   663  		return err
   664  	}
   665  
   666  	if prev, err := jsonparserw.GetString(payload, "prev"); err == nil {
   667  		tmp.prev, err = LinkIDFromHex(prev)
   668  		if err != nil {
   669  			return err
   670  		}
   671  	}
   672  
   673  	highSkip, err := tmp.parseHighSkipFromPayload(payload)
   674  	if err != nil {
   675  		return err
   676  	}
   677  	tmp.highSkip = highSkip
   678  
   679  	tmp.typ, err = jsonparserw.GetString(payload, "body", "type")
   680  	if err != nil {
   681  		return err
   682  	}
   683  
   684  	tmp.ctime, err = jsonparserw.GetInt(payload, "ctime")
   685  	if err != nil {
   686  		return err
   687  	}
   688  
   689  	seqno, err := jsonparserw.GetInt(payload, "seqno")
   690  	if err != nil {
   691  		return err
   692  	}
   693  	tmp.seqno = keybase1.Seqno(seqno)
   694  
   695  	if tmp.HasRevocations(payload) {
   696  		tmp.hasRevocations = true
   697  	}
   698  
   699  	// Assume public unless its a number
   700  	tmp.seqType = keybase1.SeqType_PUBLIC
   701  	if seqTypeInt, err := jsonparserw.GetInt(payload, "seq_type"); err == nil {
   702  		tmp.seqType = keybase1.SeqType(seqTypeInt)
   703  	}
   704  
   705  	// Assume false if unsupported
   706  	tmp.ignoreIfUnsupported = SigIgnoreIfUnsupported(false)
   707  	if ignore, err := jsonparserw.GetBoolean(payload, "ignore_if_unsupported"); err == nil {
   708  		tmp.ignoreIfUnsupported = SigIgnoreIfUnsupported(ignore)
   709  	}
   710  
   711  	// Due to an earlier error, it's possible for the merkle root that we signed over
   712  	// to be in one of two places, so check both.
   713  	if i, err := jsonparserw.GetInt(payload, "body", "merkle_root", "seqno"); err == nil {
   714  		tmp.merkleSeqno = keybase1.Seqno(i)
   715  	} else if i, err := jsonparserw.GetInt(payload, "merkle_root", "seqno"); err == nil {
   716  		tmp.merkleSeqno = keybase1.Seqno(i)
   717  	}
   718  
   719  	// Hash meta was only ever in the correct place (within body)
   720  	if s, err := jsonparserw.GetString(payload, "body", "merkle_root", "hash_meta"); err == nil {
   721  		tmp.merkleHashMeta, err = keybase1.HashMetaFromString(s)
   722  		if err != nil {
   723  			return err
   724  		}
   725  	}
   726  
   727  	ei, err := jsonparserw.GetInt(payload, "expire_in")
   728  	if err != nil {
   729  		return err
   730  	}
   731  
   732  	tmp.etime = tmp.ctime + ei
   733  
   734  	tmp.payloadHash = fixAndHashPayload(g, payload, linkID)
   735  
   736  	if tmp.sigVersion == KeybaseSignatureV2 {
   737  		tmp.payloadV2 = payload
   738  	}
   739  
   740  	return nil
   741  }
   742  
   743  func (c *ChainLink) UnpackLocal(payload []byte) (err error) {
   744  	tmp := ChainLinkUnpacked{}
   745  	err = tmp.unpackPayloadJSON(c.G(), payload, c.id)
   746  	if err == nil {
   747  		tmp.payloadLocal = payload
   748  		c.unpacked = &tmp
   749  	}
   750  	return
   751  }
   752  
   753  func (c *ChainLink) UnpackComputedKeyInfos(data []byte) error {
   754  	if data == nil {
   755  		return nil
   756  	}
   757  	var tmp ComputedKeyInfos
   758  	tmp.SetGlobalContext(c.G())
   759  	if err := json.Unmarshal(data, &tmp); err == nil {
   760  		c.cki = &tmp
   761  	} else {
   762  		return err
   763  	}
   764  	return nil
   765  }
   766  
   767  func (c *ChainLink) unpackStubbed(raw string) error {
   768  	ol, err := DecodeStubbedOuterLinkV2(raw)
   769  	if err != nil {
   770  		return err
   771  	}
   772  	if ol.SeqType == 0 {
   773  		// Assume public if unset
   774  		ol.SeqType = keybase1.SeqType_PUBLIC
   775  	}
   776  
   777  	if !ol.IgnoreIfUnsupported.Bool() && !ol.LinkType.IsSupportedType() {
   778  		return ChainLinkStubbedUnsupportedError{fmt.Sprintf("Stubbed link with type %d is unknown and not marked with IgnoreIfUnsupported", ol.LinkType)}
   779  	}
   780  
   781  	c.id = ol.LinkID()
   782  
   783  	// Because the outer link does not have a highSkip parent object, we check
   784  	// for the nullity of highSkipSeqno to see if highSkip should be set, since
   785  	// a null highSkipHash is valid when specifying highSkip=0.
   786  	var highSkipPtr *HighSkip
   787  	if ol.HighSkipSeqno != nil {
   788  		highSkip := NewHighSkip(*ol.HighSkipSeqno, *ol.HighSkipHash)
   789  		highSkipPtr = &highSkip
   790  	}
   791  
   792  	c.unpacked = &ChainLinkUnpacked{
   793  		prev:                ol.Prev,
   794  		seqno:               ol.Seqno,
   795  		seqType:             ol.SeqType,
   796  		ignoreIfUnsupported: ol.IgnoreIfUnsupported,
   797  		highSkip:            highSkipPtr,
   798  		sigVersion:          ol.Version,
   799  		outerLinkV2:         ol,
   800  		stubbed:             true,
   801  	}
   802  	return nil
   803  }
   804  
   805  func (c *ChainLink) unpackFromLocalStorage(m MetaContext, selfUID keybase1.UID, packed []byte) error {
   806  	if s, err := jsonparserw.GetString(packed, "s2"); err == nil {
   807  		return c.unpackStubbed(s)
   808  	}
   809  
   810  	tmp := ChainLinkUnpacked{}
   811  	var err error
   812  	tmp.sig, err = jsonparserw.GetString(packed, "sig")
   813  	if err != nil {
   814  		return err
   815  	}
   816  
   817  	// Beware that this is server-untrusted data at this point. We'll have to check it
   818  	// before we can exit without error (see below).
   819  	tmp.sigVersion = KeybaseSignatureV1
   820  	if sv, err := jsonparserw.GetInt(packed, "sig_version"); err == nil {
   821  		tmp.sigVersion = SigVersion(int(sv))
   822  		if tmp.sigVersion != KeybaseSignatureV1 && tmp.sigVersion != KeybaseSignatureV2 {
   823  			return ChainLinkError{fmt.Sprintf("Bad sig_version: expected 1 or 2 but got %d", tmp.sigVersion)}
   824  		}
   825  	}
   826  
   827  	if i, err := jsonparserw.GetInt(packed, "merkle_seqno"); err == nil {
   828  		tmp.firstAppearedMerkleSeqnoUnverified = keybase1.Seqno(i)
   829  	}
   830  
   831  	var payload []byte
   832  	switch tmp.sigVersion {
   833  	case KeybaseSignatureV1:
   834  		// Use the payload from the signature here, since we always get the full signature with
   835  		// the attached payload for V1 signatures. Note that we redundantly check that the payload
   836  		// matches the sig in verifyPayloadV1() on the way out of this Unpack function.
   837  		payload, err = tmp.Payload()
   838  		if err != nil {
   839  			return err
   840  		}
   841  	case KeybaseSignatureV2:
   842  		// use the payload in payload_json
   843  		data, _, _, err := jsonparserw.Get(packed, "payload_json")
   844  		if err != nil {
   845  			return err
   846  		}
   847  
   848  		// unquote it
   849  		sdata, err := strconv.Unquote(`"` + string(data) + `"`)
   850  		if err != nil {
   851  			return err
   852  		}
   853  		payload = []byte(sdata)
   854  	default:
   855  		err = ChainLinkError{fmt.Sprintf("unhandled signature version %d", tmp.sigVersion)}
   856  		return err
   857  	}
   858  
   859  	// unpack the payload
   860  	if err := tmp.unpackPayloadJSON(c.G(), payload, c.id); err != nil {
   861  		m.Debug("unpack payload json err: %s", err)
   862  		return err
   863  	}
   864  
   865  	// We previously took the server's word on what version we wanted, but now
   866  	// we're going to check that it matches what we actually sign over -- what's
   867  	// in the JSON payload. If it doesn't match, the we error out right here.
   868  	if err := tmp.assertPayloadSigVersionMatchesHint(payload); err != nil {
   869  		return err
   870  	}
   871  
   872  	var sigKID, serverKID, payloadKID keybase1.KID
   873  
   874  	if tmp.sigVersion == KeybaseSignatureV2 {
   875  		var ol2 *OuterLinkV2WithMetadata
   876  		ol2, err = DecodeOuterLinkV2(tmp.sig)
   877  		if err != nil {
   878  			return err
   879  		}
   880  		if ol2.SeqType == 0 {
   881  			// Assume public if unset
   882  			ol2.SeqType = keybase1.SeqType_PUBLIC
   883  		}
   884  		tmp.outerLinkV2 = ol2
   885  		sigKID = ol2.kid
   886  	}
   887  
   888  	payloadKID = tmp.kid
   889  
   890  	if kid, err := jsonparserw.GetString(packed, "kid"); err == nil {
   891  		serverKID = keybase1.KIDFromString(kid)
   892  	}
   893  
   894  	if !payloadKID.IsNil() && !serverKID.IsNil() && !payloadKID.Equal(serverKID) {
   895  		return ChainLinkKIDMismatchError{
   896  			fmt.Sprintf("Payload KID (%s) doesn't match server KID (%s).",
   897  				payloadKID, serverKID),
   898  		}
   899  	}
   900  
   901  	if !payloadKID.IsNil() && !sigKID.IsNil() && !payloadKID.Equal(sigKID) {
   902  		return ChainLinkKIDMismatchError{
   903  			fmt.Sprintf("Payload KID (%s) doesn't match sig KID (%s).",
   904  				payloadKID, sigKID),
   905  		}
   906  	}
   907  
   908  	if !serverKID.IsNil() && !sigKID.IsNil() && !serverKID.Equal(sigKID) {
   909  		return ChainLinkKIDMismatchError{
   910  			fmt.Sprintf("Server KID (%s) doesn't match sig KID (%s).",
   911  				serverKID, sigKID),
   912  		}
   913  	}
   914  
   915  	if tmp.kid.IsNil() && !sigKID.IsNil() {
   916  		tmp.kid = sigKID
   917  	}
   918  	if tmp.kid.IsNil() && !serverKID.IsNil() {
   919  		tmp.kid = serverKID
   920  	}
   921  
   922  	// Note, we can still be in a situation in which don't know any kids!
   923  	// That would be bad *if* we need to verify the signature for this link.
   924  
   925  	// only unpack the proof_text_full if owner of this link
   926  	if tmp.uid.Equal(selfUID) {
   927  		if pt, err := jsonparserw.GetString(packed, "proof_text_full"); err == nil {
   928  			tmp.proofText = pt
   929  		}
   930  	}
   931  
   932  	c.unpacked = &tmp
   933  
   934  	// IF we're loaded from *trusted* storage, like our local
   935  	// DB, then we can skip verification later
   936  	if b, err := jsonparserw.GetBoolean(packed, "sig_verified"); err == nil && b {
   937  		c.sigVerified = true
   938  		m.VLogf(VLog1, "| Link is marked as 'sig_verified'")
   939  		if ckidata, _, _, err := jsonparserw.Get(packed, "computed_key_infos"); err == nil {
   940  			if uerr := c.UnpackComputedKeyInfos(ckidata); uerr != nil {
   941  				m.Warning("Problem unpacking computed key infos: %s", uerr)
   942  			}
   943  		}
   944  	}
   945  	if b, err := jsonparserw.GetBoolean(packed, "hash_verified"); err == nil && b {
   946  		c.hashVerified = true
   947  	}
   948  	if b, err := jsonparserw.GetBoolean(packed, "chain_verified"); err == nil && b {
   949  		c.chainVerified = true
   950  	}
   951  	if b, err := jsonparserw.GetBoolean(packed, "payload_verified"); err == nil && b {
   952  		c.payloadVerified = true
   953  	}
   954  	if i, err := jsonparserw.GetInt(packed, "disk_version"); err == nil {
   955  		c.diskVersion = int(i)
   956  	}
   957  
   958  	// It is not acceptable to digest sig_id from the server, but we do derive it
   959  	// as we unpack the server reply (see VerifyLink), and it is acceptable to
   960  	// read it out of a locally-stored chainlink. Note this field is required,
   961  	// and if we don't have it, there has been a major problem.
   962  	s, err := jsonparserw.GetString(packed, "sig_id")
   963  	if err != nil {
   964  		return err
   965  	}
   966  	c.unpacked.sigID, err = keybase1.SigIDFromString(s)
   967  	if err != nil {
   968  		return err
   969  	}
   970  
   971  	// sigID is set as a side effect of verifying the link. Make sure we do that
   972  	// on the way out of this function, before we return success. But it's not
   973  	// needed in the cased of a stubbed V2 link.
   974  	err = c.VerifyLink()
   975  	if err != nil {
   976  		return err
   977  	}
   978  
   979  	c.G().VDL.Log(VLog1, "| Unpacked Link %s", c.id)
   980  
   981  	return nil
   982  }
   983  
   984  func (tmp *ChainLinkUnpacked) Payload() ([]byte, error) {
   985  	// local track payloads are stored in ChainLinkUnpacked.
   986  	// if anything there, use it:
   987  	if len(tmp.payloadLocal) > 0 {
   988  		return tmp.payloadLocal, nil
   989  	}
   990  
   991  	switch tmp.sigVersion {
   992  	case KeybaseSignatureV1:
   993  		// v1 links have the payload inside the sig
   994  		sigPayload, _, _, err := SigExtractPayloadAndKID(tmp.sig)
   995  		return sigPayload, err
   996  	case KeybaseSignatureV2:
   997  		// v2 links have the payload in ChainLinkUnpacked
   998  		return tmp.payloadV2, nil
   999  	default:
  1000  		return nil, ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", tmp.sigVersion)}
  1001  	}
  1002  }
  1003  
  1004  func (tmp *ChainLinkUnpacked) assertPayloadSigVersionMatchesHint(payload []byte) error {
  1005  	payloadVersion, err := getSigVersionFromPayload(payload)
  1006  	if err != nil {
  1007  		return err
  1008  	}
  1009  	if tmp.sigVersion != payloadVersion {
  1010  		return ChainLinkError{msg: fmt.Sprintf("Big sigchain version hint from server: %d != %d", tmp.sigVersion, payloadVersion)}
  1011  	}
  1012  	return nil
  1013  }
  1014  
  1015  func (c *ChainLink) CheckNameAndID(s NormalizedUsername, i keybase1.UID) error {
  1016  
  1017  	// We can't check name and ID if we have compacted chain link with no
  1018  	// payload JSON
  1019  	if c.IsStubbed() {
  1020  		return nil
  1021  	}
  1022  
  1023  	if c.unpacked.uid.NotEqual(i) {
  1024  		return UIDMismatchError{
  1025  			fmt.Sprintf("UID mismatch %s != %s in Link %s", c.unpacked.uid, i, c.id),
  1026  		}
  1027  	}
  1028  	if !s.Eq(NewNormalizedUsername(c.unpacked.username)) {
  1029  		return NewBadUsernameErrorWithFullMessage(
  1030  			fmt.Sprintf("Username mismatch %s != %s in Link %s",
  1031  				c.unpacked.username, s, c.id))
  1032  	}
  1033  	return nil
  1034  
  1035  }
  1036  
  1037  func ComputeLinkID(d []byte) LinkID {
  1038  	h := sha256.Sum256(d)
  1039  	return LinkID(h[:])
  1040  }
  1041  
  1042  func (c *ChainLink) getPayloadHash() LinkID {
  1043  	if c.unpacked == nil {
  1044  		return nil
  1045  	}
  1046  	return c.unpacked.payloadHash
  1047  }
  1048  
  1049  func (c *ChainLink) verifyHashV2() error {
  1050  	if c.hashVerified {
  1051  		return nil
  1052  	}
  1053  	ol := c.unpacked.outerLinkV2
  1054  	if ol == nil {
  1055  		return fmt.Errorf("nil outer link V2 unpacking")
  1056  	}
  1057  	if h := ol.LinkID(); !FastByteArrayEq(h, c.id) {
  1058  		return SigchainV2MismatchedHashError{}
  1059  	}
  1060  	c.hashVerified = true
  1061  	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.hashVerified = true })
  1062  	return nil
  1063  }
  1064  
  1065  func (c *ChainLink) verifyHashV1() error {
  1066  	if c.hashVerified {
  1067  		return nil
  1068  	}
  1069  	h := c.getPayloadHash()
  1070  	if !FastByteArrayEq(h[:], c.id) {
  1071  		return fmt.Errorf("hash mismatch in verifyHashV1")
  1072  	}
  1073  	c.hashVerified = true
  1074  	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.hashVerified = true })
  1075  	return nil
  1076  }
  1077  
  1078  func (c *ChainLink) markChainVerified() {
  1079  	c.chainVerified = true
  1080  	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.chainVerified = true })
  1081  }
  1082  
  1083  // getFixedPayload usually just returns c.unpacked.Payload(), but sometimes
  1084  // it adds extra whitespace to work around server-side bugs.
  1085  func (c ChainLink) getFixedPayload() []byte {
  1086  	payload, err := c.unpacked.Payload()
  1087  	if err != nil {
  1088  		return nil
  1089  	}
  1090  	return c.fixPayload(payload, c.id)
  1091  }
  1092  
  1093  func (c *ChainLink) fixPayload(payload []byte, linkID LinkID) []byte {
  1094  	if s, ok := badWhitespaceChainLinks[linkID.Export()]; ok {
  1095  		if payload[len(payload)-1] != '\n' {
  1096  			c.G().Log.Debug("Fixing payload by adding newline on link '%s': %s", linkID.Export(), s)
  1097  
  1098  			// Careful not to mutate the passed in payload via append. So make
  1099  			// a copy first.
  1100  			ret := make([]byte, len(payload))
  1101  			copy(ret, payload)
  1102  			ret = append(ret, '\n')
  1103  
  1104  			return ret
  1105  		}
  1106  	}
  1107  	return payload
  1108  }
  1109  
  1110  // fixAndHashPayload does the inverse of ChainLink#fixPayload. It strips off a trailing
  1111  // newline for buggy signature payloads, and then computes the hash of the result. This is
  1112  // necessary now that we are computing chain link IDs from signature bodies.
  1113  func fixAndHashPayload(g *GlobalContext, payload []byte, linkID LinkID) []byte {
  1114  	toHash := payload
  1115  	if s, ok := badWhitespaceChainLinks[linkID.Export()]; ok {
  1116  		last := len(payload) - 1
  1117  		if payload[last] == '\n' {
  1118  			g.Log.Debug("Fixing payload hash by stripping newline on link '%s': %s", linkID.Export(), s)
  1119  			toHash = payload[0:last]
  1120  		}
  1121  	}
  1122  	ret := sha256.Sum256(toHash)
  1123  	return ret[:]
  1124  }
  1125  
  1126  // two chainlinks in the database have leading padding via space characters
  1127  // or newline characters. In these two cases, we strip off leading space
  1128  // before checking if they are JSON objects. In all other cases, the first
  1129  // character must be '{'
  1130  var paddedChainLinks = map[keybase1.LinkID]bool{
  1131  	"ebcf3fab043970beee1198f16098f411331b7dbaa865a285908d82fc58df1577": true,
  1132  	"c094f59c77da5e7d4023025744f8c533a098b2136f2113dc02b0745568c2faa3": true,
  1133  }
  1134  
  1135  func stripPadding(in []byte) []byte {
  1136  	for i, b := range in {
  1137  		if b != ' ' && b != '\n' {
  1138  			return in[i:]
  1139  		}
  1140  	}
  1141  	return []byte{}
  1142  }
  1143  
  1144  func isPadded(in []byte) bool {
  1145  	return len(in) > 0 && (in[0] == ' ' || in[0] == '\n')
  1146  }
  1147  
  1148  func isJSONObject(payload []byte, linkID LinkID) bool {
  1149  	if isPadded(payload) && paddedChainLinks[linkID.Export()] {
  1150  		payload = stripPadding(payload)
  1151  	}
  1152  	return msgpack.IsJSONObject(payload)
  1153  }
  1154  
  1155  func inferSigVersion(payload []byte, linkID LinkID) SigVersion {
  1156  
  1157  	// Version 1 payloads are JSON and must start with an opening '{'
  1158  	if isJSONObject(payload, linkID) {
  1159  		return KeybaseSignatureV1
  1160  	}
  1161  
  1162  	// Version 2 payloads are Msgpack and must be arrays, so they must
  1163  	// fit the following requirements. The case where b == 0xdc or
  1164  	// b = 0xdd are far-fetched, since that would mean a large or very
  1165  	// large packing. But still, allow any valid array up front.
  1166  	if msgpack.IsEncodedMsgpackArray(payload) {
  1167  		return KeybaseSignatureV2
  1168  	}
  1169  
  1170  	// We didn't find anything useful, so mark it a "none"
  1171  	return KeybaseNullSigVersion
  1172  }
  1173  
  1174  func assertCorrectSigVersion(expected SigVersion, payload []byte, linkID LinkID) error {
  1175  	vInferred := inferSigVersion(payload, linkID)
  1176  	if vInferred != expected {
  1177  		return ChainLinkError{msg: fmt.Sprintf("chainlink in wrong format; expected version=%d but payload was %d", expected, vInferred)}
  1178  	}
  1179  	return nil
  1180  }
  1181  
  1182  func (c *ChainLink) getSigPayload() ([]byte, error) {
  1183  	if c.IsStubbed() {
  1184  		return nil, ChainLinkError{"Cannot verify sig with nil outer link v2"}
  1185  	}
  1186  	v := c.unpacked.sigVersion
  1187  	var ret []byte
  1188  	switch v {
  1189  	case KeybaseSignatureV1:
  1190  		ret = c.getFixedPayload()
  1191  	case KeybaseSignatureV2:
  1192  		ret = c.unpacked.outerLinkV2.raw
  1193  	default:
  1194  		return nil, ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", c.unpacked.sigVersion)}
  1195  	}
  1196  
  1197  	err := assertCorrectSigVersion(v, ret, c.id)
  1198  	if err != nil {
  1199  		return nil, err
  1200  	}
  1201  	return ret, nil
  1202  }
  1203  
  1204  func (c *ChainLink) verifyPayloadV2() error {
  1205  
  1206  	if c.payloadVerified {
  1207  		return nil
  1208  	}
  1209  
  1210  	ol := c.unpacked.outerLinkV2
  1211  
  1212  	if ol == nil {
  1213  		return ChainLinkError{"no outer V2 structure available"}
  1214  	}
  1215  
  1216  	version := KeybaseSignatureV2
  1217  	seqno := c.getSeqnoFromPayload()
  1218  	prev := c.getPrevFromPayload()
  1219  	curr := c.getPayloadHash()
  1220  	innerVersion := c.unpacked.sigVersion
  1221  	if innerVersion != version {
  1222  		return ChainLinkError{fmt.Sprintf("In chainlink v2, expected inner link to match; got %d", innerVersion)}
  1223  	}
  1224  	ignoreIfUnsupported := c.getIgnoreIfUnsupportedFromPayload()
  1225  	linkType, err := c.GetSigchainV2TypeFromInner(ignoreIfUnsupported)
  1226  	if err != nil {
  1227  		return err
  1228  	}
  1229  	seqType := c.getSeqTypeFromPayload()
  1230  	highSkip := c.getHighSkipFromPayload()
  1231  
  1232  	if err := ol.AssertFields(version, seqno, prev, curr, linkType, seqType, ignoreIfUnsupported, highSkip); err != nil {
  1233  		return err
  1234  	}
  1235  
  1236  	c.markPayloadVerified(ol.sigID)
  1237  	return nil
  1238  }
  1239  
  1240  func (c *ChainLink) markPayloadVerified(sigid keybase1.SigID) {
  1241  	if c.unpacked != nil {
  1242  		c.unpacked.sigID = sigid
  1243  	}
  1244  	c.payloadVerified = true
  1245  	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.payloadVerified = true })
  1246  }
  1247  
  1248  func (c *ChainLink) verifyPayloadV1() error {
  1249  	if c.payloadVerified {
  1250  		return nil
  1251  	}
  1252  	sigid, err := SigAssertPayload(c.unpacked.sig, c.getFixedPayload())
  1253  	if err != nil {
  1254  		return err
  1255  	}
  1256  	params := keybase1.SigIDSuffixParametersFromTypeAndVersion(c.unpacked.typ, keybase1.SigVersion(1))
  1257  	c.markPayloadVerified(sigid.ToSigID(params))
  1258  	return nil
  1259  }
  1260  
  1261  func (c *ChainLink) getSeqnoFromPayload() keybase1.Seqno {
  1262  	if c.unpacked != nil {
  1263  		return c.unpacked.seqno
  1264  	}
  1265  	return keybase1.Seqno(-1)
  1266  }
  1267  
  1268  func (c *ChainLink) GetSeqno() keybase1.Seqno {
  1269  	return c.unpacked.seqno
  1270  }
  1271  
  1272  func (c *ChainLink) GetHighSkip() *HighSkip {
  1273  	return c.unpacked.highSkip
  1274  }
  1275  
  1276  func (c *ChainLink) GetSigID() keybase1.SigID {
  1277  	return c.unpacked.sigID
  1278  }
  1279  
  1280  func (c *ChainLink) GetSigCheckCache() (cki *ComputedKeyInfos) {
  1281  	if c.sigVerified && c.cki != nil {
  1282  		cki = c.cki
  1283  	}
  1284  	return cki
  1285  }
  1286  
  1287  func (c *ChainLink) PutSigCheckCache(cki *ComputedKeyInfos) {
  1288  	c.G().Log.Debug("Caching SigCheck for link %s (version: %d)", c.id, cki.Version)
  1289  	c.sigVerified = true
  1290  	c.dirty = true
  1291  	c.cki = cki
  1292  	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.cki = cki })
  1293  }
  1294  
  1295  func (c *ChainLink) VerifySigWithKeyFamily(ckf ComputedKeyFamily) (err error) {
  1296  	var key GenericKey
  1297  	var verifyKID keybase1.KID
  1298  	var sigIDBase keybase1.SigIDBase
  1299  	var params keybase1.SigIDSuffixParameters
  1300  
  1301  	if c.IsStubbed() {
  1302  		return ChainLinkError{"cannot verify signature -- none available; is this a stubbed out link?"}
  1303  	}
  1304  
  1305  	if c.unpacked != nil && c.unpacked.sigDropped {
  1306  		return ChainLinkError{"cannot verify signature -- none available; sig dropped intentionally."}
  1307  	}
  1308  
  1309  	verifyKID, err = c.checkServerSignatureMetadata(ckf)
  1310  	if err != nil {
  1311  		return err
  1312  	}
  1313  
  1314  	if key, _, err = ckf.FindActiveSibkeyAtTime(verifyKID, c.GetCTime()); err != nil {
  1315  		return err
  1316  	}
  1317  
  1318  	if err = c.VerifyLink(); err != nil {
  1319  		return err
  1320  	}
  1321  
  1322  	var sigPayload []byte
  1323  	sigPayload, err = c.getSigPayload()
  1324  	if err != nil {
  1325  		return err
  1326  	}
  1327  
  1328  	if sigIDBase, err = key.VerifyString(c.G().Log, c.unpacked.sig, sigPayload); err != nil {
  1329  		return BadSigError{err.Error()}
  1330  	}
  1331  	params = keybase1.SigIDSuffixParametersFromTypeAndVersion(c.unpacked.typ, keybase1.SigVersion(c.unpacked.sigVersion))
  1332  	c.unpacked.sigID = sigIDBase.ToSigID(params)
  1333  
  1334  	return nil
  1335  }
  1336  
  1337  func putLinkToCache(m MetaContext, link *ChainLink) {
  1338  	m.G().LinkCache().Put(m, link.id, link.Copy())
  1339  }
  1340  
  1341  func NewChainLink(g *GlobalContext, parent *SigChain, id LinkID) *ChainLink {
  1342  	return &ChainLink{
  1343  		Contextified: NewContextified(g),
  1344  		parent:       parent,
  1345  		id:           id,
  1346  	}
  1347  }
  1348  
  1349  func ImportLinkFromStorage(m MetaContext, id LinkID, selfUID keybase1.UID) (*ChainLink, error) {
  1350  	link, ok := m.G().LinkCache().Get(id)
  1351  	if ok {
  1352  		link.Contextified = NewContextified(m.G())
  1353  		return &link, nil
  1354  	}
  1355  
  1356  	var ret *ChainLink
  1357  	data, _, err := m.G().LocalDb.GetRaw(DbKey{Typ: DBLink, Key: id.String()})
  1358  	if err == nil && data != nil {
  1359  		// May as well recheck onload (maybe revisit this)
  1360  		ret = NewChainLink(m.G(), nil, id)
  1361  		if err = ret.unpackFromLocalStorage(m, selfUID, data); err != nil {
  1362  			return nil, err
  1363  		}
  1364  		ret.storedLocally = true
  1365  
  1366  		m.G().LinkCache().Put(m, id, ret.Copy())
  1367  	}
  1368  	return ret, err
  1369  }
  1370  
  1371  func (c *ChainLink) VerifyLink() error {
  1372  	v := c.unpacked.sigVersion
  1373  	switch v {
  1374  	case 1:
  1375  		return c.verifyLinkV1()
  1376  	case 2:
  1377  		return c.verifyLinkV2()
  1378  	default:
  1379  		return ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", v)}
  1380  	}
  1381  }
  1382  
  1383  func (c *ChainLink) verifyLinkV1() error {
  1384  	if err := c.verifyHashV1(); err != nil {
  1385  		return err
  1386  	}
  1387  	return c.verifyPayloadV1()
  1388  }
  1389  
  1390  func (c *ChainLink) verifyLinkV2() error {
  1391  	if err := c.verifyHashV2(); err != nil {
  1392  		return err
  1393  	}
  1394  
  1395  	// We might not have an unpacked payload at all, if it's a V2 link
  1396  	// without a body (for BW savings)
  1397  	if c.IsStubbed() {
  1398  		return nil
  1399  	}
  1400  
  1401  	return c.verifyPayloadV2()
  1402  }
  1403  
  1404  func (c *ChainLink) GetSigchainV2TypeFromInner(ignoreIfUnsupported SigIgnoreIfUnsupported) (SigchainV2Type, error) {
  1405  	if c.unpacked == nil || c.unpacked.typ == "" {
  1406  		return SigchainV2TypeNone, errors.New("chain link not unpacked")
  1407  	}
  1408  	return SigchainV2TypeFromV1TypeAndRevocations(c.unpacked.typ, SigHasRevokes(c.HasRevocations()), ignoreIfUnsupported)
  1409  }
  1410  
  1411  func (c *ChainLink) GetSigchainV2TypeFromV2Shell() (SigchainV2Type, error) {
  1412  	if c.unpacked == nil {
  1413  		return SigchainV2TypeNone, errors.New("GetSigchainV2TypeFromV2Shell: chain link not unpacked")
  1414  	}
  1415  	if c.unpacked.outerLinkV2 == nil {
  1416  		return SigchainV2TypeNone, errors.New("GetSigchainV2TypeFromV2Shell: chain link has no v2 shell")
  1417  	}
  1418  	return c.unpacked.outerLinkV2.LinkType, nil
  1419  }
  1420  
  1421  // GetSigchainV2Type is a helper function for getting a ChainLink's type. If it
  1422  // is a v2 link (that may or may not be stubbed), return the type from the
  1423  // outer link, otherwise from the inner link.
  1424  func (c *ChainLink) GetSigchainV2Type() (SigchainV2Type, error) {
  1425  	if c.unpacked == nil {
  1426  		return SigchainV2TypeNone, errors.New("chain link is not unpacked")
  1427  	}
  1428  	if c.unpacked.outerLinkV2 == nil && c.unpacked.typ == "" {
  1429  		return SigchainV2TypeNone, errors.New("chain inner link type is not unpacked, and has no v2 shell")
  1430  	}
  1431  	if c.unpacked.outerLinkV2 != nil {
  1432  		return c.GetSigchainV2TypeFromV2Shell()
  1433  	}
  1434  	return c.GetSigchainV2TypeFromInner(c.GetIgnoreIfSupported())
  1435  }
  1436  
  1437  func (c *ChainLink) checkServerSignatureMetadata(ckf ComputedKeyFamily) (ret keybase1.KID, err error) {
  1438  	var serverKID, linkKID, verifyKID keybase1.KID
  1439  
  1440  	// PC: I'm not sure what exactly this was trying to do since
  1441  	// c.packed.kid can only be equal to c.unpacked.kid at this point.
  1442  	// The following two lines result in the least changes below:
  1443  	serverKID = c.unpacked.kid
  1444  	linkKID = c.unpacked.kid
  1445  
  1446  	if linkKID.Exists() && serverKID.Exists() && linkKID.NotEqual(serverKID) {
  1447  		// Check the KID. This is actually redundant of a check we do in Unpack(),
  1448  		// but I'm keeping it here in case we change the way we unpack in the
  1449  		// future.  --jacko
  1450  		return ret, ChainLinkKIDMismatchError{
  1451  			fmt.Sprintf("Payload KID (%s) doesn't match server KID (%s).",
  1452  				linkKID, serverKID),
  1453  		}
  1454  	}
  1455  
  1456  	if serverKID.Exists() {
  1457  		verifyKID = serverKID
  1458  	}
  1459  
  1460  	if linkKID.Exists() {
  1461  		verifyKID = linkKID
  1462  	}
  1463  
  1464  	if verifyKID.IsNil() {
  1465  		return ret, ChainLinkError{"cannot verify signature without a KID"}
  1466  	}
  1467  
  1468  	serverKey, err := ckf.FindKeyWithKIDUnsafe(verifyKID)
  1469  	if err != nil {
  1470  		return ret, err
  1471  	}
  1472  
  1473  	// Check the fingerprint.
  1474  	if c.unpacked.pgpFingerprint != nil {
  1475  		payloadFingerprintStr := c.unpacked.pgpFingerprint.String()
  1476  		serverFingerprintStr := ""
  1477  		if fp := GetPGPFingerprintFromGenericKey(serverKey); fp != nil {
  1478  			serverFingerprintStr = fp.String()
  1479  		}
  1480  		if payloadFingerprintStr != serverFingerprintStr {
  1481  			return ret, ChainLinkFingerprintMismatchError{
  1482  				fmt.Sprintf("Payload fingerprint (%s) did not match server key (%s).",
  1483  					payloadFingerprintStr, serverFingerprintStr),
  1484  			}
  1485  		}
  1486  	}
  1487  	return verifyKID, nil
  1488  }
  1489  
  1490  func (c *ChainLink) Store(m MetaContext) (didStore bool, err error) {
  1491  
  1492  	m.VLogf(VLog1, "| Storing Link %s...", c.id)
  1493  	if c.storedLocally && !c.dirty {
  1494  		m.VLogf(VLog1, "| Bailed on link %s since wasn't dirty...", c.id)
  1495  		return didStore, nil
  1496  	}
  1497  
  1498  	if err = c.VerifyLink(); err != nil {
  1499  		return false, err
  1500  	}
  1501  
  1502  	if !c.hashVerified || (!c.IsStubbed() && !c.payloadVerified) || !c.chainVerified {
  1503  		err = fmt.Errorf("Internal error; should have been verified in Store(); hashVerified=%v, isStubbed=%v, payloadVerified=%v, chainVerified=%v",
  1504  			c.hashVerified, c.IsStubbed(), c.payloadVerified, c.chainVerified)
  1505  		return false, err
  1506  	}
  1507  
  1508  	packed, err := c.Pack()
  1509  	if err != nil {
  1510  		return false, err
  1511  	}
  1512  
  1513  	key := DbKey{Typ: DBLink, Key: c.id.String()}
  1514  
  1515  	// Don't write with any aliases
  1516  	if err = m.G().LocalDb.Put(key, nil, packed); err != nil {
  1517  		return false, err
  1518  	}
  1519  	m.VLogf(VLog1, "| Store Link %s", c.id)
  1520  
  1521  	c.storedLocally = true
  1522  	c.dirty = false
  1523  	return true, nil
  1524  }
  1525  
  1526  func (c *ChainLink) GetPGPFingerprint() *PGPFingerprint {
  1527  	return c.unpacked.pgpFingerprint
  1528  }
  1529  func (c *ChainLink) GetKID() keybase1.KID {
  1530  	return c.unpacked.kid
  1531  }
  1532  
  1533  func (c *ChainLink) MatchFingerprint(fp PGPFingerprint) bool {
  1534  	return c.unpacked.pgpFingerprint != nil && fp.Eq(*c.unpacked.pgpFingerprint)
  1535  }
  1536  
  1537  func (c *ChainLink) ToEldestKID() keybase1.KID {
  1538  	if !c.unpacked.eldestKID.IsNil() {
  1539  		return c.unpacked.eldestKID
  1540  	}
  1541  	// For links that don't explicitly specify an eldest KID, it's implied
  1542  	// that we're starting a new subchain, so the signing KID is the
  1543  	// eldest.
  1544  	return c.GetKID()
  1545  }
  1546  
  1547  // ToLinkSummary converts a ChainLink into a MerkleTriple object.
  1548  func (c ChainLink) ToMerkleTriple() *MerkleTriple {
  1549  	if c.IsStubbed() {
  1550  		return nil
  1551  	}
  1552  	return &MerkleTriple{
  1553  		Seqno:  c.GetSeqno(),
  1554  		LinkID: c.id,
  1555  		SigID:  c.GetSigID().StripSuffix(),
  1556  	}
  1557  }
  1558  
  1559  // =========================================================================
  1560  // IsInCurrentFamily checks to see if the given chainlink
  1561  // was signed by a key in the current family.
  1562  func (c *ChainLink) IsInCurrentFamily(u *User) bool {
  1563  	eldest := u.GetEldestKID()
  1564  	if eldest.IsNil() {
  1565  		return false
  1566  	}
  1567  	return eldest.Equal(c.ToEldestKID())
  1568  }
  1569  
  1570  // =========================================================================
  1571  
  1572  func (c *ChainLink) Typed() TypedChainLink {
  1573  	return c.typed
  1574  }
  1575  
  1576  func (c *ChainLink) Copy() ChainLink {
  1577  	var unpacked ChainLinkUnpacked
  1578  	if c.unpacked != nil {
  1579  		unpacked = *c.unpacked
  1580  	}
  1581  
  1582  	r := *c
  1583  	r.SetGlobalContext(nil)
  1584  	r.parent = nil
  1585  	r.chainVerified = c.chainVerified
  1586  	r.hashVerified = c.hashVerified
  1587  	r.payloadVerified = c.payloadVerified
  1588  	r.unpacked = &unpacked
  1589  
  1590  	if c.cki != nil {
  1591  		r.cki = c.cki.ShallowCopy()
  1592  	}
  1593  
  1594  	return r
  1595  }
  1596  
  1597  func (c ChainLink) LinkID() LinkID {
  1598  	return c.id
  1599  }
  1600  
  1601  func (c ChainLink) AllowStubbing() bool {
  1602  	if c.unpacked.outerLinkV2 == nil {
  1603  		return false
  1604  	}
  1605  	return c.unpacked.outerLinkV2.LinkType.AllowStubbing()
  1606  }
  1607  
  1608  // IsHighUserLink determines whether a chainlink counts as "high" in a user's chain,
  1609  // which is defined as an Eldest link, a link with seqno=1, a link that is Sibkey,
  1610  // PGPUpdate, Revoke, or any link that is revoking.
  1611  func (c ChainLink) IsHighUserLink(mctx MetaContext, uid keybase1.UID) (bool, error) {
  1612  	v2Type, err := c.GetSigchainV2Type()
  1613  	if err != nil {
  1614  		return false, err
  1615  	}
  1616  
  1617  	hardcodedEldest := false
  1618  	if c.GetSeqno() > 1 {
  1619  		prevLink := c.parent.GetLinkFromSeqno(c.GetSeqno() - 1)
  1620  		if prevLink == nil {
  1621  			return false, ChainLinkWrongSeqnoError{}
  1622  		}
  1623  		hardcodedEldest, err = isSubchainStart(mctx, &c, prevLink, uid)
  1624  		if err != nil {
  1625  			return false, err
  1626  		}
  1627  	}
  1628  
  1629  	isFirstLink := v2Type == SigchainV2TypeEldest || c.GetSeqno() == 1 || hardcodedEldest
  1630  	isNewHighLink := isFirstLink ||
  1631  		v2Type == SigchainV2TypeRevoke ||
  1632  		v2Type == SigchainV2TypeWebServiceBindingWithRevoke ||
  1633  		v2Type == SigchainV2TypeCryptocurrencyWithRevoke ||
  1634  		v2Type == SigchainV2TypeSibkey ||
  1635  		v2Type == SigchainV2TypeWotVouchWithRevoke ||
  1636  		v2Type == SigchainV2TypePGPUpdate
  1637  	return isNewHighLink, nil
  1638  }
  1639  
  1640  // ExpectedNextHighSkip returns the expected highSkip of the immediately
  1641  // subsequent link in the chain (which may not exist yet). This function can
  1642  // only be called after VerifyChain has processed the chainLink, and set
  1643  // c.computedHighSkip.
  1644  func (c ChainLink) ExpectedNextHighSkip(mctx MetaContext, uid keybase1.UID) (HighSkip, error) {
  1645  	isHigh, err := c.IsHighUserLink(mctx, uid)
  1646  	if err != nil {
  1647  		return HighSkip{}, err
  1648  	}
  1649  	if isHigh {
  1650  		return NewHighSkip(c.GetSeqno(), c.id), nil
  1651  	}
  1652  	if c.computedHighSkip == nil {
  1653  		return HighSkip{}, NewUserReverifyNeededError("Expected to have already computed this link's HighSkip, but it was not computed.")
  1654  	}
  1655  	return *c.computedHighSkip, nil
  1656  }