github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/skb.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  //
     7  // Code for encoding and decoding SKB-formatted keys. Also works for decoding
     8  // general Keybase Packet types, but we only have SKB at present.
     9  //
    10  // SKB = "Secret Key Bundle", which contains an unencrypted public key and
    11  // and encrypted secret key.
    12  //
    13  
    14  import (
    15  	"bytes"
    16  	"errors"
    17  	"fmt"
    18  	"io"
    19  	"os"
    20  	"sync"
    21  
    22  	"github.com/keybase/client/go/kbcrypto"
    23  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    24  	triplesec "github.com/keybase/go-triplesec"
    25  )
    26  
    27  // DebugDumpKey is used only in debugging. For now it's not in
    28  // use but we might need it in the future.
    29  func DebugDumpKey(g *GlobalContext, name string, b []byte) {
    30  	tmp, err := os.CreateTemp(os.TempDir(), "dump-"+name)
    31  	if err != nil {
    32  		g.Log.Warning("Failed to dumpKey %s: %s", name, err)
    33  		return
    34  	}
    35  	g.Log.Notice("DUMPKEY %s -> %s", name, tmp.Name())
    36  	buf := bytes.NewBuffer(b)
    37  	_, _ = io.Copy(tmp, buf)
    38  	tmp.Close()
    39  }
    40  
    41  type SKB struct {
    42  	Priv SKBPriv           `codec:"priv"`
    43  	Pub  []byte            `codec:"pub"`
    44  	Type kbcrypto.AlgoType `codec:"type,omitempty"`
    45  
    46  	decodedPub      GenericKey
    47  	decryptedSecret GenericKey
    48  	decryptedRaw    []byte // in case we need to reexport it
    49  
    50  	uid keybase1.UID // UID that the key is for
    51  	Contextified
    52  
    53  	// TODO(akalin): Remove this in favor of making LKSec
    54  	// Contextified (see
    55  	// https://github.com/keybase/client/issues/329 ).
    56  	newLKSecForTest func(clientHalf LKSecClientHalf) *LKSec
    57  
    58  	sync.Mutex // currently only for uid
    59  }
    60  
    61  func NewSKB() *SKB {
    62  	return &SKB{}
    63  }
    64  
    65  func NewSKBWithGlobalContext(g *GlobalContext) *SKB {
    66  	return &SKB{Contextified: NewContextified(g)}
    67  }
    68  
    69  type SKBPriv struct {
    70  	Data                 []byte `codec:"data"`
    71  	Encryption           int    `codec:"encryption"`
    72  	PassphraseGeneration int    `codec:"passphrase_generation,omitempty"`
    73  }
    74  
    75  func ToServerSKB(gc *GlobalContext, key GenericKey, tsec Triplesec, gen PassphraseGeneration) (ret *SKB, err error) {
    76  	if pgp, ok := key.(*PGPKeyBundle); ok {
    77  		return pgp.ToServerSKB(gc, tsec, gen)
    78  	}
    79  	return nil, errors.New("Only PGP keys can be encrypted for server sync")
    80  }
    81  
    82  func (key *PGPKeyBundle) ToServerSKB(gc *GlobalContext, tsec Triplesec, gen PassphraseGeneration) (ret *SKB, err error) {
    83  
    84  	ret = NewSKBWithGlobalContext(gc)
    85  
    86  	var pk, sk bytes.Buffer
    87  
    88  	// Need to serialize Private first, because
    89  	err = key.SerializePrivate(&sk)
    90  	if err != nil {
    91  		return
    92  	}
    93  	if tsec != nil {
    94  		ret.Priv.Data, err = tsec.Encrypt(sk.Bytes())
    95  		ret.Priv.Encryption = int(ClientTriplesecVersion)
    96  		if err != nil {
    97  			return
    98  		}
    99  	} else {
   100  		ret.Priv.Data = sk.Bytes()
   101  		ret.Priv.Encryption = 0
   102  	}
   103  
   104  	ret.Priv.PassphraseGeneration = int(gen)
   105  
   106  	err = key.Entity.Serialize(&pk)
   107  	if err != nil {
   108  		return
   109  	}
   110  	ret.Pub = pk.Bytes()
   111  	ret.Type = key.GetAlgoType()
   112  
   113  	return
   114  }
   115  
   116  func (s *SKB) Dump() {
   117  	if s == nil {
   118  		return
   119  	}
   120  	s.G().Log.Debug("skb: %+v, uid = %s\n", s, s.uid)
   121  }
   122  
   123  func (s *SKB) newLKSec(pps *PassphraseStream) *LKSec {
   124  	if s.newLKSecForTest != nil {
   125  		return s.newLKSecForTest(pps.LksClientHalf())
   126  	}
   127  	if s.uid.IsNil() {
   128  		panic("no uid set in skb")
   129  	}
   130  	return NewLKSec(pps, s.uid)
   131  }
   132  
   133  func (s *SKB) GetTagAndVersion() (kbcrypto.PacketTag, kbcrypto.PacketVersion) {
   134  	return kbcrypto.TagP3skb, kbcrypto.KeybasePacketV1
   135  }
   136  
   137  func (s *SKB) ReadKey() (g GenericKey, err error) {
   138  	switch {
   139  	case IsPGPAlgo(s.Type):
   140  		var w *Warnings
   141  		g, w, err = ReadOneKeyFromBytes(s.Pub)
   142  		w.Warn(s.G())
   143  	case s.Type == kbcrypto.KIDNaclEddsa:
   144  		g, err = ImportNaclSigningKeyPairFromBytes(s.Pub, nil)
   145  	case s.Type == kbcrypto.KIDNaclDH:
   146  		g, err = ImportNaclDHKeyPairFromBytes(s.Pub, nil)
   147  	default:
   148  		err = UnknownKeyTypeError{s.Type}
   149  	}
   150  	return
   151  }
   152  
   153  func (s *SKB) GetPubKey() (key GenericKey, err error) {
   154  	if key = s.decodedPub; key == nil {
   155  		key, err = s.ReadKey()
   156  		s.decodedPub = key
   157  	}
   158  	return
   159  }
   160  
   161  func (s *SKB) VerboseDescription() (ret string, err error) {
   162  	var key GenericKey
   163  	key, err = s.GetPubKey()
   164  	if err == nil && key != nil {
   165  		ret = key.VerboseDescription()
   166  	}
   167  	return
   168  }
   169  
   170  func (s *SKB) HumanDescription(owner *User) (string, error) {
   171  	key, err := s.GetPubKey()
   172  	if err != nil {
   173  		return "", err
   174  	}
   175  
   176  	if IsPGPAlgo(s.Type) {
   177  		return s.pgpHumanDescription(key)
   178  	}
   179  	return s.devHumandDescription(owner, key)
   180  }
   181  
   182  func (s *SKB) pgpHumanDescription(key GenericKey) (string, error) {
   183  	pgpKey, ok := key.(*PGPKeyBundle)
   184  	if !ok {
   185  		return "", kbcrypto.BadKeyError{Msg: "not pgp key despite skb algo type"}
   186  	}
   187  
   188  	return pgpKey.HumanDescription(), nil
   189  }
   190  
   191  func (s *SKB) devHumandDescription(owner *User, key GenericKey) (string, error) {
   192  	ckf := owner.GetComputedKeyFamily()
   193  	device, err := ckf.GetDeviceForKey(key)
   194  	if err != nil {
   195  		return "", err
   196  	}
   197  	if device == nil {
   198  		return "", NoDeviceError{Reason: fmt.Sprintf("for key ID %s", key.GetKID())}
   199  	}
   200  	if device.Description == nil {
   201  		return "", fmt.Errorf("no device description")
   202  	}
   203  	return fmt.Sprintf("Device %q", *device.Description), nil
   204  }
   205  
   206  func (s *SKB) RawUnlockedKey() []byte {
   207  	return s.decryptedRaw
   208  }
   209  
   210  func (s *SKB) unlockSecretKeyFromSecretRetriever(m MetaContext, secretRetriever SecretRetriever) (key GenericKey, err error) {
   211  	defer m.Trace("SKB#unlockSecretKeyFromSecretRetriever", &err)()
   212  	if key = s.decryptedSecret; key != nil {
   213  		return
   214  	}
   215  
   216  	var unlocked []byte
   217  	switch s.Priv.Encryption {
   218  	case 0:
   219  		unlocked = s.Priv.Data
   220  	case LKSecVersion:
   221  		unlocked, err = s.lksUnlockWithSecretRetriever(m, secretRetriever)
   222  	default:
   223  		err = kbcrypto.BadKeyError{Msg: fmt.Sprintf("Can't unlock secret from secret retriever with protection type %d", s.Priv.Encryption)}
   224  	}
   225  
   226  	if err == nil {
   227  		key, err = s.parseUnlocked(unlocked)
   228  	}
   229  	return
   230  }
   231  
   232  func (s *SKB) UnlockSecretKey(m MetaContext, passphrase string, tsec Triplesec, pps *PassphraseStream, secretStorer SecretStorer) (key GenericKey, err error) {
   233  	defer m.Trace("SKB#UnlockSecretKey", &err)()
   234  	if key = s.decryptedSecret; key != nil {
   235  		return key, nil
   236  	}
   237  	var unlocked []byte
   238  
   239  	switch {
   240  	case s.Priv.Encryption == 0:
   241  		m.Debug("case: Unlocked")
   242  		unlocked = s.Priv.Data
   243  	case s.Priv.Encryption > 0 && s.Priv.Encryption < LKSecVersion:
   244  		m.Debug("case: Triplesec")
   245  		tsecIn := tsec
   246  		if tsec == nil {
   247  			tsec, err = s.G().NewTriplesec([]byte(passphrase), nil)
   248  			if err != nil {
   249  				return nil, err
   250  			}
   251  		}
   252  		unlocked, err = s.tsecUnlock(tsec)
   253  		if err != nil {
   254  			return nil, err
   255  		}
   256  		if tsecIn == nil {
   257  			m.Debug("Caching passphrase stream: tsec=%v, pps=%v", (tsec != nil), (pps != nil))
   258  			m.ActiveDevice().CachePassphraseStream(NewPassphraseStreamCache(tsec, pps))
   259  		}
   260  	case s.Priv.Encryption == LKSecVersion:
   261  		m.Debug("case: LKSec")
   262  		ppsIn := pps
   263  		if pps == nil {
   264  			tsec, pps, err = UnverifiedPassphraseStream(m, s.uid, passphrase)
   265  			if err != nil {
   266  				return nil, fmt.Errorf("UnlockSecretKey: %s", err)
   267  			}
   268  		}
   269  		unlocked, err = s.lksUnlock(m, pps, secretStorer)
   270  		if err != nil {
   271  			return nil, err
   272  		}
   273  		if ppsIn == nil {
   274  			m.Debug("Caching passphrase stream: tsec=%v, pps=%v", (tsec != nil), (pps != nil))
   275  			m.ActiveDevice().CachePassphraseStream(NewPassphraseStreamCache(tsec, pps))
   276  		}
   277  	default:
   278  		err = kbcrypto.BadKeyError{Msg: fmt.Sprintf("Can't unlock secret with protection type %d", s.Priv.Encryption)}
   279  		return nil, err
   280  	}
   281  	key, err = s.parseUnlocked(unlocked)
   282  	return key, err
   283  }
   284  
   285  func (s *SKB) parseUnlocked(unlocked []byte) (key GenericKey, err error) {
   286  
   287  	switch {
   288  	case IsPGPAlgo(s.Type):
   289  		var w *Warnings
   290  		key, w, err = ReadOneKeyFromBytes(unlocked)
   291  		w.Warn(s.G())
   292  	case s.Type == kbcrypto.KIDNaclEddsa:
   293  		key, err = ImportNaclSigningKeyPairFromBytes(s.Pub, unlocked)
   294  	case s.Type == kbcrypto.KIDNaclDH:
   295  		key, err = ImportNaclDHKeyPairFromBytes(s.Pub, unlocked)
   296  	}
   297  
   298  	if key == nil {
   299  		err = kbcrypto.BadKeyError{Msg: "can't parse secret key after unlock"}
   300  	}
   301  	if err != nil {
   302  		return
   303  	}
   304  
   305  	if err = key.CheckSecretKey(); err == nil {
   306  		s.decryptedRaw = unlocked
   307  		s.decryptedSecret = key
   308  	}
   309  	return
   310  }
   311  
   312  func (s *SKB) tsecUnlock(tsec Triplesec) ([]byte, error) {
   313  	unlocked, err := tsec.Decrypt(s.Priv.Data)
   314  	if err != nil {
   315  		if _, ok := err.(triplesec.BadPassphraseError); ok {
   316  			err = PassphraseError{}
   317  		}
   318  		return nil, err
   319  	}
   320  	return unlocked, nil
   321  }
   322  
   323  func (s *SKB) lksUnlock(m MetaContext, pps *PassphraseStream, secretStorer SecretStorer) (unlocked []byte, err error) {
   324  	defer m.Trace("SKB#lksUnlock", &err)()
   325  	m.Debug("| creating new lks")
   326  
   327  	lks := s.newLKSec(pps)
   328  	s.Lock()
   329  	m.Debug("| setting uid in lks to %s", s.uid)
   330  	lks.SetUID(s.uid)
   331  	s.Unlock()
   332  	var ppGen PassphraseGeneration
   333  	unlocked, ppGen, _, err = lks.Decrypt(m, s.Priv.Data)
   334  	if err != nil {
   335  		return
   336  	}
   337  	pps.SetGeneration(ppGen)
   338  
   339  	if secretStorer != nil {
   340  		var secret LKSecFullSecret
   341  		secret, err = lks.GetSecret(m)
   342  		if err != nil {
   343  			unlocked = nil
   344  			return
   345  		}
   346  		// Ignore any errors storing the secret.
   347  		storeSecretErr := secretStorer.StoreSecret(m, secret)
   348  		if storeSecretErr != nil {
   349  			m.Warning("StoreSecret error: %s", storeSecretErr)
   350  		}
   351  	}
   352  
   353  	return
   354  }
   355  
   356  func (s *SKB) lksUnlockWithSecretRetriever(m MetaContext, secretRetriever SecretRetriever) (unlocked []byte, err error) {
   357  	defer m.Trace("SKB#lksUnlockWithSecretRetriever", &err)()
   358  	secret, err := secretRetriever.RetrieveSecret(m)
   359  	if err != nil {
   360  		return
   361  	}
   362  	if s.uid.IsNil() {
   363  		panic("no uid set in skb")
   364  	}
   365  	lks := NewLKSecWithFullSecret(secret, s.uid)
   366  	unlocked, _, _, err = lks.Decrypt(m, s.Priv.Data)
   367  	if err != nil {
   368  		m.Debug("SKB#lksUnlockWithSecretRetriever: failed in lks.Decrypt with uid %q", s.uid)
   369  	}
   370  
   371  	return
   372  }
   373  
   374  func (s *SKB) SetUID(uid keybase1.UID) {
   375  	s.G().Log.Debug("| Setting UID on SKB to %s", uid)
   376  	s.Lock()
   377  	s.uid = uid
   378  	s.Unlock()
   379  }
   380  
   381  func (s *SKB) ArmoredEncode() (ret string, err error) {
   382  	return kbcrypto.EncodePacketToArmoredString(s)
   383  }
   384  
   385  func (s *SKB) UnlockWithStoredSecret(m MetaContext, secretRetriever SecretRetriever) (ret GenericKey, err error) {
   386  	defer m.Trace("SKB#UnlockWithStoredSecret()", &err)()
   387  	if ret = s.decryptedSecret; ret != nil {
   388  		return
   389  	}
   390  	return s.unlockSecretKeyFromSecretRetriever(m, secretRetriever)
   391  }
   392  
   393  var ErrUnlockNotPossible = errors.New("unlock not possible")
   394  
   395  func (s *SKB) UnlockNoPrompt(m MetaContext, secretStore SecretStore) (ret GenericKey, err error) {
   396  	defer m.Trace("SKB#UnlockNoPrompt", &err)()
   397  	// already have decrypted secret?
   398  	if s.decryptedSecret != nil {
   399  		return s.decryptedSecret, nil
   400  	}
   401  
   402  	// try using the secret store:
   403  	if secretStore != nil {
   404  		key, err := s.unlockSecretKeyFromSecretRetriever(m, secretStore)
   405  		m.Debug("| unlockSecretKeyFromSecretRetriever -> %s", ErrToOk(err))
   406  		if err == nil {
   407  			return key, nil
   408  		}
   409  		// fall through if we failed to unlock with retrieved secret...
   410  	}
   411  
   412  	// try using the passphrase stream cache
   413  	pps, tsec := m.PassphraseStreamAndTriplesec()
   414  	if tsec != nil || pps != nil {
   415  		key, err := s.UnlockSecretKey(m, "", tsec, pps, nil)
   416  		if err == nil {
   417  			m.Debug("| Unlocked key with cached 3Sec and passphrase stream")
   418  			return key, nil
   419  		}
   420  		if _, ok := err.(PassphraseError); !ok {
   421  			// not a passphrase error
   422  			return nil, err
   423  		}
   424  		// fall through if it's a passphrase error
   425  	} else {
   426  		m.Debug("| No 3Sec or PassphraseStream in UnlockNoPrompt")
   427  	}
   428  
   429  	// failed to unlock without prompting user for passphrase
   430  	return nil, ErrUnlockNotPossible
   431  }
   432  
   433  func (s *SKB) unlockPrompt(m MetaContext, arg SecretKeyPromptArg, secretStore SecretStore, me *User) (ret GenericKey, err error) {
   434  	defer m.Trace("SKB#unlockPrompt", &err)()
   435  
   436  	// check to see if user has recently canceled an unlock prompt:
   437  	// if lctx != nil, then don't bother as any prompts during login should be shown.
   438  	if m.LoginContext() == nil && arg.UseCancelCache && m.ActiveDevice().SecretPromptCancelTimer().WasRecentlyCanceled(m) {
   439  		m.Debug("prompt was recently canceled; skipping")
   440  		return nil, SkipSecretPromptError{}
   441  	}
   442  
   443  	desc, err := s.HumanDescription(me)
   444  	if err != nil {
   445  		return nil, err
   446  	}
   447  
   448  	unlocker := func(pw string, storeSecret bool) (ret GenericKey, err error) {
   449  		var secretStorer SecretStorer
   450  		if storeSecret {
   451  			secretStorer = secretStore
   452  		}
   453  		return s.UnlockSecretKey(m, pw, nil, nil, secretStorer)
   454  	}
   455  
   456  	keyUnlocker := NewKeyUnlocker(4, arg.Reason, desc, PassphraseTypeKeybase, (secretStore != nil), arg.SecretUI, unlocker)
   457  
   458  	ret, err = keyUnlocker.Run(m)
   459  	if err != nil {
   460  		if _, ok := err.(InputCanceledError); ok && arg.UseCancelCache {
   461  			// cache the cancel response in the account
   462  			m.ActiveDevice().SecretPromptCancelTimer().SetNow(m)
   463  		}
   464  		return nil, err
   465  	}
   466  	return ret, nil
   467  }
   468  
   469  func (s *SKB) PromptAndUnlock(m MetaContext, arg SecretKeyPromptArg, secretStore SecretStore, me *User) (ret GenericKey, err error) {
   470  	defer m.Trace(fmt.Sprintf("SKB#PromptAndUnlock(%s)", arg.Reason), &err)()
   471  
   472  	// First try to unlock without prompting the user.
   473  	ret, err = s.UnlockNoPrompt(m, secretStore)
   474  	if err == nil {
   475  		return ret, nil
   476  	}
   477  	if err != ErrUnlockNotPossible {
   478  		return nil, err
   479  	}
   480  
   481  	// Prompt necessary:
   482  	ret, err = s.unlockPrompt(m, arg, secretStore, me)
   483  	return
   484  }