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 }