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

     1  package libkb
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"encoding/base64"
     6  	"errors"
     7  	"fmt"
     8  	"sort"
     9  	"strings"
    10  	"sync"
    11  
    12  	"github.com/keybase/client/go/kbcrypto"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/go-codec/codec"
    15  	"golang.org/x/crypto/nacl/secretbox"
    16  )
    17  
    18  const PerUserKeySeedSize = 32
    19  
    20  // A secretbox containg a seed encrypted for its successor generation
    21  type PerUserKeyPrev string
    22  
    23  type PerUserKeySeed [PerUserKeySeedSize]byte
    24  
    25  func (s *PerUserKeySeed) DeriveSigningKey() (*NaclSigningKeyPair, error) {
    26  	derived, err := DeriveFromSecret(*s, DeriveReasonPUKSigning)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	res, err := MakeNaclSigningKeyPairFromSecret(derived)
    31  	return &res, err
    32  }
    33  
    34  func (s *PerUserKeySeed) DeriveDHKey() (*NaclDHKeyPair, error) {
    35  	derived, err := DeriveFromSecret(*s, DeriveReasonPUKEncryption)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	res, err := MakeNaclDHKeyPairFromSecret(derived)
    40  	return &res, err
    41  }
    42  
    43  func (s *PerUserKeySeed) DeriveSymmetricKey(reason DeriveReason) (res NaclSecretBoxKey, err error) {
    44  	derived, err := DeriveFromSecret(*s, reason)
    45  	if err != nil {
    46  		return res, err
    47  	}
    48  	return NaclSecretBoxKey(derived), err
    49  }
    50  
    51  // derivePrevKey derives the symmetric key used to secretbox the previous generation seed.
    52  func (s *PerUserKeySeed) derivePrevKey() (res NaclSecretBoxKey, err error) {
    53  	return s.DeriveSymmetricKey(DeriveReasonPUKPrev)
    54  }
    55  
    56  func (s *PerUserKeySeed) IsBlank() bool {
    57  	var blank PerUserKeySeed
    58  	return (subtle.ConstantTimeCompare(s[:], blank[:]) == 1)
    59  }
    60  
    61  func NewPerUserKeyBox(contents PerUserKeySeed, receiverKey NaclDHKeyPair, senderKey NaclDHKeyPair, generation keybase1.PerUserKeyGeneration) (keybase1.PerUserKeyBox, error) {
    62  	if contents.IsBlank() {
    63  		return keybase1.PerUserKeyBox{}, errors.New("attempt to box blank per-user-key")
    64  	}
    65  
    66  	encInfo, err := receiverKey.Encrypt(contents[:], &senderKey)
    67  	if err != nil {
    68  		return keybase1.PerUserKeyBox{}, err
    69  	}
    70  	boxStr, err := kbcrypto.EncodePacketToArmoredString(encInfo)
    71  	if err != nil {
    72  		return keybase1.PerUserKeyBox{}, err
    73  	}
    74  
    75  	return keybase1.PerUserKeyBox{
    76  		Box:         boxStr,
    77  		ReceiverKID: receiverKey.GetKID(),
    78  		Generation:  generation,
    79  	}, nil
    80  }
    81  
    82  // Returns base64 of a msgpack array of 3 items: [version, nonce, box]
    83  // Does not do any derivation steps. Caller should pass symmetricKey derived with pukContextPrev.
    84  func newPerUserKeyPrev(contents PerUserKeySeed, symmetricKey NaclSecretBoxKey) (PerUserKeyPrev, error) {
    85  	if contents.IsBlank() {
    86  		return "", errors.New("attempt to secretbox blank per-user-key")
    87  	}
    88  
    89  	const version = 1
    90  
    91  	var nonce [NaclDHNonceSize]byte
    92  	nonce, err := RandomNaclDHNonce()
    93  	if err != nil {
    94  		return "", err
    95  	}
    96  
    97  	// secretbox
    98  	sealed := secretbox.Seal(nil, contents[:], &nonce, (*[NaclSecretBoxKeySize]byte)(&symmetricKey))
    99  
   100  	parts := []interface{}{version, nonce, sealed}
   101  
   102  	// msgpack
   103  	mh := codec.MsgpackHandle{WriteExt: true}
   104  	var msgpacked []byte
   105  	enc := codec.NewEncoderBytes(&msgpacked, &mh)
   106  	err = enc.Encode(parts)
   107  	if err != nil {
   108  		return "", err
   109  	}
   110  
   111  	// b64
   112  	return PerUserKeyPrev(base64.StdEncoding.EncodeToString(msgpacked)), nil
   113  }
   114  
   115  // Opens the output of NewPerUserKeyPrev
   116  func openPerUserKeyPrev(sbox PerUserKeyPrev, symmetricKey NaclSecretBoxKey) (PerUserKeySeed, error) {
   117  	var res PerUserKeySeed
   118  
   119  	// decode b64
   120  	msgpacked, err := base64.StdEncoding.DecodeString(string(sbox))
   121  	if err != nil {
   122  		return res, err
   123  	}
   124  
   125  	// decode msgpack
   126  	mh := codec.MsgpackHandle{WriteExt: true}
   127  	dec := codec.NewDecoderBytes(msgpacked, &mh)
   128  	var parts struct {
   129  		Version int
   130  		Nonce   []byte
   131  		Sealed  []byte
   132  	}
   133  	err = dec.Decode(&parts)
   134  	if err != nil {
   135  		return res, err
   136  	}
   137  
   138  	// check parts
   139  	if parts.Version != 1 {
   140  		return res, fmt.Errorf("per user key secret box version %v != 1", parts.Version)
   141  	}
   142  
   143  	if len(parts.Nonce) != NaclDHNonceSize {
   144  		return res, fmt.Errorf("per user key secret box nonce length %v != %v",
   145  			len(parts.Nonce), NaclDHNonceSize)
   146  	}
   147  	var nonce [NaclDHNonceSize]byte
   148  	copy(nonce[:], parts.Nonce)
   149  
   150  	expectedSealedLength := PerUserKeySeedSize + secretbox.Overhead
   151  	if len(parts.Sealed) != expectedSealedLength {
   152  		return res, fmt.Errorf("per user key secret box sealed length %v != %v", len(parts.Sealed), expectedSealedLength)
   153  	}
   154  
   155  	// open secretbox
   156  	var symmetricKey2 [NaclSecretBoxKeySize]byte = symmetricKey
   157  	contents, ok := secretbox.Open(nil, parts.Sealed, &nonce, &symmetricKey2)
   158  	if !ok {
   159  		return res, errors.New("per user key secret box open failed")
   160  	}
   161  	if len(contents) != PerUserKeySeedSize {
   162  		return res, fmt.Errorf("per user key seed length %v != %v", len(contents), PerUserKeySeedSize)
   163  	}
   164  	return MakeByte32(contents), nil
   165  }
   166  
   167  type perUserKeyFull struct {
   168  	seed   PerUserKeySeed
   169  	sigKey *NaclSigningKeyPair
   170  	encKey *NaclDHKeyPair
   171  }
   172  
   173  type perUserKeyMap map[keybase1.PerUserKeyGeneration]perUserKeyFull
   174  type perUserKeySeqGenMap map[keybase1.Seqno]keybase1.PerUserKeyGeneration
   175  
   176  // PerUserKeyring holds on to all versions of the per user key.
   177  // Generation=0 should be nil, but all others should be present.
   178  type PerUserKeyring struct {
   179  	Contextified
   180  	sync.Mutex
   181  	uid         keybase1.UID
   182  	generations perUserKeyMap
   183  	// sigchain seqno when each key was introduced
   184  	seqgen perUserKeySeqGenMap
   185  }
   186  
   187  // NewPerUserKeyring makes a new per-user-key keyring for a given UID.
   188  func NewPerUserKeyring(g *GlobalContext, uid keybase1.UID) (*PerUserKeyring, error) {
   189  	if uid.IsNil() {
   190  		return nil, fmt.Errorf("NewPerUserKeyring called with nil uid")
   191  	}
   192  	return &PerUserKeyring{
   193  		Contextified: NewContextified(g),
   194  		uid:          uid,
   195  		generations:  make(perUserKeyMap),
   196  		seqgen:       make(perUserKeySeqGenMap),
   197  	}, nil
   198  }
   199  
   200  func (s *PerUserKeyring) GetUID() keybase1.UID {
   201  	return s.uid
   202  }
   203  
   204  // PrepareBoxForNewDevice encrypts the latest shared key seed for a new device.
   205  // The returned box should be pushed to the server.
   206  func (s *PerUserKeyring) PrepareBoxForNewDevice(m MetaContext, receiverKey NaclDHKeyPair,
   207  	senderKey NaclDHKeyPair) (box keybase1.PerUserKeyBox, err error) {
   208  	s.Lock()
   209  	defer s.Unlock()
   210  
   211  	gen := s.currentGenerationLocked()
   212  	if gen < 1 {
   213  		return box, errors.New("PerUserKeyring#PrepareBoxForNewDevice no keys loaded")
   214  	}
   215  	full, ok := s.generations[gen]
   216  	if !ok {
   217  		return box, errors.New("PerUserKeyring#PrepareBoxForNewDevice missing entry for current generation")
   218  	}
   219  	box, err = NewPerUserKeyBox(full.seed, receiverKey, senderKey, gen)
   220  	return box, err
   221  }
   222  
   223  // Encrypt seed for receiverKeys. Use senderKey to encrypt.
   224  // Does not use the keyring at all. Attached for organizational purposes.
   225  // Used when creating a new seed.
   226  func (s *PerUserKeyring) PrepareBoxesForDevices(m MetaContext, contents PerUserKeySeed,
   227  	generation keybase1.PerUserKeyGeneration, receiverKeys []NaclDHKeyPair,
   228  	senderKey GenericKey) (boxes []keybase1.PerUserKeyBox, err error) {
   229  	// Do not lock self because we do not use self.
   230  
   231  	if contents.IsBlank() {
   232  		return nil, errors.New("attempt to box blank per-user-key")
   233  	}
   234  
   235  	senderKeyDH, ok := senderKey.(NaclDHKeyPair)
   236  	if !ok {
   237  		return nil, fmt.Errorf("Unexpected encryption key type: %T", senderKey)
   238  	}
   239  
   240  	for _, receiverKey := range receiverKeys {
   241  		box, err := NewPerUserKeyBox(contents, receiverKey, senderKeyDH, generation)
   242  		if err != nil {
   243  			return nil, err
   244  		}
   245  		boxes = append(boxes, box)
   246  	}
   247  	return boxes, nil
   248  }
   249  
   250  // Prepares a prev secretbox containing generation n-1 encrypted for generation n.
   251  // Asserts that the current generation is n-1.
   252  // The `generation` parameter is n.
   253  func (s *PerUserKeyring) PreparePrev(m MetaContext, newSeed PerUserKeySeed,
   254  	newGeneration keybase1.PerUserKeyGeneration) (PerUserKeyPrev, error) {
   255  	s.Lock()
   256  	defer s.Unlock()
   257  
   258  	if newSeed.IsBlank() {
   259  		return "", errors.New("attempt to prev with blank per-user-key")
   260  	}
   261  
   262  	currentGen := s.currentGenerationLocked()
   263  	if currentGen == 0 {
   264  		return "", errors.New("attempt to prepare per-user-key prev with no keys")
   265  	}
   266  	if currentGen != newGeneration-1 {
   267  		return "", fmt.Errorf("incompatible prev generations %v != %v-1", currentGen, newGeneration)
   268  	}
   269  
   270  	symmetricKey, err := newSeed.derivePrevKey()
   271  	if err != nil {
   272  		return "", err
   273  	}
   274  
   275  	contents := s.generations[currentGen].seed
   276  
   277  	return newPerUserKeyPrev(contents, symmetricKey)
   278  }
   279  
   280  // AddKey registers a full key locally.
   281  func (s *PerUserKeyring) AddKey(m MetaContext, generation keybase1.PerUserKeyGeneration,
   282  	seqno keybase1.Seqno, seed PerUserKeySeed) error {
   283  	s.Lock()
   284  	defer s.Unlock()
   285  	m.Debug("PerUserKeyring#AddKey(generation: %v, seqno:%v)", generation, seqno)
   286  
   287  	if seed.IsBlank() {
   288  		return errors.New("attempt to add blank per-user-key")
   289  	}
   290  
   291  	currentGen := s.currentGenerationLocked()
   292  
   293  	if generation != currentGen+1 {
   294  		return fmt.Errorf("cannot add key for non-next generation: %v != %v+1",
   295  			generation, currentGen)
   296  	}
   297  
   298  	_, exists := s.generations[generation]
   299  	if exists {
   300  		return fmt.Errorf("AddKey duplicate for generation: %v", generation)
   301  	}
   302  
   303  	expanded, err := expandPerUserKey(seed)
   304  	if err != nil {
   305  		return err
   306  	}
   307  
   308  	s.generations[generation] = expanded.lower()
   309  	s.seqgen[seqno] = generation
   310  
   311  	return nil
   312  }
   313  
   314  func (s *PerUserKeyring) HasAnyKeys() bool {
   315  	return s.CurrentGeneration() > 0
   316  }
   317  
   318  // CurrentGeneration returns what generation we're on. The version possible
   319  // Version is 1. Version 0 implies no keys are available.
   320  func (s *PerUserKeyring) CurrentGeneration() keybase1.PerUserKeyGeneration {
   321  	s.Lock()
   322  	defer s.Unlock()
   323  	return s.currentGenerationLocked()
   324  }
   325  
   326  func (s *PerUserKeyring) currentGenerationLocked() keybase1.PerUserKeyGeneration {
   327  	return keybase1.PerUserKeyGeneration(len(s.generations))
   328  }
   329  
   330  func (s *PerUserKeyring) GetLatestSigningKey(m MetaContext) (*NaclSigningKeyPair, error) {
   331  	s.Lock()
   332  	defer s.Unlock()
   333  	gen := s.currentGenerationLocked()
   334  	if gen < 1 {
   335  		return nil, errors.New("PerUserKeyring#GetLatestSigningKey no keys loaded")
   336  	}
   337  	key, found := s.generations[gen]
   338  	if !found {
   339  		return nil, fmt.Errorf("PerUserKeyring#GetLatestSigningKey no key for generation %v", gen)
   340  	}
   341  	return key.sigKey, nil
   342  }
   343  
   344  func (s *PerUserKeyring) GetSeedByGeneration(m MetaContext, gen keybase1.PerUserKeyGeneration) (res PerUserKeySeed, err error) {
   345  	s.Lock()
   346  	defer s.Unlock()
   347  	if gen < 1 {
   348  		return res, fmt.Errorf("PerUserKeyring#GetSeedByGeneration bad generation: %v", gen)
   349  	}
   350  	if len(s.generations) < 1 {
   351  		return res, fmt.Errorf("no per-user-keys in keyring")
   352  	}
   353  	key, found := s.generations[gen]
   354  	if !found {
   355  		return res, fmt.Errorf("no per-user-key for generation: %v", gen)
   356  	}
   357  	return key.seed, nil
   358  }
   359  
   360  func (s *PerUserKeyring) GetSeedByGenerationOrSync(m MetaContext, gen keybase1.PerUserKeyGeneration) (res PerUserKeySeed, err error) {
   361  	if seed, err := s.GetSeedByGeneration(m, gen); err == nil {
   362  		return seed, nil
   363  	}
   364  	// Generation was not available, try to sync.
   365  	if err := s.Sync(m); err != nil {
   366  		return res, err
   367  	}
   368  	return s.GetSeedByGeneration(m, gen)
   369  }
   370  
   371  // Get the encryption key of a generation.
   372  func (s *PerUserKeyring) GetEncryptionKeyByGeneration(m MetaContext, gen keybase1.PerUserKeyGeneration) (*NaclDHKeyPair, error) {
   373  	s.Lock()
   374  	defer s.Unlock()
   375  
   376  	return s.getEncryptionKeyByGenerationLocked(m, gen)
   377  }
   378  
   379  func (s *PerUserKeyring) GetEncryptionKeyByGenerationOrSync(m MetaContext, gen keybase1.PerUserKeyGeneration) (*NaclDHKeyPair, error) {
   380  	if key, err := s.GetEncryptionKeyByGeneration(m, gen); err == nil {
   381  		return key, nil
   382  	}
   383  
   384  	// Generation was not available, try to sync.
   385  	if err := s.Sync(m); err != nil {
   386  		return nil, err
   387  	}
   388  	return s.GetEncryptionKeyByGeneration(m, gen)
   389  }
   390  
   391  func (s *PerUserKeyring) getEncryptionKeyByGenerationLocked(m MetaContext, gen keybase1.PerUserKeyGeneration) (*NaclDHKeyPair, error) {
   392  	if gen < 1 {
   393  		return nil, fmt.Errorf("PerUserKeyring#GetEncryptionKey bad generation: %v", gen)
   394  	}
   395  	key, found := s.generations[gen]
   396  	if !found {
   397  		return nil, fmt.Errorf("no encryption key for generation: %v", gen)
   398  	}
   399  	return key.encKey, nil
   400  }
   401  
   402  // Get the encryption key at the user sigchain seqno.
   403  func (s *PerUserKeyring) GetEncryptionKeyBySeqno(m MetaContext, seqno keybase1.Seqno) (*NaclDHKeyPair, error) {
   404  	s.Lock()
   405  	defer s.Unlock()
   406  
   407  	gen, ok := s.seqgen[seqno]
   408  	if !ok {
   409  		return nil, fmt.Errorf("no encrypted key for seqno %v", seqno)
   410  	}
   411  	return s.getEncryptionKeyByGenerationLocked(m, gen)
   412  }
   413  
   414  func (s *PerUserKeyring) GetEncryptionKeyBySeqnoOrSync(m MetaContext, seqno keybase1.Seqno) (*NaclDHKeyPair, error) {
   415  	if key, err := s.GetEncryptionKeyBySeqno(m, seqno); err == nil {
   416  		return key, nil
   417  	}
   418  	// Key at generation from seqno was not available, try to sync.
   419  	if err := s.Sync(m); err != nil {
   420  		return nil, err
   421  	}
   422  	return s.GetEncryptionKeyBySeqno(m, seqno)
   423  }
   424  
   425  // GetEncryptionKeyByKID finds an encryption key that matches kid.
   426  func (s *PerUserKeyring) GetEncryptionKeyByKID(m MetaContext, kid keybase1.KID) (*NaclDHKeyPair, error) {
   427  	s.Lock()
   428  	defer s.Unlock()
   429  
   430  	for _, key := range s.generations {
   431  		if key.encKey.GetKID().Equal(kid) {
   432  			return key.encKey, nil
   433  		}
   434  	}
   435  	return nil, NotFoundError{Msg: fmt.Sprintf("no per-user encryption key found for KID %s", kid)}
   436  }
   437  
   438  // Sync our PerUserKeyring with the server. It will either add all new
   439  // keys since our last update, or not at all if there was an error.
   440  // Pass it a standard Go network context.
   441  func (s *PerUserKeyring) Sync(m MetaContext) (err error) {
   442  	return s.syncAsConfiguredDevice(m, nil)
   443  }
   444  
   445  // `m.LoginContext` and `upak` are optional
   446  func (s *PerUserKeyring) SyncWithExtras(m MetaContext, upak *keybase1.UserPlusAllKeys) (err error) {
   447  	return s.syncAsConfiguredDevice(m, upak)
   448  }
   449  
   450  // `m.LoginContext` and `upak` are optional
   451  func (s *PerUserKeyring) syncAsConfiguredDevice(m MetaContext, upak *keybase1.UserPlusAllKeys) (err error) {
   452  	uv, deviceID, _, _, activeDecryptionKey := m.ActiveDevice().AllFields()
   453  	if !s.uid.Equal(uv.Uid) {
   454  		return fmt.Errorf("UID changed on PerUserKeyring")
   455  	}
   456  	if deviceID.IsNil() {
   457  		return fmt.Errorf("missing configured deviceID")
   458  	}
   459  	return s.sync(m, upak, deviceID, activeDecryptionKey)
   460  }
   461  
   462  // `m.LoginContext` and `upak` are optional
   463  func (s *PerUserKeyring) SyncAsProvisioningKey(m MetaContext, upak *keybase1.UserPlusAllKeys, deviceID keybase1.DeviceID, decryptionKey GenericKey) (err error) {
   464  	if deviceID.IsNil() {
   465  		return fmt.Errorf("missing deviceID")
   466  	}
   467  	// Note this `== nil` check might not work, as it might be a typed nil.
   468  	if decryptionKey == nil {
   469  		return fmt.Errorf("missing decryption key")
   470  	}
   471  	return s.sync(m, upak, deviceID, decryptionKey)
   472  }
   473  
   474  // `m.LoginContext` and `upak` are optional
   475  func (s *PerUserKeyring) sync(m MetaContext, upak *keybase1.UserPlusAllKeys, deviceID keybase1.DeviceID, decryptionKey GenericKey) (err error) {
   476  	defer m.Trace("PerUserKeyring#sync", &err)()
   477  
   478  	m.Debug("PerUserKeyring#sync(%v, %v)", m.LoginContext() != nil, upak != nil)
   479  
   480  	s.Lock()
   481  	defer s.Unlock()
   482  
   483  	box, prevs, err := s.fetchBoxesLocked(m, deviceID)
   484  	if err != nil {
   485  		return err
   486  	}
   487  
   488  	if upak == nil {
   489  		upak, err = s.getUPAK(m, upak, false)
   490  		if err != nil {
   491  			return err
   492  		}
   493  	}
   494  
   495  	checker := newPerUserKeyChecker(upak)
   496  	newKeys, err := s.importLocked(m, box, prevs, decryptionKey, checker)
   497  	if err != nil {
   498  		return err
   499  
   500  	}
   501  	return s.mergeLocked(newKeys, checker.seqgen)
   502  }
   503  
   504  func (s *PerUserKeyring) getUPAK(m MetaContext, upak *keybase1.UserPlusAllKeys,
   505  	forceReload bool) (*keybase1.UserPlusAllKeys, error) {
   506  	if upak != nil {
   507  		return upak, nil
   508  	}
   509  	upakArg := NewLoadUserArgWithMetaContext(m).WithUID(s.uid).WithForcePoll(
   510  		forceReload)
   511  	upak, _, err := m.G().GetUPAKLoader().Load(upakArg)
   512  	return upak, err
   513  }
   514  
   515  func (s *PerUserKeyring) mergeLocked(m perUserKeyMap, seqgen perUserKeySeqGenMap) (err error) {
   516  	for k, v := range m {
   517  		s.generations[k] = v
   518  	}
   519  	s.seqgen = seqgen
   520  	return nil
   521  }
   522  
   523  type perUserKeySyncResp struct {
   524  	Box    *keybase1.PerUserKeyBox `json:"box"`
   525  	Prevs  []perUserKeyPrevResp    `json:"prevs"`
   526  	Status AppStatus               `json:"status"`
   527  }
   528  
   529  func (s *perUserKeySyncResp) GetAppStatus() *AppStatus {
   530  	return &s.Status
   531  }
   532  
   533  type perUserKeyPrevResp struct {
   534  	Ctext      PerUserKeyPrev                `json:"ctext"`
   535  	Generation keybase1.PerUserKeyGeneration `json:"generation"`
   536  }
   537  
   538  type byGeneration []perUserKeyPrevResp
   539  
   540  func (m byGeneration) Len() int           { return len(m) }
   541  func (m byGeneration) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }
   542  func (m byGeneration) Less(i, j int) bool { return m[i].Generation < m[j].Generation }
   543  
   544  func (s *PerUserKeyring) fetchBoxesLocked(m MetaContext,
   545  	deviceID keybase1.DeviceID) (box *keybase1.PerUserKeyBox, prevs []perUserKeyPrevResp, err error) {
   546  
   547  	defer m.Trace("PerUserKeyring#fetchBoxesLocked", &err)()
   548  
   549  	var resp perUserKeySyncResp
   550  	err = m.G().API.GetDecode(m, APIArg{
   551  		Endpoint: "key/fetch_per_user_key_secrets",
   552  		Args: HTTPArgs{
   553  			"generation": I{int(s.currentGenerationLocked())},
   554  			"device_id":  S{deviceID.String()},
   555  		},
   556  		SessionType: APISessionTypeREQUIRED,
   557  		RetryCount:  5, // It's pretty bad to fail this, so retry.
   558  	}, &resp)
   559  	if err != nil {
   560  		return nil, nil, err
   561  	}
   562  	m.Debug("| Got back box:%v and prevs:%d from server", resp.Box != nil, len(resp.Prevs))
   563  
   564  	return resp.Box, resp.Prevs, nil
   565  }
   566  
   567  // perUserKeyChecker checks the [secret]boxes returned from the server
   568  // against the public keys advertised in the user's sigchain. As we import
   569  // keys, we check them.  We check that the boxes were encrypted with a
   570  // valid device subkey (though it can be now revoked). And we check that the
   571  // public keys corresponds to what was signed in as a per_user_key.
   572  type perUserKeyChecker struct {
   573  	allowedEncryptingKIDs map[keybase1.KID]bool
   574  	expectedPUKSigKIDs    map[keybase1.PerUserKeyGeneration]keybase1.KID
   575  	expectedPUKEncKIDs    map[keybase1.PerUserKeyGeneration]keybase1.KID
   576  	latestGeneration      keybase1.PerUserKeyGeneration
   577  	seqgen                perUserKeySeqGenMap
   578  }
   579  
   580  func newPerUserKeyChecker(upak *keybase1.UserPlusAllKeys) *perUserKeyChecker {
   581  	ret := perUserKeyChecker{
   582  		allowedEncryptingKIDs: make(map[keybase1.KID]bool),
   583  		expectedPUKSigKIDs:    make(map[keybase1.PerUserKeyGeneration]keybase1.KID),
   584  		expectedPUKEncKIDs:    make(map[keybase1.PerUserKeyGeneration]keybase1.KID),
   585  		latestGeneration:      0,
   586  		seqgen:                make(perUserKeySeqGenMap),
   587  	}
   588  	isEncryptionKey := func(k keybase1.PublicKey) bool {
   589  		return !k.IsSibkey && k.PGPFingerprint == ""
   590  	}
   591  	for _, r := range upak.Base.RevokedDeviceKeys {
   592  		if isEncryptionKey(r.Key) {
   593  			ret.allowedEncryptingKIDs[r.Key.KID] = true
   594  		}
   595  	}
   596  	for _, k := range upak.Base.DeviceKeys {
   597  		if isEncryptionKey(k) {
   598  			ret.allowedEncryptingKIDs[k.KID] = true
   599  		}
   600  	}
   601  	for _, k := range upak.Base.PerUserKeys {
   602  		ret.expectedPUKSigKIDs[keybase1.PerUserKeyGeneration(k.Gen)] = k.SigKID
   603  		ret.expectedPUKEncKIDs[keybase1.PerUserKeyGeneration(k.Gen)] = k.EncKID
   604  		gen := keybase1.PerUserKeyGeneration(k.Gen)
   605  		ret.seqgen[k.Seqno] = gen
   606  		if gen > ret.latestGeneration {
   607  			ret.latestGeneration = gen
   608  		}
   609  	}
   610  
   611  	return &ret
   612  }
   613  
   614  // checkPublic checks that a key matches the KIDs published by the user.
   615  func (c *perUserKeyChecker) checkPublic(key importedPerUserKey, generation keybase1.PerUserKeyGeneration) error {
   616  	// sig key
   617  	if expectedSigKID, ok := c.expectedPUKSigKIDs[generation]; ok {
   618  		if !expectedSigKID.SecureEqual(key.sigKey.GetKID()) {
   619  			return fmt.Errorf("import per-user-key: wrong sigKID expected %v", expectedSigKID.String())
   620  		}
   621  	} else {
   622  		return fmt.Errorf("import per-user-key: no sigKID for generation: %v", generation)
   623  	}
   624  
   625  	// enc key
   626  	if expectedEncKID, ok := c.expectedPUKEncKIDs[generation]; ok {
   627  		if !expectedEncKID.SecureEqual(key.encKey.GetKID()) {
   628  			return fmt.Errorf("import per-user-key: wrong sigKID expected %v", expectedEncKID.String())
   629  		}
   630  	} else {
   631  		return fmt.Errorf("import per-user-key: no sigKID for generation: %v", generation)
   632  	}
   633  
   634  	return nil
   635  }
   636  
   637  func (s *PerUserKeyring) importLocked(m MetaContext,
   638  	box *keybase1.PerUserKeyBox, prevs []perUserKeyPrevResp,
   639  	decryptionKey GenericKey, checker *perUserKeyChecker) (ret perUserKeyMap, err error) {
   640  
   641  	defer m.Trace("PerUserKeyring#importLocked", &err)()
   642  
   643  	if box == nil && len(prevs) == 0 {
   644  		// No new stuff, this keyring is up to date.
   645  		return make(perUserKeyMap), nil
   646  	}
   647  
   648  	if box == nil {
   649  		return nil, errors.New("per-user-key import nil box")
   650  	}
   651  
   652  	if box.Generation > checker.latestGeneration {
   653  		// Let's get a new UPAK in case that's just out of date.
   654  		upak, err := s.getUPAK(m, nil, true)
   655  		if err != nil {
   656  			return nil, err
   657  		}
   658  		checker = newPerUserKeyChecker(upak)
   659  	}
   660  	if box.Generation != checker.latestGeneration {
   661  		return nil, fmt.Errorf("sync (%v) and checker (%v) disagree on generation", box.Generation, checker.latestGeneration)
   662  	}
   663  
   664  	sort.Sort(sort.Reverse(byGeneration(prevs)))
   665  
   666  	var debugPrevGenList []string
   667  	for _, prev := range prevs {
   668  		debugPrevGenList = append(debugPrevGenList, fmt.Sprintf("%d", prev.Generation))
   669  	}
   670  	if len(debugPrevGenList) > 0 {
   671  		m.Debug("PerUserKeyring#importLocked prevs:(%s)", strings.Join(debugPrevGenList, ","))
   672  	}
   673  
   674  	ret = make(perUserKeyMap)
   675  	imp1, err := importPerUserKeyBox(box, decryptionKey, checker.latestGeneration, checker)
   676  	if err != nil {
   677  		return nil, err
   678  	}
   679  	ret[box.Generation] = imp1.lower()
   680  
   681  	walkGeneration := box.Generation - 1
   682  	walkKey := imp1.prevKey
   683  	for _, prev := range prevs {
   684  		if walkGeneration <= 0 {
   685  			return nil, errors.New("per-user-key prev chain too long")
   686  		}
   687  		imp, err := importPerUserKeyPrev(walkGeneration, prev, walkKey, walkGeneration, checker)
   688  		if err != nil {
   689  			return nil, err
   690  		}
   691  		ret[walkGeneration] = imp.lower()
   692  
   693  		walkGeneration--
   694  		walkKey = imp.prevKey
   695  	}
   696  
   697  	return ret, nil
   698  }
   699  
   700  type importedPerUserKey struct {
   701  	seed   PerUserKeySeed
   702  	sigKey *NaclSigningKeyPair
   703  	encKey *NaclDHKeyPair
   704  	// Key used to decrypt the secretbox of the previous generation
   705  	prevKey NaclSecretBoxKey
   706  }
   707  
   708  func (k *importedPerUserKey) lower() perUserKeyFull {
   709  	return perUserKeyFull{
   710  		seed:   k.seed,
   711  		sigKey: k.sigKey,
   712  		encKey: k.encKey,
   713  	}
   714  }
   715  
   716  // Decrypt, expand, and check a per-user-key from a Box.
   717  func importPerUserKeyBox(box *keybase1.PerUserKeyBox, decryptionKey GenericKey,
   718  	wantedGeneration keybase1.PerUserKeyGeneration, checker *perUserKeyChecker) (*importedPerUserKey, error) {
   719  	if box == nil {
   720  		return nil, NewPerUserKeyImportError("per-user-key box nil")
   721  	}
   722  	if box.Generation != wantedGeneration {
   723  		return nil, NewPerUserKeyImportError("bad generation returned: %d", box.Generation)
   724  	}
   725  	if !decryptionKey.GetKID().Equal(box.ReceiverKID) {
   726  		return nil, NewPerUserKeyImportError("wrong encryption kid: %s", box.ReceiverKID.String())
   727  	}
   728  	rawKey, encryptingKID, err := decryptionKey.DecryptFromString(box.Box)
   729  	if err != nil {
   730  		return nil, err
   731  	}
   732  	if len(checker.allowedEncryptingKIDs) == 0 {
   733  		return nil, NewPerUserKeyImportError("no allowed encrypting kids")
   734  	}
   735  	if !checker.allowedEncryptingKIDs[encryptingKID] {
   736  		return nil, NewPerUserKeyImportError("unexpected encrypting kid: %s", encryptingKID)
   737  	}
   738  	seed, err := MakeByte32Soft(rawKey)
   739  	if err != nil {
   740  		return nil, NewPerUserKeyImportError("%s", err)
   741  	}
   742  	imp, err := expandPerUserKey(seed)
   743  	if err != nil {
   744  		return nil, NewPerUserKeyImportError("%s", err)
   745  	}
   746  	err = checker.checkPublic(imp, wantedGeneration)
   747  	if err != nil {
   748  		return nil, err
   749  	}
   750  	return &imp, nil
   751  }
   752  
   753  // Decrypt, expand, and check a per-user-key from a SecretBox.
   754  func importPerUserKeyPrev(generation keybase1.PerUserKeyGeneration, prev perUserKeyPrevResp, decryptionKey NaclSecretBoxKey,
   755  	wantedGeneration keybase1.PerUserKeyGeneration, checker *perUserKeyChecker) (*importedPerUserKey, error) {
   756  
   757  	if generation != prev.Generation {
   758  		return nil, fmt.Errorf("import per-user-key mismatched generation: %v != %v",
   759  			generation, prev.Generation)
   760  	}
   761  
   762  	seed, err := openPerUserKeyPrev(prev.Ctext, decryptionKey)
   763  	if err != nil {
   764  		return nil, err
   765  	}
   766  
   767  	imp, err := expandPerUserKey(seed)
   768  	if err != nil {
   769  		return nil, err
   770  	}
   771  
   772  	err = checker.checkPublic(imp, generation)
   773  	if err != nil {
   774  		return nil, err
   775  	}
   776  
   777  	return &imp, nil
   778  }
   779  
   780  func expandPerUserKey(seed PerUserKeySeed) (res importedPerUserKey, err error) {
   781  	sigKey, err := seed.DeriveSigningKey()
   782  	if err != nil {
   783  		return res, err
   784  	}
   785  	encKey, err := seed.DeriveDHKey()
   786  	if err != nil {
   787  		return res, err
   788  	}
   789  	prevKey, err := seed.derivePrevKey()
   790  	if err != nil {
   791  		return res, err
   792  	}
   793  	return importedPerUserKey{
   794  		seed:    seed,
   795  		sigKey:  sigKey,
   796  		encKey:  encKey,
   797  		prevKey: prevKey,
   798  	}, nil
   799  }