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

     1  package libkb
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/buger/jsonparser"
     8  	"github.com/keybase/client/go/jsonparserw"
     9  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    10  )
    11  
    12  func LoadUPAKLite(arg LoadUserArg) (ret *keybase1.UPKLiteV1AllIncarnations, err error) {
    13  	uid := arg.uid
    14  	m := arg.m
    15  
    16  	user, err := LoadUserFromServer(m, uid, nil)
    17  	if err != nil {
    18  		return nil, err
    19  	}
    20  	leaf, err := lookupMerkleLeaf(m, uid, false, nil, MerkleOpts{NoServerPolling: false})
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  	loader := NewHighSigChainLoader(m, user, leaf)
    25  	highChain, err := loader.Load()
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	return buildUPKLiteAllIncarnations(m, user, leaf, highChain)
    30  }
    31  
    32  type HighSigChainLoader struct {
    33  	MetaContextified
    34  	user      *User
    35  	leaf      *MerkleUserLeaf
    36  	chain     *HighSigChain
    37  	chainType *ChainType
    38  	ckf       ComputedKeyFamily
    39  	dirtyTail *MerkleTriple
    40  }
    41  
    42  type HighSigChain struct {
    43  	MetaContextified
    44  	uid        keybase1.UID
    45  	username   NormalizedUsername
    46  	chainLinks ChainLinks
    47  	// for a locally delegated key
    48  	localCki *ComputedKeyInfos
    49  	// For a user who has never done a reset, this is 1.
    50  	currentSubchainStart keybase1.Seqno
    51  	prevSubchains        []ChainLinks
    52  }
    53  
    54  const UPKLiteMinorVersionCurrent = keybase1.UPKLiteMinorVersion_V0
    55  
    56  func NewHighSigChainLoader(m MetaContext, user *User, leaf *MerkleUserLeaf) *HighSigChainLoader {
    57  	hsc := HighSigChain{
    58  		MetaContextified: NewMetaContextified(m),
    59  		uid:              user.GetUID(),
    60  		username:         user.GetNormalizedName(),
    61  	}
    62  	loader := HighSigChainLoader{
    63  		user:             user,
    64  		leaf:             leaf,
    65  		chain:            &hsc,
    66  		chainType:        PublicChain,
    67  		MetaContextified: NewMetaContextified(m),
    68  	}
    69  	loader.ckf.kf = user.GetKeyFamily()
    70  	return &loader
    71  }
    72  
    73  func (l *HighSigChainLoader) Load() (ret *HighSigChain, err error) {
    74  	// request new links (and the unverified tail) from the server
    75  	// and put them into the highSigChain
    76  	err = l.LoadFromServer()
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	// verify the chain
    81  	err = l.chain.VerifyChain(l.M())
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	// compute keys
    86  	err = l.VerifySigsAndComputeKeys()
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return l.chain, nil
    91  }
    92  
    93  func (l *HighSigChainLoader) selfUID() (uid keybase1.UID) {
    94  	// for now let's always assume this isn't applicable, because there's
    95  	// no distinction for loading yourself
    96  	return uid
    97  }
    98  
    99  func (l *HighSigChainLoader) LoadFromServer() (err error) {
   100  	srv := l.GetMerkleTriple()
   101  	l.dirtyTail, err = l.chain.LoadFromServer(l.M(), srv, l.selfUID())
   102  	return err
   103  }
   104  
   105  func (hsc *HighSigChain) LoadFromServer(m MetaContext, t *MerkleTriple, selfUID keybase1.UID) (dirtyTail *MerkleTriple, err error) {
   106  	// get the high sigs from the server
   107  	// ------------------
   108  	m, tbs := m.WithTimeBuckets()
   109  
   110  	apiArg := APIArg{
   111  		Endpoint:    "sig/get_high",
   112  		SessionType: APISessionTypeOPTIONAL,
   113  		Args: HTTPArgs{
   114  			"uid": S{Val: hsc.uid.String()},
   115  			"c3":  I{Val: int(sigCompression3Unstubbed)},
   116  		},
   117  	}
   118  	resp, finisher, err := m.G().API.GetResp(m, apiArg)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	defer finisher()
   123  	recordFin := tbs.Record("HighSigChain.LoadFromServer.ReadAll")
   124  	body, err := io.ReadAll(resp.Body)
   125  	if err != nil {
   126  		recordFin()
   127  		return nil, err
   128  	}
   129  	recordFin()
   130  
   131  	// parse the response
   132  	// ------------------
   133  	if val, err := jsonparserw.GetInt(body, "status", "code"); err == nil {
   134  		if keybase1.StatusCode(val) == keybase1.StatusCode_SCDeleted {
   135  			return nil, UserDeletedError{}
   136  		}
   137  	}
   138  	var links ChainLinks
   139  	var lastLink *ChainLink
   140  
   141  	_, err = jsonparserw.ArrayEach(body, func(value []byte, dataType jsonparser.ValueType, offset int, inErr error) {
   142  		var link *ChainLink
   143  
   144  		parentSigChain := &SigChain{} // because we don't want the cache to use these
   145  		link, err = ImportLinkFromServer(m, parentSigChain, value, selfUID)
   146  		if err != nil {
   147  			m.Debug("Error importing link: %s", err.Error())
   148  		}
   149  		links = append(links, link)
   150  		lastLink = link
   151  	}, "sigs")
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	foundTail, err := lastLink.checkAgainstMerkleTree(t)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	if !foundTail {
   161  		err = fmt.Errorf("Last link is not the tail")
   162  		return nil, err
   163  	}
   164  	dirtyTail = lastLink.ToMerkleTriple()
   165  
   166  	hsc.chainLinks = links
   167  	return dirtyTail, err
   168  }
   169  
   170  func (hsc *HighSigChain) VerifyChain(m MetaContext) (err error) {
   171  	defer m.Trace("HighSigChain.VerifyChain", &err)()
   172  
   173  	for i := len(hsc.chainLinks) - 1; i >= 0; i-- {
   174  		curr := hsc.chainLinks[i]
   175  		m.VLogf(VLog1, "| verify high chain link %d (%s)", curr.GetSeqno(), curr.id)
   176  		if err = curr.VerifyLink(); err != nil {
   177  			return err
   178  		}
   179  		var expectedPrevID LinkID
   180  		var expectedPrevSeqno keybase1.Seqno
   181  		if curr.GetHighSkip() != nil {
   182  			expectedPrevSeqno = curr.GetHighSkip().Seqno
   183  			expectedPrevID = curr.GetHighSkip().Hash
   184  		} else {
   185  			// fallback to normal prevs if the link doesn't have a high_skip
   186  			expectedPrevSeqno = curr.GetSeqno() - 1
   187  			expectedPrevID = curr.GetPrev()
   188  		}
   189  		if i == 0 && (expectedPrevSeqno != 0 || expectedPrevID != nil) {
   190  			return ChainLinkPrevHashMismatchError{
   191  				fmt.Sprintf("The first link should have 0,nil for it's expected previous. It had %d, %s", expectedPrevSeqno, expectedPrevID),
   192  			}
   193  		}
   194  		if i > 0 {
   195  			prev := hsc.chainLinks[i-1]
   196  			if !prev.id.Eq(expectedPrevID) {
   197  				return ChainLinkPrevHashMismatchError{fmt.Sprintf("Chain mismatch at seqno=%d", curr.GetSeqno())}
   198  			}
   199  			if prev.GetSeqno() != expectedPrevSeqno {
   200  				return ChainLinkWrongSeqnoError{fmt.Sprintf("Chain seqno mismatch at seqno=%d (previous=%d)", curr.GetSeqno(), prev.GetSeqno())}
   201  			}
   202  		}
   203  		if err = curr.CheckNameAndID(hsc.username, hsc.uid); err != nil {
   204  			return err
   205  		}
   206  		// this isn't being used for anything right now, but it might be useful
   207  		// if we ever want to do caching, especially as it can be distinguished
   208  		// from the other field, chainVerified
   209  		curr.highChainVerified = true
   210  	}
   211  	return nil
   212  }
   213  
   214  func (l *HighSigChainLoader) VerifySigsAndComputeKeys() (err error) {
   215  	_, err = l.chain.VerifySigsAndComputeKeys(l.M(), l.leaf.eldest, &l.ckf)
   216  	return err
   217  }
   218  
   219  func (hsc *HighSigChain) verifySigsAndComputeKeysCurrent(m MetaContext, eldest keybase1.KID, ckf *ComputedKeyFamily) (linksConsumed int, err error) {
   220  	// this is the case immediately after a reset
   221  	if ckf.kf == nil || eldest.IsNil() {
   222  		m.VLogf(VLog1, "UPAKLite short-circuit verifySigsAndComputeKeysCurrent, since no Key available")
   223  		hsc.localCki = NewComputedKeyInfos(hsc.G())
   224  		ckf.cki = hsc.localCki
   225  		return 0, err
   226  	}
   227  
   228  	var links ChainLinks
   229  	links, err = cropToRightmostSubchain(m, hsc.chainLinks, eldest, hsc.uid)
   230  	if err != nil {
   231  		return 0, err
   232  	}
   233  	if len(links) == 0 {
   234  		// actually, not sure how this can happen without eldest being nil
   235  		m.VLogf(VLog1, "Empty chain after we limited to eldest %s", eldest)
   236  		hsc.localCki = NewComputedKeyInfos(hsc.G())
   237  		ckf.cki = hsc.localCki
   238  		return 0, nil
   239  	}
   240  
   241  	hsc.currentSubchainStart = links[0].GetSeqno()
   242  	m.VLogf(VLog1, "UPAKLite verifying current chain starting at %d", int(hsc.currentSubchainStart))
   243  	_, ckf.cki, err = verifySubchain(m, hsc.username, *ckf.kf, links)
   244  	return len(links), err
   245  }
   246  
   247  func (hsc *HighSigChain) VerifySigsAndComputeKeys(m MetaContext, eldest keybase1.KID, ckf *ComputedKeyFamily) (cached bool, err error) {
   248  	username := hsc.username
   249  	uid := hsc.uid
   250  	hsc.currentSubchainStart = 0
   251  
   252  	// current
   253  	linksConsumed, err := hsc.verifySigsAndComputeKeysCurrent(m, eldest, ckf)
   254  	if err != nil || ckf.kf == nil {
   255  		return false, err
   256  	}
   257  
   258  	// historical
   259  	historicalLinks := hsc.chainLinks.omittingNRightmostLinks(linksConsumed)
   260  	if len(historicalLinks) > 0 {
   261  		m.VLogf(VLog1, "After consuming %d links, there are %d historical links left",
   262  			linksConsumed, len(historicalLinks))
   263  		// errors are ignored from this method in full sigchain loads also, because we'd rather
   264  		// not block current behavior from a failure in here.
   265  		_, prevSubchains, _ := verifySigsAndComputeKeysHistorical(m, uid, username, historicalLinks, *ckf.kf)
   266  		hsc.prevSubchains = prevSubchains
   267  	}
   268  
   269  	return false, nil
   270  }
   271  
   272  func (l *HighSigChainLoader) GetMerkleTriple() (ret *MerkleTriple) {
   273  	// leaf is what the server said was the leaf for the user
   274  	if l.leaf != nil {
   275  		ret = l.chainType.GetMerkleTriple(l.leaf)
   276  	}
   277  	return ret
   278  }
   279  
   280  func extractDeviceKeys(cki *ComputedKeyInfos) *map[keybase1.KID]keybase1.PublicKeyV2NaCl {
   281  	deviceKeys := make(map[keybase1.KID]keybase1.PublicKeyV2NaCl)
   282  	if cki != nil {
   283  		for kid := range cki.Infos {
   284  			if !KIDIsPGP(kid) {
   285  				deviceKeys[kid] = cki.exportDeviceKeyV2(kid)
   286  			}
   287  		}
   288  	}
   289  	return &deviceKeys
   290  }
   291  
   292  func buildUPKLiteAllIncarnations(m MetaContext, user *User, leaf *MerkleUserLeaf, hsc *HighSigChain) (ret *keybase1.UPKLiteV1AllIncarnations, err error) {
   293  	// build the current UPKLiteV1
   294  	uid := user.GetUID()
   295  	name := user.GetName()
   296  	status := user.GetStatus()
   297  	eldestSeqno := hsc.currentSubchainStart
   298  	deviceKeys := extractDeviceKeys(hsc.GetComputedKeyInfos())
   299  	currentUpk := keybase1.UPKLiteV1{
   300  		Uid:         uid,
   301  		Username:    name,
   302  		EldestSeqno: eldestSeqno,
   303  		Status:      status,
   304  		DeviceKeys:  *deviceKeys,
   305  		Reset:       nil,
   306  	}
   307  
   308  	// build the historical (aka PastIncarnations) UPKLiteV1s
   309  	var previousUpks []keybase1.UPKLiteV1
   310  	resetMap := make(map[int](*keybase1.ResetSummary))
   311  	if resets := leaf.resets; resets != nil {
   312  		for _, l := range resets.chain {
   313  			tmp := l.Summarize()
   314  			resetMap[int(l.ResetSeqno)] = &tmp
   315  		}
   316  	}
   317  	for idx, subchain := range hsc.prevSubchains {
   318  		latestLink := subchain[len(subchain)-1]
   319  		eldestSeqno = subchain[0].GetSeqno()
   320  		reset := resetMap[idx+1]
   321  		if reset != nil {
   322  			reset.EldestSeqno = eldestSeqno
   323  		}
   324  		prevDeviceKeys := extractDeviceKeys(latestLink.cki)
   325  		prevUpk := keybase1.UPKLiteV1{
   326  			Uid:         uid,
   327  			Username:    name,
   328  			EldestSeqno: eldestSeqno,
   329  			Status:      status,
   330  			DeviceKeys:  *prevDeviceKeys,
   331  			Reset:       reset,
   332  		}
   333  		previousUpks = append(previousUpks, prevUpk)
   334  	}
   335  
   336  	// Collect the link IDs (that is, the hashes of the signature inputs) from all chainlinks.
   337  	linkIDs := map[keybase1.Seqno]keybase1.LinkID{}
   338  	for _, link := range hsc.chainLinks {
   339  		linkIDs[link.GetSeqno()] = link.LinkID().Export()
   340  	}
   341  
   342  	final := keybase1.UPKLiteV1AllIncarnations{
   343  		Current:          currentUpk,
   344  		PastIncarnations: previousUpks,
   345  		SeqnoLinkIDs:     linkIDs,
   346  		MinorVersion:     UPKLiteMinorVersionCurrent,
   347  	}
   348  	ret = &final
   349  	return ret, err
   350  }
   351  
   352  func (hsc HighSigChain) GetComputedKeyInfos() (cki *ComputedKeyInfos) {
   353  	cki = hsc.localCki
   354  	if cki == nil {
   355  		if l := last(hsc.chainLinks); l != nil {
   356  			if l.cki == nil {
   357  				hsc.G().Log.Debug("GetComputedKeyInfos: l.cki is nil")
   358  			}
   359  			cki = l.cki
   360  		}
   361  	}
   362  	return cki
   363  }