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

     1  package libkb
     2  
     3  // UPAK = "User Plus All Keys"
     4  
     5  import (
     6  	"fmt"
     7  
     8  	"github.com/keybase/client/go/kbcrypto"
     9  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    10  )
    11  
    12  // BaseProofSet creates a basic proof set for a user with their
    13  // keybase and uid proofs and any pgp fingerprint proofs.
    14  func BaseProofSet(u *keybase1.UserPlusKeysV2AllIncarnations) *ProofSet {
    15  	proofs := []Proof{
    16  		{Key: "keybase", Value: u.GetName()},
    17  		{Key: "uid", Value: u.GetUID().String()},
    18  	}
    19  	for _, key := range u.Current.PGPKeys {
    20  		proofs = append(proofs, Proof{Key: PGPAssertionKey, Value: key.Fingerprint.String()})
    21  	}
    22  	return NewProofSet(proofs)
    23  }
    24  
    25  // checkKIDPGP checks that the user has the given PGP KID valid *now*. Note that it doesn't
    26  // check for revoked PGP keys, and it also does not check key expiration.
    27  func checkKIDPGP(u *keybase1.UserPlusKeysV2AllIncarnations, kid keybase1.KID) (found bool) {
    28  	for _, key := range u.Current.PGPKeys {
    29  		if key.Base.Kid.Equal(kid) {
    30  			return true
    31  		}
    32  	}
    33  	return false
    34  }
    35  
    36  func checkKIDKeybase(u *keybase1.UserPlusKeysV2AllIncarnations, kid keybase1.KID) (found bool, revokedAt *keybase1.KeybaseTime, deleted bool) {
    37  	exportRevokedAt := func(key keybase1.PublicKeyV2NaCl) *keybase1.KeybaseTime {
    38  		if key.Base.Revocation != nil {
    39  			// This is the inverse of the marshalling we do in rpc_exim.go.
    40  			return &keybase1.KeybaseTime{
    41  				Unix:  key.Base.Revocation.Time,
    42  				Chain: key.Base.Revocation.PrevMerkleRootSigned.Seqno,
    43  			}
    44  		}
    45  		return nil
    46  	}
    47  	for _, key := range u.Current.DeviceKeys {
    48  		if key.Base.Kid.Equal(kid) {
    49  			found = true
    50  			revokedAt = exportRevokedAt(key)
    51  		}
    52  	}
    53  	for _, pastIncarnation := range u.PastIncarnations {
    54  		for _, key := range pastIncarnation.DeviceKeys {
    55  			if key.Base.Kid.Equal(kid) {
    56  				found = true
    57  				deleted = true
    58  				revokedAt = exportRevokedAt(key)
    59  			}
    60  		}
    61  	}
    62  	return
    63  }
    64  
    65  func CheckKID(u *keybase1.UserPlusKeysV2AllIncarnations, kid keybase1.KID) (found bool, revokedAt *keybase1.KeybaseTime, deleted bool) {
    66  	if IsPGPAlgo(kbcrypto.AlgoType(kid.GetKeyType())) {
    67  		found = checkKIDPGP(u, kid)
    68  		return found, nil, false
    69  	}
    70  	return checkKIDKeybase(u, kid)
    71  }
    72  
    73  func GetRemoteChainLinkFor(m MetaContext, follower *keybase1.UserPlusKeysV2AllIncarnations, followeeUsername NormalizedUsername, followeeUID keybase1.UID) (ret *TrackChainLink, err error) {
    74  	defer m.Trace(fmt.Sprintf("UPAK#GetRemoteChainLinkFor(%s,%s,%s)", follower.Current.GetUID(), followeeUsername, followeeUID), &err)()
    75  	m.VLogf(VLog1, "| Full user: %+v\n", *follower)
    76  	rtl := follower.GetRemoteTrack(followeeUID)
    77  	if rtl == nil {
    78  		m.VLogf(VLog0, "| no remote track found")
    79  		return nil, nil
    80  	}
    81  	if !NewNormalizedUsername(rtl.Username).Eq(followeeUsername) {
    82  		return nil, UIDMismatchError{Msg: fmt.Sprintf("Usernames didn't match for (%s,%q); got %s", followeeUID, followeeUsername.String(), rtl.Uid)}
    83  	}
    84  	if !rtl.Uid.Equal(followeeUID) {
    85  		return nil, UIDMismatchError{Msg: fmt.Sprintf("UIDs didn't match for (%s,%q); got %s", followeeUID, followeeUsername.String(), rtl.Uid)}
    86  	}
    87  	var lid LinkID
    88  	m.VLogf(VLog0, "| remote track found with linkID=%s", rtl.LinkID)
    89  	lid, err = ImportLinkID(rtl.LinkID)
    90  	if err != nil {
    91  		m.Debug("| Failed to import link ID")
    92  		return nil, err
    93  	}
    94  	var link *ChainLink
    95  	link, err = ImportLinkFromStorage(m, lid, follower.GetUID())
    96  	if err != nil {
    97  		m.Debug("| failed to import link from storage")
    98  		return nil, err
    99  	}
   100  	if link == nil {
   101  		m.Debug("| no cached chainlink found")
   102  		// Such a bug is only possible if the DB cache was reset after
   103  		// this user was originally loaded in; otherwise, all of this
   104  		// UPAK's chain links should be available on disk.
   105  		return nil, InconsistentCacheStateError{}
   106  	}
   107  	ret, err = ParseTrackChainLink(GenericChainLink{link})
   108  	m.VLogf(VLog0, "| ParseTrackChainLink -> found=%v", (ret != nil))
   109  	return ret, err
   110  }
   111  
   112  func TrackChainLinkFromUPK2AI(m MetaContext, follower *keybase1.UserPlusKeysV2AllIncarnations, followeeUsername NormalizedUsername, followeeUID keybase1.UID) (*TrackChainLink, error) {
   113  	tcl, err := GetRemoteChainLinkFor(m, follower, followeeUsername, followeeUID)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	tcl, err = TrackChainLinkFor(m, follower.Current.Uid, followeeUID, tcl, err)
   118  	return tcl, err
   119  }
   120  
   121  func NormalizedUsernameFromUPK2(u keybase1.UserPlusKeysV2) NormalizedUsername {
   122  	return NewNormalizedUsername(u.Username)
   123  }