github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/pgp_encrypt.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 engine
     5  
     6  import (
     7  	"errors"
     8  	"io"
     9  
    10  	"github.com/keybase/client/go/libkb"
    11  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/keybase/go-crypto/openpgp/armor"
    13  )
    14  
    15  type PGPEncryptArg struct {
    16  	Recips       []string // user assertions
    17  	Source       io.Reader
    18  	Sink         io.WriteCloser
    19  	NoSign       bool
    20  	NoSelf       bool
    21  	BinaryOutput bool
    22  	KeyQuery     string
    23  }
    24  
    25  // PGPEncrypt encrypts data read from a source into a sink
    26  // for a set of users.  It will track them if necessary.
    27  type PGPEncrypt struct {
    28  	arg      *PGPEncryptArg
    29  	me       *libkb.User
    30  	warnings libkb.HashSecurityWarnings
    31  	libkb.Contextified
    32  }
    33  
    34  // NewPGPEncrypt creates a PGPEncrypt engine.
    35  func NewPGPEncrypt(g *libkb.GlobalContext, arg *PGPEncryptArg) *PGPEncrypt {
    36  	return &PGPEncrypt{
    37  		arg:          arg,
    38  		Contextified: libkb.NewContextified(g),
    39  	}
    40  }
    41  
    42  // Name is the unique engine name.
    43  func (e *PGPEncrypt) Name() string {
    44  	return "PGPEncrypt"
    45  }
    46  
    47  // GetPrereqs returns the engine prereqs.
    48  func (e *PGPEncrypt) Prereqs() Prereqs {
    49  	return Prereqs{}
    50  }
    51  
    52  // RequiredUIs returns the required UIs.
    53  func (e *PGPEncrypt) RequiredUIs() []libkb.UIKind {
    54  	// context.SecretKeyPromptArg requires SecretUI
    55  	return []libkb.UIKind{
    56  		libkb.SecretUIKind,
    57  		libkb.PgpUIKind,
    58  	}
    59  }
    60  
    61  // SubConsumers returns the other UI consumers for this engine.
    62  func (e *PGPEncrypt) SubConsumers() []libkb.UIConsumer {
    63  	return []libkb.UIConsumer{
    64  		&PGPKeyfinder{},
    65  		&ResolveThenIdentify2{},
    66  	}
    67  }
    68  
    69  // Run starts the engine.
    70  func (e *PGPEncrypt) Run(m libkb.MetaContext) error {
    71  	// verify valid options based on logged in state:
    72  	ok, uid := isLoggedIn(m)
    73  
    74  	if !ok {
    75  		// not logged in.  this is fine, unless they requested signing the message.
    76  		if !e.arg.NoSign {
    77  			return libkb.LoginRequiredError{Context: "you must be logged in to sign"}
    78  		}
    79  
    80  		// or trying to encrypt for self
    81  		if !e.arg.NoSelf {
    82  			return libkb.LoginRequiredError{Context: "you must be logged in to encrypt for yourself (or use --no-self flag)"}
    83  		}
    84  	} else {
    85  		me, err := libkb.LoadMeByMetaContextAndUID(m, uid)
    86  		if err != nil {
    87  			return err
    88  		}
    89  		e.me = me
    90  	}
    91  
    92  	var mykey *libkb.PGPKeyBundle
    93  	var signer *libkb.PGPKeyBundle
    94  	if !e.arg.NoSign {
    95  		ska := libkb.SecretKeyArg{
    96  			Me:       e.me,
    97  			KeyType:  libkb.PGPKeyType,
    98  			KeyQuery: e.arg.KeyQuery,
    99  		}
   100  		key, err := e.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(ska, "command-line signature"))
   101  		if err != nil {
   102  			return err
   103  		}
   104  
   105  		var ok bool
   106  		mykey, ok = key.(*libkb.PGPKeyBundle)
   107  		if !ok {
   108  			return errors.New("Can only sign with PGP keys")
   109  		}
   110  		signer = mykey
   111  	}
   112  
   113  	usernames, err := e.verifyUsers(m, e.arg.Recips, ok)
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	kfarg := &PGPKeyfinderArg{
   119  		Usernames: usernames,
   120  	}
   121  
   122  	kf := NewPGPKeyfinder(e.G(), kfarg)
   123  	if err := RunEngine2(m, kf); err != nil {
   124  		return err
   125  	}
   126  	uplus := kf.UsersPlusKeys()
   127  
   128  	var writer io.WriteCloser
   129  	if e.arg.BinaryOutput {
   130  		writer = e.arg.Sink
   131  	} else {
   132  		aw, err := armor.Encode(e.arg.Sink, "PGP MESSAGE", libkb.PGPArmorHeaders)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		writer = aw
   137  	}
   138  
   139  	ks := newKeyset()
   140  	e.warnings = libkb.HashSecurityWarnings{}
   141  
   142  	if mykey != nil {
   143  		if w := mykey.SecurityWarnings(
   144  			libkb.HashSecurityWarningOurIdentityHash,
   145  		); len(w) > 0 {
   146  			e.warnings = append(e.warnings, w...)
   147  		}
   148  	}
   149  
   150  	for _, up := range uplus {
   151  		for _, k := range up.Keys {
   152  			if len(k.Entity.Revocations)+len(k.Entity.UnverifiedRevocations) > 0 {
   153  				continue
   154  			}
   155  
   156  			if w := k.SecurityWarnings(
   157  				libkb.HashSecurityWarningRecipientsIdentityHash,
   158  			); len(w) > 0 {
   159  				e.warnings = append(e.warnings, w...)
   160  			}
   161  
   162  			ks.Add(k)
   163  		}
   164  	}
   165  
   166  	if len(e.arg.Recips) > 0 && len(ks.keys) == 0 {
   167  		return errors.New("Cannot encrypt - recipient does not have a non-revoked key.")
   168  	}
   169  
   170  	if !e.arg.NoSelf {
   171  		if mykey == nil {
   172  			// need to load the public key for the logged in user
   173  			mykey, err = e.loadSelfKey()
   174  			if err != nil {
   175  				return err
   176  			}
   177  		}
   178  
   179  		// mykey could still be nil
   180  		if mykey != nil {
   181  			ks.Add(mykey)
   182  		}
   183  	}
   184  
   185  	for _, warning := range e.warnings.Strings() {
   186  		if err := m.UIs().PgpUI.OutputPGPWarning(m.Ctx(), keybase1.OutputPGPWarningArg{
   187  			Warning: warning,
   188  		}); err != nil {
   189  			return err
   190  		}
   191  	}
   192  
   193  	recipients := ks.Sorted()
   194  	if err := libkb.PGPEncrypt(e.arg.Source, writer, signer, recipients); err != nil {
   195  		return err
   196  	}
   197  	if !e.arg.BinaryOutput {
   198  		return e.arg.Sink.Close()
   199  	}
   200  	return nil
   201  }
   202  
   203  func (e *PGPEncrypt) loadSelfKey() (*libkb.PGPKeyBundle, error) {
   204  	me, err := libkb.LoadMe(libkb.NewLoadUserArg(e.G()))
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	keys := me.FilterActivePGPKeys(true, e.arg.KeyQuery)
   210  	if len(keys) == 0 {
   211  		return nil, libkb.NoKeyError{Msg: "No PGP key found for encrypting for self (add a PGP key or use --no-self flag)"}
   212  	}
   213  	return keys[0], nil
   214  }
   215  
   216  func (e *PGPEncrypt) verifyUsers(m libkb.MetaContext, assertions []string, loggedIn bool) ([]string, error) {
   217  	var names []string
   218  	for _, userAssert := range assertions {
   219  		arg := keybase1.Identify2Arg{
   220  			UserAssertion: userAssert,
   221  			Reason: keybase1.IdentifyReason{
   222  				Type: keybase1.IdentifyReasonType_ENCRYPT,
   223  			},
   224  			AlwaysBlock:      true,
   225  			IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   226  		}
   227  		eng := NewResolveThenIdentify2(e.G(), &arg)
   228  		if err := RunEngine2(m, eng); err != nil {
   229  			return nil, libkb.IdentifyFailedError{Assertion: userAssert, Reason: err.Error()}
   230  		}
   231  		res, err := eng.Result(m)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		names = append(names, res.Upk.GetName())
   236  	}
   237  	return names, nil
   238  }
   239  
   240  // keyset maintains a set of pgp keys, preserving insertion order.
   241  type keyset struct {
   242  	index []keybase1.KID
   243  	keys  map[keybase1.KID]*libkb.PGPKeyBundle
   244  }
   245  
   246  // newKeyset creates an empty keyset.
   247  func newKeyset() *keyset {
   248  	return &keyset{keys: make(map[keybase1.KID]*libkb.PGPKeyBundle)}
   249  }
   250  
   251  // Add adds bundle to the keyset.  If a key already exists, it
   252  // will be ignored.
   253  func (k *keyset) Add(bundle *libkb.PGPKeyBundle) {
   254  	kid := bundle.GetKID()
   255  	if _, ok := k.keys[kid]; ok {
   256  		return
   257  	}
   258  	k.keys[kid] = bundle
   259  	k.index = append(k.index, kid)
   260  }
   261  
   262  // Sorted returns the unique keys in insertion order.
   263  func (k *keyset) Sorted() []*libkb.PGPKeyBundle {
   264  	var sorted []*libkb.PGPKeyBundle
   265  	for _, kid := range k.index {
   266  		sorted = append(sorted, k.keys[kid])
   267  	}
   268  	return sorted
   269  }