1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4// 5// Code used in populating JSON objects to generating Keybase-style 6// signatures. 7// 8package libkb 9 10import ( 11 "encoding/base64" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 16 keybase1 "github.com/keybase/client/go/protocol/keybase1" 17 stellar1 "github.com/keybase/client/go/protocol/stellar1" 18 jsonw "github.com/keybase/go-jsonw" 19) 20 21func clientInfo(m MetaContext) *jsonw.Wrapper { 22 ret := jsonw.NewDictionary() 23 _ = ret.SetKey("version", jsonw.NewString(Version)) 24 _ = ret.SetKey("name", jsonw.NewString(GoClientID)) 25 return ret 26} 27 28type KeySection struct { 29 Key GenericKey 30 EldestKID keybase1.KID 31 ParentKID keybase1.KID 32 HasRevSig bool 33 RevSig string 34 SigningUser UserBasic 35 IncludePGPHash bool 36 PerUserKeyGeneration keybase1.PerUserKeyGeneration 37} 38 39func LinkEntropy() (string, error) { 40 entropyBytes, err := RandBytes(18) 41 if err != nil { 42 return "", fmt.Errorf("failed to generate entropy bytes: %v", err) 43 } 44 return base64.StdEncoding.EncodeToString(entropyBytes), nil 45} 46 47func (arg KeySection) ToJSON() (*jsonw.Wrapper, error) { 48 ret := jsonw.NewDictionary() 49 50 err := ret.SetKey("kid", jsonw.NewString(arg.Key.GetKID().String())) 51 if err != nil { 52 return nil, err 53 } 54 55 if arg.EldestKID != "" { 56 err := ret.SetKey("eldest_kid", jsonw.NewString(arg.EldestKID.String())) 57 if err != nil { 58 return nil, err 59 } 60 } 61 62 if arg.ParentKID != "" { 63 err := ret.SetKey("parent_kid", jsonw.NewString(arg.ParentKID.String())) 64 if err != nil { 65 return nil, err 66 } 67 } 68 69 if arg.HasRevSig { 70 var revSig *jsonw.Wrapper 71 if arg.RevSig != "" { 72 revSig = jsonw.NewString(arg.RevSig) 73 } else { 74 revSig = jsonw.NewNil() 75 } 76 err := ret.SetKey("reverse_sig", revSig) 77 if err != nil { 78 return nil, err 79 } 80 } 81 82 if arg.SigningUser != nil { 83 err := ret.SetKey("host", jsonw.NewString(CanonicalHost)) 84 if err != nil { 85 return nil, err 86 } 87 err = ret.SetKey("uid", UIDWrapper(arg.SigningUser.GetUID())) 88 if err != nil { 89 return nil, err 90 } 91 err = ret.SetKey("username", jsonw.NewString(arg.SigningUser.GetName())) 92 if err != nil { 93 return nil, err 94 } 95 } 96 97 if arg.PerUserKeyGeneration != 0 { 98 err := ret.SetKey("generation", jsonw.NewInt(int(arg.PerUserKeyGeneration))) 99 if err != nil { 100 return nil, err 101 } 102 } 103 104 if pgp, ok := arg.Key.(*PGPKeyBundle); ok { 105 fingerprint := pgp.GetFingerprint() 106 err := ret.SetKey("fingerprint", jsonw.NewString(fingerprint.String())) 107 if err != nil { 108 return nil, err 109 } 110 err = ret.SetKey("key_id", jsonw.NewString(fingerprint.ToKeyID())) 111 if err != nil { 112 return nil, err 113 } 114 if arg.IncludePGPHash { 115 hash, err := pgp.FullHash() 116 if err != nil { 117 return nil, err 118 } 119 120 err = ret.SetKey("full_hash", jsonw.NewString(hash)) 121 if err != nil { 122 return nil, err 123 } 124 } 125 } 126 127 return ret, nil 128} 129 130func (u *User) ToTrackingStatementKey(errp *error) *jsonw.Wrapper { 131 ret := jsonw.NewDictionary() 132 133 if !u.HasActiveKey() { 134 *errp = fmt.Errorf("User %s doesn't have an active key", u.GetName()) 135 } else { 136 kid := u.GetEldestKID() 137 _ = ret.SetKey("kid", jsonw.NewString(kid.String())) 138 ckf := u.GetComputedKeyFamily() 139 if fingerprint, exists := ckf.kf.kid2pgp[kid]; exists { 140 _ = ret.SetKey("key_fingerprint", jsonw.NewString(fingerprint.String())) 141 } 142 } 143 return ret 144} 145 146func (u *User) ToTrackingStatementPGPKeys(errp *error) *jsonw.Wrapper { 147 keys := u.GetActivePGPKeys(true) 148 if len(keys) == 0 { 149 return nil 150 } 151 152 ret := jsonw.NewArray(len(keys)) 153 for i, k := range keys { 154 kd := jsonw.NewDictionary() 155 kid := k.GetKID() 156 fp := k.GetFingerprintP() 157 _ = kd.SetKey("kid", jsonw.NewString(kid.String())) 158 if fp != nil { 159 _ = kd.SetKey("key_fingerprint", jsonw.NewString(fp.String())) 160 } 161 _ = ret.SetIndex(i, kd) 162 } 163 return ret 164} 165 166func (u *User) ToTrackingStatementBasics(errp *error) *jsonw.Wrapper { 167 ret := jsonw.NewDictionary() 168 _ = ret.SetKey("username", jsonw.NewString(u.name)) 169 if lastIDChange, err := u.basics.AtKey("last_id_change").GetInt(); err == nil { 170 _ = ret.SetKey("last_id_change", jsonw.NewInt(lastIDChange)) 171 } 172 if idVersion, err := u.basics.AtKey("id_version").GetInt(); err == nil { 173 _ = ret.SetKey("id_version", jsonw.NewInt(idVersion)) 174 } 175 return ret 176} 177 178func (u *User) ToTrackingStatementSeqTail() *jsonw.Wrapper { 179 mul := u.GetPublicChainTail() 180 if mul == nil { 181 return jsonw.NewNil() 182 } 183 ret := jsonw.NewDictionary() 184 _ = ret.SetKey("sig_id", jsonw.NewString(mul.SigID.ToSigIDLegacy().String())) 185 _ = ret.SetKey("seqno", jsonw.NewInt(int(mul.Seqno))) 186 _ = ret.SetKey("payload_hash", jsonw.NewString(mul.LinkID.String())) 187 return ret 188} 189 190func (u *User) ToTrackingStatement(w *jsonw.Wrapper, outcome *IdentifyOutcome) (err error) { 191 192 track := jsonw.NewDictionary() 193 if u.HasActiveKey() { 194 key := u.ToTrackingStatementKey(&err) 195 if key != nil { 196 _ = track.SetKey("key", key) 197 } 198 } 199 if pgpkeys := u.ToTrackingStatementPGPKeys(&err); pgpkeys != nil { 200 err := track.SetKey("pgp_keys", pgpkeys) 201 if err != nil { 202 return err 203 } 204 } 205 err = track.SetKey("seq_tail", u.ToTrackingStatementSeqTail()) 206 if err != nil { 207 return err 208 } 209 err = track.SetKey("basics", u.ToTrackingStatementBasics(&err)) 210 if err != nil { 211 return err 212 } 213 err = track.SetKey("id", UIDWrapper(u.id)) 214 if err != nil { 215 return err 216 } 217 err = track.SetKey("remote_proofs", outcome.TrackingStatement()) 218 if err != nil { 219 return err 220 } 221 222 entropy, err := LinkEntropy() 223 if err != nil { 224 return err 225 } 226 err = track.SetKey("entropy", jsonw.NewString(entropy)) 227 if err != nil { 228 return err 229 } 230 231 return w.SetKey("track", track) 232} 233 234func (u *User) ToWotStatement() *jsonw.Wrapper { 235 user := jsonw.NewDictionary() 236 _ = user.SetKey("username", jsonw.NewString(u.GetNormalizedName().String())) 237 _ = user.SetKey("uid", UIDWrapper(u.GetUID())) 238 _ = user.SetKey("seq_tail", u.ToTrackingStatementSeqTail()) 239 eldest := jsonw.NewDictionary() 240 _ = eldest.SetKey("kid", jsonw.NewString(u.GetEldestKID().String())) 241 _ = eldest.SetKey("seqno", jsonw.NewInt64(int64(u.GetCurrentEldestSeqno()))) 242 _ = user.SetKey("eldest", eldest) 243 244 return user 245} 246 247func (u *User) ToUntrackingStatementBasics() *jsonw.Wrapper { 248 ret := jsonw.NewDictionary() 249 _ = ret.SetKey("username", jsonw.NewString(u.name)) 250 return ret 251} 252 253func (u *User) ToUntrackingStatement(w *jsonw.Wrapper) (err error) { 254 untrack := jsonw.NewDictionary() 255 err = untrack.SetKey("basics", u.ToUntrackingStatementBasics()) 256 if err != nil { 257 return err 258 } 259 err = untrack.SetKey("id", UIDWrapper(u.GetUID())) 260 if err != nil { 261 return err 262 } 263 264 entropy, err := LinkEntropy() 265 if err != nil { 266 return err 267 } 268 err = untrack.SetKey("entropy", jsonw.NewString(entropy)) 269 if err != nil { 270 return err 271 } 272 273 return w.SetKey("untrack", untrack) 274} 275 276func (g *GenericChainLink) BaseToTrackingStatement(state keybase1.ProofState) *jsonw.Wrapper { 277 ret := jsonw.NewDictionary() 278 _ = ret.SetKey("curr", jsonw.NewString(g.id.String())) 279 _ = ret.SetKey("sig_id", jsonw.NewString(g.GetSigID().String())) 280 281 rkp := jsonw.NewDictionary() 282 _ = ret.SetKey("remote_key_proof", rkp) 283 _ = rkp.SetKey("state", jsonw.NewInt(int(state))) 284 285 prev := g.GetPrev() 286 var prevVal *jsonw.Wrapper 287 if prev == nil { 288 prevVal = jsonw.NewNil() 289 } else { 290 prevVal = jsonw.NewString(prev.String()) 291 } 292 293 _ = ret.SetKey("prev", prevVal) 294 _ = ret.SetKey("ctime", jsonw.NewInt64(g.unpacked.ctime)) 295 _ = ret.SetKey("etime", jsonw.NewInt64(g.unpacked.etime)) 296 return ret 297} 298 299func remoteProofToTrackingStatement(s RemoteProofChainLink, base *jsonw.Wrapper) { 300 proofType := s.GetProofType() 301 _ = base.AtKey("remote_key_proof").SetKey("proof_type", jsonw.NewInt(int(proofType))) 302 _ = base.AtKey("remote_key_proof").SetKey("check_data_json", s.CheckDataJSON()) 303 _ = base.SetKey("sig_type", jsonw.NewInt(SigTypeRemoteProof)) 304} 305 306type HighSkip struct { 307 Seqno keybase1.Seqno 308 Hash LinkID 309} 310 311func NewHighSkip(highSkipSeqno keybase1.Seqno, highSkipHash LinkID) HighSkip { 312 return HighSkip{ 313 Seqno: highSkipSeqno, 314 Hash: highSkipHash, 315 } 316} 317 318func NewInitialHighSkip() HighSkip { 319 return NewHighSkip(keybase1.Seqno(0), nil) 320} 321 322func (h HighSkip) AssertEqualsExpected(expected HighSkip) error { 323 if expected.Seqno != h.Seqno { 324 return fmt.Errorf("Expected highSkip.Seqno %d, got %d.", expected.Seqno, h.Seqno) 325 } 326 if !expected.Hash.Eq(h.Hash) { 327 return fmt.Errorf("Expected highSkip.Hash %s, got %s.", expected.Hash.String(), h.Hash.String()) 328 } 329 return nil 330} 331 332type ProofMetadata struct { 333 Me *User 334 SigningUser UserBasic 335 Seqno keybase1.Seqno 336 PrevLinkID LinkID 337 LinkType LinkType 338 SigningKey GenericKey 339 Eldest keybase1.KID 340 CreationTime int64 341 ExpireIn int 342 IncludePGPHash bool 343 SigVersion SigVersion 344 SeqType keybase1.SeqType 345 MerkleRoot *MerkleRoot 346 IgnoreIfUnsupported SigIgnoreIfUnsupported 347 // HighSkipFallback is used for teams to provide for a KEX-provisisonee to 348 // provide the provisioner's information as the latest high link. 349 HighSkipFallback *HighSkip 350} 351 352type ProofMetadataRes struct { 353 J *jsonw.Wrapper 354 Seqno keybase1.Seqno 355} 356 357func (arg ProofMetadata) merkleRootInfo(m MetaContext) (ret *jsonw.Wrapper) { 358 if mr := arg.MerkleRoot; mr != nil { 359 return mr.ToSigJSON() 360 } 361 if mc := m.G().MerkleClient; mc != nil { 362 ret, _ = mc.LastRootToSigJSON(m) 363 } 364 return ret 365} 366 367func (arg ProofMetadata) ToJSON(m MetaContext) (*jsonw.Wrapper, error) { 368 res, err := arg.ToJSON2(m) 369 if err != nil { 370 return nil, err 371 } 372 return res.J, nil 373} 374 375func (arg ProofMetadata) ToJSON2(m MetaContext) (ret *ProofMetadataRes, err error) { 376 // if only Me exists, then that is the signing user too 377 if arg.SigningUser == nil && arg.Me != nil { 378 arg.SigningUser = arg.Me 379 } 380 381 var seqno keybase1.Seqno 382 var prev *jsonw.Wrapper 383 384 // sanity check the seqno and prev relationship 385 if arg.Seqno > 1 && len(arg.PrevLinkID) == 0 { 386 return nil, fmt.Errorf("can't have a seqno > 1 without a prev value") 387 } 388 389 if arg.Seqno > 0 { 390 seqno = arg.Seqno 391 if arg.Seqno == 1 { 392 prev = jsonw.NewNil() 393 } else { 394 prev = jsonw.NewString(arg.PrevLinkID.String()) 395 } 396 } else { 397 if arg.Me == nil { 398 return nil, fmt.Errorf("missing self user object while signing") 399 } 400 lastSeqno := arg.Me.sigChain().GetLastKnownSeqno() 401 lastLink := arg.Me.sigChain().GetLastKnownID() 402 if lastLink == nil { 403 seqno = 1 404 prev = jsonw.NewNil() 405 } else { 406 seqno = lastSeqno + 1 407 prev = jsonw.NewString(lastLink.String()) 408 } 409 } 410 411 ctime := arg.CreationTime 412 if ctime == 0 { 413 ctime = m.G().Clock().Now().Unix() 414 } 415 416 ei := arg.ExpireIn 417 if ei == 0 { 418 ei = SigExpireIn 419 } 420 421 j := jsonw.NewDictionary() 422 err = j.SetKey("tag", jsonw.NewString("signature")) 423 if err != nil { 424 return nil, err 425 } 426 err = j.SetKey("ctime", jsonw.NewInt64(ctime)) 427 if err != nil { 428 return nil, err 429 } 430 err = j.SetKey("expire_in", jsonw.NewInt(ei)) 431 if err != nil { 432 return nil, err 433 } 434 err = j.SetKey("seqno", jsonw.NewInt64(int64(seqno))) 435 if err != nil { 436 return nil, err 437 } 438 err = j.SetKey("prev", prev) 439 if err != nil { 440 return nil, err 441 } 442 443 var highSkip *HighSkip 444 allowHighSkips := m.G().Env.GetFeatureFlags().HasFeature(EnvironmentFeatureAllowHighSkips) 445 if allowHighSkips { 446 if (arg.Me != nil) && (arg.HighSkipFallback != nil) { 447 return nil, fmt.Errorf("arg.Me and arg.HighSkipFallback can't both be non-nil.") 448 } else if arg.Me != nil { 449 highSkipPre, err := arg.Me.GetExpectedNextHighSkip(m) 450 if err != nil { 451 return nil, err 452 } 453 highSkip = &highSkipPre 454 } else if arg.HighSkipFallback != nil { 455 highSkip = arg.HighSkipFallback 456 } 457 458 if highSkip != nil { 459 highSkipObj := jsonw.NewDictionary() 460 err := highSkipObj.SetKey("seqno", jsonw.NewInt64(int64(highSkip.Seqno))) 461 if err != nil { 462 return nil, err 463 } 464 if hash := highSkip.Hash; hash != nil { 465 err := highSkipObj.SetKey("hash", jsonw.NewString(hash.String())) 466 if err != nil { 467 return nil, err 468 } 469 } else { 470 err := highSkipObj.SetKey("hash", jsonw.NewNil()) 471 if err != nil { 472 return nil, err 473 } 474 } 475 err = j.SetKey("high_skip", highSkipObj) 476 if err != nil { 477 return nil, err 478 } 479 } 480 } 481 482 if arg.IgnoreIfUnsupported { 483 err := j.SetKey("ignore_if_unsupported", jsonw.NewBool(true)) 484 if err != nil { 485 return nil, err 486 } 487 } 488 eldest := arg.Eldest 489 if eldest == "" { 490 if arg.Me == nil { 491 return nil, fmt.Errorf("missing self user object while signing") 492 } 493 eldest = arg.Me.GetEldestKID() 494 } 495 496 body := jsonw.NewDictionary() 497 498 if arg.SigVersion != 0 { 499 err := body.SetKey("version", jsonw.NewInt(int(arg.SigVersion))) 500 if err != nil { 501 return nil, err 502 } 503 } else { 504 err := body.SetKey("version", jsonw.NewInt(int(KeybaseSignatureV1))) 505 if err != nil { 506 return nil, err 507 } 508 } 509 510 err = body.SetKey("type", jsonw.NewString(string(arg.LinkType))) 511 if err != nil { 512 return nil, err 513 } 514 515 key, err := KeySection{ 516 Key: arg.SigningKey, 517 EldestKID: eldest, 518 SigningUser: arg.SigningUser, 519 IncludePGPHash: arg.IncludePGPHash, 520 }.ToJSON() 521 if err != nil { 522 return nil, err 523 } 524 err = body.SetKey("key", key) 525 if err != nil { 526 return nil, err 527 } 528 // Capture the most recent Merkle Root, inside of "body" 529 // field. 530 if mr := arg.merkleRootInfo(m); mr != nil { 531 err := body.SetKey("merkle_root", mr) 532 if err != nil { 533 return nil, err 534 } 535 } 536 537 err = j.SetKey("body", body) 538 if err != nil { 539 return nil, err 540 } 541 542 // Save what kind of client we're running. 543 err = j.SetKey("client", clientInfo(m)) 544 if err != nil { 545 return nil, err 546 } 547 548 if arg.SeqType != 0 { 549 err := j.SetKey("seq_type", jsonw.NewInt(int(arg.SeqType))) 550 if err != nil { 551 return nil, err 552 } 553 } 554 555 return &ProofMetadataRes{ 556 J: j, 557 Seqno: seqno, 558 }, nil 559} 560 561func (u *User) TrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User, outcome *IdentifyOutcome) (*ProofMetadataRes, error) { 562 ret, err := ProofMetadata{ 563 Me: u, 564 LinkType: LinkTypeTrack, 565 SigningKey: signingKey, 566 SigVersion: sigVersion, 567 }.ToJSON2(m) 568 if err == nil { 569 err = u2.ToTrackingStatement(ret.J.AtKey("body"), outcome) 570 } 571 return ret, err 572} 573 574func (u *User) UntrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User) (*ProofMetadataRes, error) { 575 ret, err := ProofMetadata{ 576 Me: u, 577 LinkType: LinkTypeUntrack, 578 SigningKey: signingKey, 579 SigVersion: sigVersion, 580 }.ToJSON2(m) 581 if err == nil { 582 err = u2.ToUntrackingStatement(ret.J.AtKey("body")) 583 } 584 return ret, err 585} 586 587// arg.Me user is used to get the last known seqno in ProofMetadata. 588// If arg.Me == nil, set arg.Seqno. 589func KeyProof(m MetaContext, arg Delegator) (*jsonw.Wrapper, error) { 590 res, err := KeyProof2(m, arg) 591 if err != nil { 592 return nil, err 593 } 594 return res.J, nil 595} 596 597// arg.Me user is used to get the last known seqno in ProofMetadata. 598// If arg.Me == nil, set arg.Seqno. 599func KeyProof2(m MetaContext, arg Delegator) (ret *ProofMetadataRes, err error) { 600 var kp *jsonw.Wrapper 601 includePGPHash := false 602 603 if arg.DelegationType == DelegationTypeEldest { 604 includePGPHash = true 605 } else if arg.NewKey != nil { 606 keySection := KeySection{ 607 Key: arg.NewKey, 608 } 609 switch arg.DelegationType { 610 case DelegationTypePGPUpdate: 611 keySection.IncludePGPHash = true 612 case DelegationTypeSibkey: 613 keySection.HasRevSig = true 614 keySection.RevSig = arg.RevSig 615 keySection.IncludePGPHash = true 616 default: 617 keySection.ParentKID = arg.ExistingKey.GetKID() 618 } 619 620 if kp, err = keySection.ToJSON(); err != nil { 621 return nil, err 622 } 623 } 624 625 // Only set the fallback for subkeys during KEX where arg.Me == nil; it is 626 // otherwise updated using me.SigChainBump(). 627 var highSkipFallback *HighSkip 628 if arg.Me == nil && arg.DelegationType == DelegationTypeSubkey { 629 highSkip := NewHighSkip(arg.Seqno-1, arg.PrevLinkID) 630 highSkipFallback = &highSkip 631 } 632 633 ret, err = ProofMetadata{ 634 Me: arg.Me, 635 SigningUser: arg.SigningUser, 636 LinkType: LinkType(arg.DelegationType), 637 ExpireIn: arg.Expire, 638 SigningKey: arg.GetSigningKey(), 639 Eldest: arg.EldestKID, 640 CreationTime: arg.Ctime, 641 IncludePGPHash: includePGPHash, 642 Seqno: arg.Seqno, 643 HighSkipFallback: highSkipFallback, 644 PrevLinkID: arg.PrevLinkID, 645 MerkleRoot: arg.MerkleRoot, 646 }.ToJSON2(m) 647 if err != nil { 648 return nil, err 649 } 650 651 body := ret.J.AtKey("body") 652 653 if arg.Device != nil { 654 device := *arg.Device 655 device.Kid = arg.NewKey.GetKID() 656 var dw *jsonw.Wrapper 657 dw, err = device.Export(LinkType(arg.DelegationType)) 658 if err != nil { 659 return nil, err 660 } 661 err = body.SetKey("device", dw) 662 if err != nil { 663 return nil, err 664 } 665 } 666 if kp != nil { 667 err := body.SetKey(string(arg.DelegationType), kp) 668 if err != nil { 669 return nil, err 670 } 671 } 672 return ret, nil 673} 674 675func (u *User) ServiceProof(m MetaContext, signingKey GenericKey, typ ServiceType, remotename string, sigVersion SigVersion) (*ProofMetadataRes, error) { 676 ret, err := ProofMetadata{ 677 Me: u, 678 LinkType: LinkTypeWebServiceBinding, 679 SigningKey: signingKey, 680 SigVersion: sigVersion, 681 }.ToJSON2(m) 682 if err != nil { 683 return nil, err 684 } 685 service := typ.ToServiceJSON(remotename) 686 entropy, err := LinkEntropy() 687 if err != nil { 688 return nil, err 689 } 690 err = service.SetKey("entropy", jsonw.NewString(entropy)) 691 if err != nil { 692 return nil, err 693 } 694 err = ret.J.AtKey("body").SetKey("service", service) 695 if err != nil { 696 return nil, err 697 } 698 return ret, nil 699} 700 701func (u *User) WotVouchProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte, merkleRoot *MerkleRoot, sigIDToRevoke *keybase1.SigID) (*ProofMetadataRes, error) { 702 md := ProofMetadata{ 703 Me: u, 704 LinkType: LinkTypeWotVouch, 705 MerkleRoot: merkleRoot, 706 SigningKey: signingKey, 707 SigVersion: sigVersion, 708 IgnoreIfUnsupported: true, 709 } 710 ret, err := md.ToJSON2(m) 711 if err != nil { 712 return nil, err 713 } 714 715 body := ret.J.AtKey("body") 716 if err := body.SetKey("wot_vouch", jsonw.NewString(hex.EncodeToString(mac))); err != nil { 717 return nil, err 718 } 719 720 if sigIDToRevoke != nil { 721 revokeSection := jsonw.NewDictionary() 722 err := revokeSection.SetKey("sig_id", jsonw.NewString(sigIDToRevoke.String())) 723 if err != nil { 724 return nil, err 725 } 726 err = body.SetKey("revoke", revokeSection) 727 if err != nil { 728 return nil, err 729 } 730 } 731 732 return ret, nil 733} 734 735func (u *User) WotReactProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte) (*ProofMetadataRes, error) { 736 md := ProofMetadata{ 737 Me: u, 738 LinkType: LinkTypeWotReact, 739 SigningKey: signingKey, 740 SigVersion: sigVersion, 741 IgnoreIfUnsupported: true, 742 } 743 ret, err := md.ToJSON2(m) 744 if err != nil { 745 return nil, err 746 } 747 748 body := ret.J.AtKey("body") 749 if err := body.SetKey("wot_react", jsonw.NewString(hex.EncodeToString(mac))); err != nil { 750 return nil, err 751 } 752 753 return ret, nil 754} 755 756// SimpleSignJson marshals the given Json structure and then signs it. 757func SignJSON(jw *jsonw.Wrapper, key GenericKey) (out string, id keybase1.SigIDBase, lid LinkID, err error) { 758 var tmp []byte 759 if tmp, err = jw.Marshal(); err != nil { 760 return 761 } 762 out, id, err = key.SignToString(tmp) 763 lid = ComputeLinkID(tmp) 764 return 765} 766 767func GetDefaultSigVersion(g *GlobalContext) SigVersion { 768 return KeybaseSignatureV2 769} 770 771func MakeSig( 772 m MetaContext, 773 signingKey GenericKey, 774 v1LinkType LinkType, 775 innerLinkJSON []byte, 776 hasRevokes SigHasRevokes, 777 seqType keybase1.SeqType, 778 ignoreIfUnsupported SigIgnoreIfUnsupported, 779 me *User, 780 sigVersion SigVersion) (sig string, sigID keybase1.SigID, linkID LinkID, err error) { 781 782 switch sigVersion { 783 case KeybaseSignatureV1: 784 var sigIDBase keybase1.SigIDBase 785 sig, sigIDBase, err = signingKey.SignToString(innerLinkJSON) 786 linkID = ComputeLinkID(innerLinkJSON) 787 params := keybase1.SigIDSuffixParametersFromTypeAndVersion(string(v1LinkType), keybase1.SigVersion(sigVersion)) 788 sigID = sigIDBase.ToSigID(params) 789 case KeybaseSignatureV2: 790 prevSeqno := me.GetSigChainLastKnownSeqno() 791 prevLinkID := me.GetSigChainLastKnownID() 792 highSkip, highSkipErr := me.GetExpectedNextHighSkip(m) 793 if highSkipErr != nil { 794 return sig, sigID, linkID, highSkipErr 795 } 796 sig, sigID, linkID, err = MakeSigchainV2OuterSig( 797 m, 798 signingKey, 799 v1LinkType, 800 prevSeqno+1, 801 innerLinkJSON, 802 prevLinkID, 803 hasRevokes, 804 seqType, 805 ignoreIfUnsupported, 806 &highSkip, 807 ) 808 default: 809 err = errors.New("Invalid Signature Version") 810 } 811 return sig, sigID, linkID, err 812} 813 814func (u *User) RevokeKeysProof(m MetaContext, key GenericKey, kidsToRevoke []keybase1.KID, 815 deviceToDisable keybase1.DeviceID, merkleRoot *MerkleRoot) (*ProofMetadataRes, error) { 816 ret, err := ProofMetadata{ 817 Me: u, 818 LinkType: LinkTypeRevoke, 819 SigningKey: key, 820 MerkleRoot: merkleRoot, 821 }.ToJSON2(m) 822 if err != nil { 823 return nil, err 824 } 825 body := ret.J.AtKey("body") 826 revokeSection := jsonw.NewDictionary() 827 err = revokeSection.SetKey("kids", jsonw.NewWrapper(kidsToRevoke)) 828 if err != nil { 829 return nil, err 830 } 831 err = body.SetKey("revoke", revokeSection) 832 if err != nil { 833 return nil, err 834 } 835 if deviceToDisable.Exists() { 836 device, err := u.GetDevice(deviceToDisable) 837 if err != nil { 838 return nil, err 839 } 840 deviceSection := jsonw.NewDictionary() 841 err = deviceSection.SetKey("id", jsonw.NewString(deviceToDisable.String())) 842 if err != nil { 843 return nil, err 844 } 845 err = deviceSection.SetKey("type", jsonw.NewString(device.Type.String())) 846 if err != nil { 847 return nil, err 848 } 849 err = deviceSection.SetKey("status", jsonw.NewInt(DeviceStatusDefunct)) 850 if err != nil { 851 return nil, err 852 } 853 err = body.SetKey("device", deviceSection) 854 if err != nil { 855 return nil, err 856 } 857 } 858 return ret, nil 859} 860 861func (u *User) RevokeSigsProof(m MetaContext, key GenericKey, sigIDsToRevoke []keybase1.SigID, merkleRoot *MerkleRoot) (*ProofMetadataRes, error) { 862 ret, err := ProofMetadata{ 863 Me: u, 864 LinkType: LinkTypeRevoke, 865 SigningKey: key, 866 MerkleRoot: merkleRoot, 867 }.ToJSON2(m) 868 if err != nil { 869 return nil, err 870 } 871 body := ret.J.AtKey("body") 872 revokeSection := jsonw.NewDictionary() 873 idsArray := jsonw.NewArray(len(sigIDsToRevoke)) 874 for i, id := range sigIDsToRevoke { 875 err := idsArray.SetIndex(i, jsonw.NewString(id.String())) 876 if err != nil { 877 return nil, err 878 } 879 } 880 err = revokeSection.SetKey("sig_ids", idsArray) 881 if err != nil { 882 return nil, err 883 } 884 err = body.SetKey("revoke", revokeSection) 885 if err != nil { 886 return nil, err 887 } 888 return ret, nil 889} 890 891func (u *User) CryptocurrencySig(m MetaContext, key GenericKey, address string, typ CryptocurrencyType, sigToRevoke keybase1.SigID, merkleRoot *MerkleRoot, sigVersion SigVersion) (*ProofMetadataRes, error) { 892 ret, err := ProofMetadata{ 893 Me: u, 894 LinkType: LinkTypeCryptocurrency, 895 SigningKey: key, 896 MerkleRoot: merkleRoot, 897 SigVersion: sigVersion, 898 }.ToJSON2(m) 899 if err != nil { 900 return nil, err 901 } 902 body := ret.J.AtKey("body") 903 currencySection := jsonw.NewDictionary() 904 err = currencySection.SetKey("address", jsonw.NewString(address)) 905 if err != nil { 906 return nil, err 907 } 908 err = currencySection.SetKey("type", jsonw.NewString(typ.String())) 909 if err != nil { 910 return nil, err 911 } 912 entropy, err := LinkEntropy() 913 if err != nil { 914 return nil, err 915 } 916 err = currencySection.SetKey("entropy", jsonw.NewString(entropy)) 917 if err != nil { 918 return nil, err 919 } 920 err = body.SetKey("cryptocurrency", currencySection) 921 if err != nil { 922 return nil, err 923 } 924 if len(sigToRevoke) > 0 { 925 revokeSection := jsonw.NewDictionary() 926 err := revokeSection.SetKey("sig_id", jsonw.NewString(sigToRevoke.String())) 927 if err != nil { 928 return nil, err 929 } 930 err = body.SetKey("revoke", revokeSection) 931 if err != nil { 932 return nil, err 933 } 934 } 935 return ret, nil 936} 937 938func (u *User) UpdatePassphraseProof(m MetaContext, key GenericKey, pwh string, ppGen PassphraseGeneration, pdpka5kid string) (*jsonw.Wrapper, error) { 939 ret, err := ProofMetadata{ 940 Me: u, 941 LinkType: LinkTypeUpdatePassphrase, 942 SigningKey: key, 943 }.ToJSON(m) 944 if err != nil { 945 return nil, err 946 } 947 body := ret.AtKey("body") 948 pp := jsonw.NewDictionary() 949 err = pp.SetKey("hash", jsonw.NewString(pwh)) 950 if err != nil { 951 return nil, err 952 } 953 err = pp.SetKey("pdpka5_kid", jsonw.NewString(pdpka5kid)) 954 if err != nil { 955 return nil, err 956 } 957 err = pp.SetKey("version", jsonw.NewInt(int(ClientTriplesecVersion))) 958 if err != nil { 959 return nil, err 960 } 961 err = pp.SetKey("passphrase_generation", jsonw.NewInt(int(ppGen))) 962 if err != nil { 963 return nil, err 964 } 965 err = body.SetKey("update_passphrase_hash", pp) 966 if err != nil { 967 return nil, err 968 } 969 return ret, nil 970} 971 972func (u *User) UpdateEmailProof(m MetaContext, key GenericKey, newEmail string) (*jsonw.Wrapper, error) { 973 ret, err := ProofMetadata{ 974 Me: u, 975 LinkType: LinkTypeUpdateSettings, 976 SigningKey: key, 977 }.ToJSON(m) 978 if err != nil { 979 return nil, err 980 } 981 body := ret.AtKey("body") 982 settings := jsonw.NewDictionary() 983 err = settings.SetKey("email", jsonw.NewString(newEmail)) 984 if err != nil { 985 return nil, err 986 } 987 err = body.SetKey("update_settings", settings) 988 if err != nil { 989 return nil, err 990 } 991 return ret, nil 992} 993 994type SigMultiItem struct { 995 Sig3 *Sig3 `json:"sig3,omitempty"` 996 Sig string `json:"sig,omitempty"` 997 SigningKID keybase1.KID `json:"signing_kid"` 998 Type string `json:"type"` 999 SeqType keybase1.SeqType `json:"seq_type"` 1000 SigInner string `json:"sig_inner"` 1001 TeamID keybase1.TeamID `json:"team_id,omitempty"` 1002 PublicKeys *SigMultiItemPublicKeys `json:"public_keys,omitempty"` 1003 Version SigVersion `json:"version"` 1004 Expansions *jsonw.Wrapper `json:"expansions,omitempty"` 1005} 1006 1007type SigMultiItemPublicKeys struct { 1008 Encryption keybase1.KID `json:"encryption"` 1009 Signing keybase1.KID `json:"signing"` 1010} 1011 1012type Sig3 struct { 1013 Inner string `json:"i,omitempty"` 1014 Outer string `json:"o,omitempty"` 1015 Sig string `json:"s,omitempty"` 1016} 1017 1018// PerUserKeyProof creates a proof introducing a new per-user-key generation. 1019// `signingKey` is the key signing in this new key. Not to be confused with the derived per-user-key signing key. 1020func PerUserKeyProof(m MetaContext, 1021 me *User, 1022 pukSigKID keybase1.KID, 1023 pukEncKID keybase1.KID, 1024 generation keybase1.PerUserKeyGeneration, 1025 signingKey GenericKey) (*ProofMetadataRes, error) { 1026 1027 if me == nil { 1028 return nil, fmt.Errorf("missing user object for proof") 1029 } 1030 1031 ret, err := ProofMetadata{ 1032 Me: me, 1033 LinkType: LinkTypePerUserKey, 1034 SigningKey: signingKey, 1035 }.ToJSON2(m) 1036 if err != nil { 1037 return nil, err 1038 } 1039 1040 pukSection := jsonw.NewDictionary() 1041 err = pukSection.SetKey("signing_kid", jsonw.NewString(pukSigKID.String())) 1042 if err != nil { 1043 return nil, err 1044 } 1045 err = pukSection.SetKey("encryption_kid", jsonw.NewString(pukEncKID.String())) 1046 if err != nil { 1047 return nil, err 1048 } 1049 err = pukSection.SetKey("generation", jsonw.NewInt(int(generation))) 1050 if err != nil { 1051 return nil, err 1052 } 1053 // The caller is responsible for overwriting reverse_sig after signing. 1054 err = pukSection.SetKey("reverse_sig", jsonw.NewNil()) 1055 if err != nil { 1056 return nil, err 1057 } 1058 1059 body := ret.J.AtKey("body") 1060 err = body.SetKey("per_user_key", pukSection) 1061 if err != nil { 1062 return nil, err 1063 } 1064 return ret, nil 1065} 1066 1067type UserLinkSignature struct { 1068 Payload JSONPayload 1069 Seqno keybase1.Seqno 1070 LinkID LinkID 1071} 1072 1073// Make a per-user key proof with a reverse sig. 1074// Modifies the User `me` with a sigchain bump and key delegation. 1075// Returns a JSONPayload ready for use in "sigs" in sig/multi. 1076func PerUserKeyProofReverseSigned(m MetaContext, me *User, perUserKeySeed PerUserKeySeed, generation keybase1.PerUserKeyGeneration, 1077 signer GenericKey) (*UserLinkSignature, error) { 1078 1079 pukSigKey, err := perUserKeySeed.DeriveSigningKey() 1080 if err != nil { 1081 return nil, err 1082 } 1083 1084 pukEncKey, err := perUserKeySeed.DeriveDHKey() 1085 if err != nil { 1086 return nil, err 1087 } 1088 1089 // Make reverse sig 1090 forward, err := PerUserKeyProof(m, me, pukSigKey.GetKID(), pukEncKey.GetKID(), generation, signer) 1091 if err != nil { 1092 return nil, err 1093 } 1094 reverseSig, _, _, err := SignJSON(forward.J, pukSigKey) 1095 if err != nil { 1096 return nil, err 1097 } 1098 1099 // Make sig 1100 jw := forward.J 1101 err = jw.SetValueAtPath("body.per_user_key.reverse_sig", jsonw.NewString(reverseSig)) 1102 if err != nil { 1103 return nil, err 1104 } 1105 sig, sigID, linkID, err := SignJSON(jw, signer) 1106 if err != nil { 1107 return nil, err 1108 } 1109 1110 // Update the user locally 1111 me.SigChainBump(linkID, sigID.ToSigIDLegacy(), false) 1112 err = me.localDelegatePerUserKey(keybase1.PerUserKey{ 1113 Gen: int(generation), 1114 Seqno: me.GetSigChainLastKnownSeqno(), 1115 SigKID: pukSigKey.GetKID(), 1116 EncKID: pukEncKey.GetKID(), 1117 SignedByKID: signer.GetKID(), 1118 }) 1119 if err != nil { 1120 return nil, err 1121 } 1122 1123 publicKeysEntry := make(JSONPayload) 1124 publicKeysEntry["signing"] = pukSigKey.GetKID().String() 1125 publicKeysEntry["encryption"] = pukEncKey.GetKID().String() 1126 1127 payload := make(JSONPayload) 1128 payload["sig"] = sig 1129 payload["signing_kid"] = signer.GetKID().String() 1130 payload["type"] = LinkTypePerUserKey 1131 payload["public_keys"] = publicKeysEntry 1132 return &UserLinkSignature{ 1133 Payload: payload, 1134 Seqno: forward.Seqno, 1135 LinkID: linkID, 1136 }, nil 1137} 1138 1139// StellarProof creates a proof of a stellar wallet. 1140func StellarProof(m MetaContext, me *User, walletAddress stellar1.AccountID, 1141 signingKey GenericKey) (*ProofMetadataRes, error) { 1142 if me == nil { 1143 return nil, fmt.Errorf("missing user object for proof") 1144 } 1145 walletPubKey, err := MakeNaclSigningKeyPairFromStellarAccountID(walletAddress) 1146 if err != nil { 1147 return nil, err 1148 } 1149 walletKID := walletPubKey.GetKID() 1150 1151 ret, err := ProofMetadata{ 1152 Me: me, 1153 LinkType: LinkTypeWalletStellar, 1154 SigningKey: signingKey, 1155 SigVersion: KeybaseSignatureV2, 1156 IgnoreIfUnsupported: SigIgnoreIfUnsupported(true), 1157 }.ToJSON2(m) 1158 if err != nil { 1159 return nil, err 1160 } 1161 1162 walletSection := jsonw.NewDictionary() 1163 err = walletSection.SetKey("address", jsonw.NewString(walletAddress.String())) 1164 if err != nil { 1165 return nil, err 1166 } 1167 err = walletSection.SetKey("network", jsonw.NewString(string(WalletNetworkStellar))) 1168 if err != nil { 1169 return nil, err 1170 } 1171 1172 // Inner links can be hidden. To prevent an attacker from figuring out the 1173 // contents from the hash of the inner link, add 18 random bytes. 1174 entropy, err := LinkEntropy() 1175 if err != nil { 1176 return nil, err 1177 } 1178 err = walletSection.SetKey("entropy", jsonw.NewString(entropy)) 1179 if err != nil { 1180 return nil, err 1181 } 1182 1183 walletKeySection := jsonw.NewDictionary() 1184 err = walletKeySection.SetKey("kid", jsonw.NewString(walletKID.String())) 1185 if err != nil { 1186 return nil, err 1187 } 1188 // The caller is responsible for overwriting reverse_sig after signing. 1189 err = walletKeySection.SetKey("reverse_sig", jsonw.NewNil()) 1190 if err != nil { 1191 return nil, err 1192 } 1193 1194 body := ret.J.AtKey("body") 1195 err = body.SetKey("wallet", walletSection) 1196 if err != nil { 1197 return nil, err 1198 } 1199 err = body.SetKey("wallet_key", walletKeySection) 1200 if err != nil { 1201 return nil, err 1202 } 1203 return ret, nil 1204} 1205 1206// Make a stellar proof with a reverse sig. 1207// Modifies the User `me` with a sigchain bump and key delegation. 1208// Returns a JSONPayload ready for use in "sigs" in sig/multi. 1209func StellarProofReverseSigned(m MetaContext, me *User, walletAddress stellar1.AccountID, 1210 stellarSigner stellar1.SecretKey, deviceSigner GenericKey) (*UserLinkSignature, error) { 1211 // Make reverse sig 1212 forward, err := StellarProof(m, me, walletAddress, deviceSigner) 1213 if err != nil { 1214 return nil, err 1215 } 1216 stellarSignerKey, err := MakeNaclSigningKeyPairFromStellarSecretKey(stellarSigner) 1217 if err != nil { 1218 return nil, err 1219 } 1220 reverseSig, _, _, err := SignJSON(forward.J, stellarSignerKey) 1221 if err != nil { 1222 return nil, err 1223 } 1224 1225 // Make sig 1226 jw := forward.J 1227 err = jw.SetValueAtPath("body.wallet_key.reverse_sig", jsonw.NewString(reverseSig)) 1228 if err != nil { 1229 return nil, err 1230 } 1231 innerJSON, err := jw.Marshal() 1232 if err != nil { 1233 return nil, err 1234 } 1235 sig, sigID, linkID, err := MakeSig( 1236 m, 1237 deviceSigner, 1238 LinkTypeWalletStellar, 1239 innerJSON, 1240 SigHasRevokes(false), 1241 keybase1.SeqType_PUBLIC, 1242 SigIgnoreIfUnsupported(true), 1243 me, 1244 KeybaseSignatureV2, 1245 ) 1246 if err != nil { 1247 return nil, err 1248 } 1249 1250 // Update the user locally 1251 me.SigChainBump(linkID, sigID, false) 1252 // TODO: do we need to locally do something like me.localDelegatePerUserKey? 1253 1254 payload := make(JSONPayload) 1255 payload["sig"] = sig 1256 payload["sig_inner"] = string(innerJSON) 1257 payload["signing_kid"] = deviceSigner.GetKID().String() 1258 payload["public_key"] = stellarSignerKey.GetKID().String() 1259 payload["type"] = LinkTypeWalletStellar 1260 return &UserLinkSignature{ 1261 Payload: payload, 1262 Seqno: forward.Seqno, 1263 LinkID: linkID, 1264 }, nil 1265} 1266