github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/saltpack_encrypt_test.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  	"fmt"
     8  	"strings"
     9  	"testing"
    10  
    11  	"golang.org/x/net/context"
    12  
    13  	"github.com/keybase/client/go/libkb"
    14  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    15  	"github.com/keybase/client/go/saltpackkeystest"
    16  	"github.com/keybase/go-codec/codec"
    17  	"github.com/keybase/saltpack"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  type fakeSaltpackUI2 struct {
    22  	DidDecrypt bool
    23  	LastSender keybase1.SaltpackSender
    24  }
    25  
    26  func (s *fakeSaltpackUI2) SaltpackPromptForDecrypt(_ context.Context, arg keybase1.SaltpackPromptForDecryptArg, usedDelegateUI bool) (err error) {
    27  	s.DidDecrypt = true
    28  	s.LastSender = arg.Sender
    29  	return nil
    30  }
    31  
    32  func (s *fakeSaltpackUI2) SaltpackVerifySuccess(_ context.Context, arg keybase1.SaltpackVerifySuccessArg) error {
    33  	return nil
    34  }
    35  
    36  func (s *fakeSaltpackUI2) SaltpackVerifyBadSender(_ context.Context, arg keybase1.SaltpackVerifyBadSenderArg) error {
    37  	return fmt.Errorf("fakeSaltpackUI2 SaltpackVerifyBadSender error: %s", arg.Sender.SenderType.String())
    38  }
    39  
    40  func TestSaltpackEncrypt(t *testing.T) {
    41  	tc := SetupEngineTest(t, "SaltpackEncrypt")
    42  	defer tc.Cleanup()
    43  
    44  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
    45  	u2 := CreateAndSignupFakeUser(tc, "nalcp")
    46  	u3 := CreateAndSignupFakeUser(tc, "nalcp")
    47  
    48  	trackUI := &FakeIdentifyUI{
    49  		Proofs: make(map[string]string),
    50  	}
    51  	uis := libkb.UIs{IdentifyUI: trackUI, SecretUI: u3.NewSecretUI()}
    52  
    53  	run := func(Recips []string) {
    54  		sink := libkb.NewBufferCloser()
    55  		arg := &SaltpackEncryptArg{
    56  			Opts: keybase1.SaltpackEncryptOptions{
    57  				Recipients:    Recips,
    58  				UseEntityKeys: true,
    59  			},
    60  			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
    61  			Sink:   sink,
    62  		}
    63  
    64  		eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
    65  		m := NewMetaContextForTest(tc).WithUIs(uis)
    66  		if err := RunEngine2(m, eng); err != nil {
    67  			t.Fatal(err)
    68  		}
    69  
    70  		out := sink.Bytes()
    71  		if len(out) == 0 {
    72  			t.Fatal("no output")
    73  		}
    74  	}
    75  	run([]string{u1.Username, u2.Username})
    76  
    77  	// If we add ourselves, we should be smart and not error out
    78  	// (We are u3 in this case)
    79  	run([]string{u1.Username, u2.Username, u3.Username})
    80  }
    81  
    82  // This is now the default behavior. Still good to test it though. Note that
    83  // this flag is only meaningful in repudiable mode.
    84  func TestSaltpackEncryptHideRecipients(t *testing.T) {
    85  	tc := SetupEngineTest(t, "SaltpackEncrypt")
    86  	defer tc.Cleanup()
    87  
    88  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
    89  	u2 := CreateAndSignupFakeUser(tc, "nalcp")
    90  	u3 := CreateAndSignupFakeUser(tc, "nalcp")
    91  
    92  	trackUI := &FakeIdentifyUI{
    93  		Proofs: make(map[string]string),
    94  	}
    95  	uis := libkb.UIs{IdentifyUI: trackUI, SecretUI: u3.NewSecretUI()}
    96  
    97  	run := func(Recips []string) {
    98  		sink := libkb.NewBufferCloser()
    99  		arg := &SaltpackEncryptArg{
   100  			Opts: keybase1.SaltpackEncryptOptions{
   101  				UseEntityKeys: true,
   102  				// There used to be a HideRecipients flag here, but this is now
   103  				// the default for encryption.
   104  				// (It's not really meaningful for signcryption mode, where the
   105  				// recipients are always opaque.)
   106  				AuthenticityType: keybase1.AuthenticityType_REPUDIABLE,
   107  				Recipients:       Recips,
   108  				Binary:           true,
   109  			},
   110  			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
   111  			Sink:   sink,
   112  		}
   113  
   114  		eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   115  		m := NewMetaContextForTest(tc).WithUIs(uis)
   116  		if err := RunEngine2(m, eng); err != nil {
   117  			t.Fatal(err)
   118  		}
   119  
   120  		out := sink.Bytes()
   121  		if len(out) == 0 {
   122  			t.Fatal("no output")
   123  		}
   124  
   125  		var header saltpack.EncryptionHeader
   126  		dec := codec.NewDecoderBytes(out, &codec.MsgpackHandle{WriteExt: true})
   127  		var b []byte
   128  		if err := dec.Decode(&b); err != nil {
   129  			t.Fatal(err)
   130  		}
   131  		dec = codec.NewDecoderBytes(b, &codec.MsgpackHandle{WriteExt: true})
   132  		if err := dec.Decode(&header); err != nil {
   133  			t.Fatal(err)
   134  		}
   135  
   136  		for _, receiver := range header.Receivers {
   137  			if receiver.ReceiverKID != nil {
   138  				t.Fatal("receiver KID included in anonymous saltpack header")
   139  			}
   140  		}
   141  
   142  	}
   143  	run([]string{u1.Username, u2.Username})
   144  
   145  	// If we add ourselves, we should be smart and not error out
   146  	// (We are u3 in this case)
   147  	run([]string{u1.Username, u2.Username, u3.Username})
   148  }
   149  
   150  func TestSaltpackEncryptAnonymousSigncryption(t *testing.T) {
   151  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   152  	defer tc.Cleanup()
   153  
   154  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
   155  	u2 := CreateAndSignupFakeUser(tc, "nalcp")
   156  	u3 := CreateAndSignupFakeUser(tc, "nalcp")
   157  
   158  	trackUI := &FakeIdentifyUI{
   159  		Proofs: make(map[string]string),
   160  	}
   161  	saltpackUI := &fakeSaltpackUI2{}
   162  	uis := libkb.UIs{
   163  		IdentifyUI: trackUI,
   164  		SecretUI:   u3.NewSecretUI(),
   165  		SaltpackUI: saltpackUI,
   166  	}
   167  
   168  	run := func(Recips []string) {
   169  		encsink := libkb.NewBufferCloser()
   170  		encarg := &SaltpackEncryptArg{
   171  			Opts: keybase1.SaltpackEncryptOptions{
   172  				UseEntityKeys:    true,
   173  				Recipients:       Recips,
   174  				AuthenticityType: keybase1.AuthenticityType_ANONYMOUS,
   175  				Binary:           true,
   176  				// HERE! This is what we're testing. (Signcryption mode is the
   177  				// default. EncryptionOnlyMode is false.)
   178  			},
   179  			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
   180  			Sink:   encsink,
   181  		}
   182  
   183  		enceng := NewSaltpackEncrypt(encarg, NewSaltpackUserKeyfinderAsInterface)
   184  		m := NewMetaContextForTest(tc).WithUIs(uis)
   185  		if err := RunEngine2(m, enceng); err != nil {
   186  			t.Fatal(err)
   187  		}
   188  
   189  		encout := encsink.Bytes()
   190  		if len(encout) == 0 {
   191  			t.Fatal("no output")
   192  		}
   193  
   194  		// Decode the header.
   195  		var header saltpack.EncryptionHeader
   196  		hdec := codec.NewDecoderBytes(encout, &codec.MsgpackHandle{WriteExt: true})
   197  		var hbytes []byte
   198  		if err := hdec.Decode(&hbytes); err != nil {
   199  			t.Fatal(err)
   200  		}
   201  		hdec = codec.NewDecoderBytes(hbytes, &codec.MsgpackHandle{WriteExt: true})
   202  		if err := hdec.Decode(&header); err != nil {
   203  			t.Fatal(err)
   204  		}
   205  
   206  		// Necessary so that PUKs are used for decryption
   207  		initPerUserKeyringInTestContext(t, tc)
   208  
   209  		decsink := libkb.NewBufferCloser()
   210  		decarg := &SaltpackDecryptArg{
   211  			Source: strings.NewReader(encsink.String()),
   212  			Sink:   decsink,
   213  		}
   214  		deceng := NewSaltpackDecrypt(decarg, saltpackkeystest.NewMockPseudonymResolver(t))
   215  		if err := RunEngine2(m, deceng); err != nil {
   216  			t.Fatal(err)
   217  		}
   218  
   219  		if !saltpackUI.DidDecrypt {
   220  			t.Fatal("fake saltpackUI not called")
   221  		}
   222  
   223  		// The message should not contain the sender's public key (in the sender secretbox).
   224  		// Instead, the sender key should be the ephemeral key.
   225  		// This tests that the sender type is anonymous.
   226  		if saltpackUI.LastSender.SenderType != keybase1.SaltpackSenderType_ANONYMOUS {
   227  			t.Fatal("sender type not anonymous:", saltpackUI.LastSender.SenderType)
   228  		}
   229  	}
   230  
   231  	run([]string{u1.Username, u2.Username})
   232  
   233  	// If we add ourselves, we should be smart and not error out
   234  	// (We are u3 in this case)
   235  	run([]string{u1.Username, u2.Username, u3.Username})
   236  }
   237  
   238  func TestSaltpackEncryptSelfNoKey(t *testing.T) {
   239  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   240  	defer tc.Cleanup()
   241  
   242  	_, passphrase := createFakeUserWithNoKeys(tc)
   243  	trackUI := &FakeIdentifyUI{
   244  		Proofs: make(map[string]string),
   245  	}
   246  	uis := libkb.UIs{IdentifyUI: trackUI, SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}}
   247  
   248  	sink := libkb.NewBufferCloser()
   249  	arg := &SaltpackEncryptArg{
   250  		Opts: keybase1.SaltpackEncryptOptions{
   251  			// Note: these users actually exist, but they do not have PUKs
   252  			Recipients:    []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
   253  			UseDeviceKeys: true,
   254  		},
   255  		Source: strings.NewReader("track and encrypt, track and encrypt"),
   256  		Sink:   sink,
   257  	}
   258  
   259  	eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   260  	m := NewMetaContextForTest(tc).WithUIs(uis)
   261  	err := RunEngine2(m, eng)
   262  	if _, ok := err.(libkb.NoDeviceError); !ok {
   263  		t.Fatalf("expected error type libkb.NoDeviceError, got %T (%s)", err, err)
   264  	}
   265  }
   266  
   267  func TestSaltpackEncryptLoggedOut(t *testing.T) {
   268  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   269  	defer tc.Cleanup()
   270  
   271  	trackUI := &FakeIdentifyUI{
   272  		Proofs: make(map[string]string),
   273  	}
   274  	uis := libkb.UIs{IdentifyUI: trackUI, SecretUI: &libkb.TestSecretUI{}}
   275  
   276  	sink := libkb.NewBufferCloser()
   277  	arg := &SaltpackEncryptArg{
   278  		Opts: keybase1.SaltpackEncryptOptions{
   279  			// Note: these users actually exist, but they do not have PUKs
   280  			Recipients:    []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
   281  			UseDeviceKeys: true,
   282  			// Only anonymous mode works when you're logged out.
   283  			AuthenticityType: keybase1.AuthenticityType_ANONYMOUS,
   284  			NoSelfEncrypt:    true,
   285  		},
   286  		Source: strings.NewReader("track and encrypt, track and encrypt"),
   287  		Sink:   sink,
   288  	}
   289  
   290  	eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   291  	m := NewMetaContextForTest(tc).WithUIs(uis)
   292  	err := RunEngine2(m, eng)
   293  	if err != nil {
   294  		t.Fatalf("Got unexpected error: %s", err)
   295  	}
   296  }
   297  
   298  func TestSaltpackEncryptNoNaclOnlyPGP(t *testing.T) {
   299  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   300  	defer tc.Cleanup()
   301  
   302  	u2 := createFakeUserWithPGPOnly(t, tc)
   303  	Logout(tc)
   304  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
   305  
   306  	trackUI := &FakeIdentifyUI{
   307  		Proofs: make(map[string]string),
   308  	}
   309  	uis := libkb.UIs{
   310  		IdentifyUI: trackUI,
   311  		SecretUI:   u1.NewSecretUI(),
   312  		SaltpackUI: &fakeSaltpackUI{},
   313  	}
   314  
   315  	msg := "this will never work"
   316  	sink := libkb.NewBufferCloser()
   317  	arg := &SaltpackEncryptArg{
   318  		Opts: keybase1.SaltpackEncryptOptions{
   319  			Recipients:    []string{u2.Username},
   320  			NoSelfEncrypt: true,
   321  			UseDeviceKeys: true,
   322  		},
   323  		Source: strings.NewReader(msg),
   324  		Sink:   sink,
   325  	}
   326  
   327  	eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   328  	m := NewMetaContextForTest(tc).WithUIs(uis)
   329  	err := RunEngine2(m, eng)
   330  	if perr, ok := err.(libkb.NoNaClEncryptionKeyError); !ok {
   331  		t.Fatalf("Got wrong error type: %T %v", err, err)
   332  	} else if !perr.HasPGPKey {
   333  		t.Fatalf("Should have a PGP key")
   334  	} else if perr.Username != u2.Username {
   335  		t.Fatalf("Wrong username")
   336  	}
   337  }
   338  
   339  func TestSaltpackEncryptNoSelf(t *testing.T) {
   340  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   341  	defer tc.Cleanup()
   342  
   343  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
   344  	u2 := CreateAndSignupFakeUser(tc, "nalcp")
   345  
   346  	msg := "for your eyes only (not even mine!)"
   347  
   348  	trackUI := &FakeIdentifyUI{
   349  		Proofs: make(map[string]string),
   350  	}
   351  	uis := libkb.UIs{
   352  		IdentifyUI: trackUI,
   353  		SecretUI:   u2.NewSecretUI(),
   354  		SaltpackUI: &fakeSaltpackUI{},
   355  	}
   356  
   357  	sink := libkb.NewBufferCloser()
   358  	arg := &SaltpackEncryptArg{
   359  		Opts: keybase1.SaltpackEncryptOptions{
   360  			Recipients:    []string{u1.Username},
   361  			NoSelfEncrypt: true,
   362  			UseDeviceKeys: true,
   363  		},
   364  		Source: strings.NewReader(msg),
   365  		Sink:   sink,
   366  	}
   367  
   368  	eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   369  	m := NewMetaContextForTest(tc).WithUIs(uis)
   370  	if err := RunEngine2(m, eng); err != nil {
   371  		t.Fatal(err)
   372  	}
   373  
   374  	out := sink.Bytes()
   375  	if len(out) == 0 {
   376  		t.Fatal("no output")
   377  	}
   378  
   379  	// decrypt it
   380  	decoded := libkb.NewBufferCloser()
   381  	decarg := &SaltpackDecryptArg{
   382  		Source: strings.NewReader(string(out)),
   383  		Sink:   decoded,
   384  	}
   385  	dec := NewSaltpackDecrypt(decarg, saltpackkeystest.NewMockPseudonymResolver(t))
   386  	err := RunEngine2(m, dec)
   387  
   388  	decErr, ok := err.(libkb.DecryptionError)
   389  	if !ok {
   390  		t.Fatalf("Expected err type %T, but got %T", libkb.DecryptionError{}, err)
   391  	}
   392  	if _, ok = decErr.Cause.Err.(libkb.NoDecryptionKeyError); !ok {
   393  		t.Fatalf("Expected err Cause of type %T, but got %T", libkb.NoDecryptionKeyError{}, decErr.Cause.Err)
   394  	}
   395  
   396  	Logout(tc)
   397  	err = u1.Login(tc.G)
   398  	require.NoError(t, err)
   399  
   400  	m = m.WithSecretUI(u1.NewSecretUI())
   401  	decarg.Source = strings.NewReader(string(out))
   402  	dec = NewSaltpackDecrypt(decarg, saltpackkeystest.NewMockPseudonymResolver(t))
   403  	err = RunEngine2(m, dec)
   404  	if err != nil {
   405  		t.Fatal(err)
   406  	}
   407  	decmsg := decoded.String()
   408  	if decmsg != msg {
   409  		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
   410  	}
   411  }
   412  
   413  func TestSaltpackEncryptBinary(t *testing.T) {
   414  	tc := SetupEngineTest(t, "SaltpackEncryptBinary")
   415  	defer tc.Cleanup()
   416  	fu := CreateAndSignupFakeUser(tc, "enc")
   417  
   418  	// encrypt a message
   419  	msg := "10 days in Japan"
   420  	sink := libkb.NewBufferCloser()
   421  	uis := libkb.UIs{
   422  		IdentifyUI: &FakeIdentifyUI{},
   423  		SecretUI:   fu.NewSecretUI(),
   424  		LogUI:      tc.G.UI.GetLogUI(),
   425  		SaltpackUI: &fakeSaltpackUI{},
   426  	}
   427  	// Should encrypt for self, too.
   428  	arg := &SaltpackEncryptArg{
   429  		Source: strings.NewReader(msg),
   430  		Sink:   sink,
   431  		Opts: keybase1.SaltpackEncryptOptions{
   432  			Binary:        true,
   433  			UseEntityKeys: true,
   434  		},
   435  	}
   436  	enc := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   437  	m := NewMetaContextForTest(tc).WithUIs(uis)
   438  	if err := RunEngine2(m, enc); err != nil {
   439  		t.Fatal(err)
   440  	}
   441  	out := sink.String()
   442  
   443  	// Necessary so that PUKs are used for decryption
   444  	initPerUserKeyringInTestContext(t, tc)
   445  
   446  	// decrypt it
   447  	decoded := libkb.NewBufferCloser()
   448  	decarg := &SaltpackDecryptArg{
   449  		Source: strings.NewReader(out),
   450  		Sink:   decoded,
   451  	}
   452  	dec := NewSaltpackDecrypt(decarg, saltpackkeystest.NewMockPseudonymResolver(t))
   453  	if err := RunEngine2(m, dec); err != nil {
   454  		t.Fatal(err)
   455  	}
   456  	decmsg := decoded.String()
   457  	if decmsg != msg {
   458  		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
   459  	}
   460  }
   461  
   462  func TestSaltpackEncryptForceVersion(t *testing.T) {
   463  	tc := SetupEngineTest(t, "SaltpackEncrypt")
   464  	defer tc.Cleanup()
   465  
   466  	u1 := CreateAndSignupFakeUser(tc, "nalcp")
   467  
   468  	trackUI := &FakeIdentifyUI{
   469  		Proofs: make(map[string]string),
   470  	}
   471  	uis := libkb.UIs{IdentifyUI: trackUI, SecretUI: u1.NewSecretUI()}
   472  
   473  	run := func(versionFlag int, majorVersionExpected int) {
   474  		sink := libkb.NewBufferCloser()
   475  		arg := &SaltpackEncryptArg{
   476  			Opts: keybase1.SaltpackEncryptOptions{
   477  				// Encryption only mode is required to set version 1.
   478  				AuthenticityType: keybase1.AuthenticityType_REPUDIABLE,
   479  				Recipients:       []string{u1.Username},
   480  				Binary:           true,
   481  				SaltpackVersion:  versionFlag, // This is what we're testing!
   482  				UseEntityKeys:    true,
   483  			},
   484  			Source: strings.NewReader("testing version flag"),
   485  			Sink:   sink,
   486  		}
   487  
   488  		eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   489  		m := NewMetaContextForTest(tc).WithUIs(uis)
   490  		if err := RunEngine2(m, eng); err != nil {
   491  			t.Fatal(err)
   492  		}
   493  
   494  		out := sink.Bytes()
   495  		if len(out) == 0 {
   496  			t.Fatal("no output")
   497  		}
   498  
   499  		var header saltpack.EncryptionHeader
   500  		dec := codec.NewDecoderBytes(out, &codec.MsgpackHandle{WriteExt: true})
   501  		var b []byte
   502  		if err := dec.Decode(&b); err != nil {
   503  			t.Fatal(err)
   504  		}
   505  		dec = codec.NewDecoderBytes(b, &codec.MsgpackHandle{WriteExt: true})
   506  		if err := dec.Decode(&header); err != nil {
   507  			t.Fatal(err)
   508  		}
   509  
   510  		if header.Version.Major != majorVersionExpected {
   511  			t.Fatalf("passed saltpack version %d and expected major version %d, found %d", versionFlag, majorVersionExpected, header.Version.Major)
   512  		}
   513  	}
   514  
   515  	// 0 means the default, which is major version 2.
   516  	run(0, 2)
   517  	run(1, 1)
   518  	run(2, 2)
   519  }