github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/saltpack_sign_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  	"bytes"
     8  	"io"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/keybase/client/go/libkb"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/go-codec/codec"
    15  	"github.com/keybase/saltpack"
    16  )
    17  
    18  func TestSaltpackSignDeviceRequired(t *testing.T) {
    19  	tc := SetupEngineTest(t, "sign")
    20  	defer tc.Cleanup()
    21  
    22  	uis := libkb.UIs{
    23  		SecretUI: &libkb.TestSecretUI{},
    24  	}
    25  	eng := NewSaltpackSign(tc.G, nil)
    26  	m := NewMetaContextForTest(tc).WithUIs(uis)
    27  	err := RunEngine2(m, eng)
    28  	if err == nil {
    29  		t.Fatal("sign not logged in returned no error")
    30  	}
    31  	if _, ok := err.(libkb.DeviceRequiredError); !ok {
    32  		t.Errorf("error type: %T, expected DeviceRequiredError", err)
    33  	}
    34  }
    35  
    36  func TestSaltpackSignVerify(t *testing.T) {
    37  	tc := SetupEngineTest(t, "sign")
    38  	defer tc.Cleanup()
    39  
    40  	fu := CreateAndSignupFakeUser(tc, "sign")
    41  
    42  	// signTests are defined in pgp_sign_test.  Make sure that saltpack sign can
    43  	// sign/verify the same messages as pgp.
    44  	for _, test := range signTests {
    45  		var sink bytes.Buffer
    46  
    47  		sarg := &SaltpackSignArg{
    48  			Sink:   libkb.NopWriteCloser{W: &sink},
    49  			Source: io.NopCloser(bytes.NewBufferString(test.input)),
    50  		}
    51  
    52  		eng := NewSaltpackSign(tc.G, sarg)
    53  		uis := libkb.UIs{
    54  			IdentifyUI: &FakeIdentifyUI{},
    55  			SecretUI:   fu.NewSecretUI(),
    56  		}
    57  
    58  		m := NewMetaContextForTest(tc).WithUIs(uis)
    59  		if err := RunEngine2(m, eng); err != nil {
    60  			t.Errorf("%s: run error: %s", test.name, err)
    61  			continue
    62  		}
    63  
    64  		sig := sink.String()
    65  
    66  		if len(sig) == 0 {
    67  			t.Errorf("%s: empty sig", test.name)
    68  		}
    69  
    70  		varg := &SaltpackVerifyArg{
    71  			Sink:   libkb.NopWriteCloser{W: &sink},
    72  			Source: strings.NewReader(sig),
    73  		}
    74  		veng := NewSaltpackVerify(tc.G, varg)
    75  
    76  		m = m.WithSaltpackUI(fakeSaltpackUI{})
    77  
    78  		if err := RunEngine2(m, veng); err != nil {
    79  			t.Errorf("%s: verify error: %s", test.name, err)
    80  			continue
    81  		}
    82  
    83  		// test SignedBy option:
    84  		varg = &SaltpackVerifyArg{
    85  			Sink:   libkb.NopWriteCloser{W: &sink},
    86  			Source: strings.NewReader(sig),
    87  			Opts: keybase1.SaltpackVerifyOptions{
    88  				SignedBy: fu.Username,
    89  			},
    90  		}
    91  		veng = NewSaltpackVerify(tc.G, varg)
    92  		if err := RunEngine2(m, veng); err != nil {
    93  			t.Errorf("%s: verify w/ SignedBy error: %s", test.name, err)
    94  			continue
    95  		}
    96  
    97  		varg = &SaltpackVerifyArg{
    98  			Sink:   libkb.NopWriteCloser{W: &sink},
    99  			Source: strings.NewReader(sig),
   100  			Opts: keybase1.SaltpackVerifyOptions{
   101  				SignedBy: "unknown",
   102  			},
   103  		}
   104  		veng = NewSaltpackVerify(tc.G, varg)
   105  		if err := RunEngine2(m, veng); err == nil {
   106  			t.Errorf("%s: verify w/ SignedBy=unknown worked, should have failed", test.name)
   107  			continue
   108  		}
   109  	}
   110  
   111  	// now try the same messages, but generate detached signatures
   112  	for _, test := range signTests {
   113  		var sink bytes.Buffer
   114  
   115  		sarg := &SaltpackSignArg{
   116  			Sink:   libkb.NopWriteCloser{W: &sink},
   117  			Source: io.NopCloser(bytes.NewBufferString(test.input)),
   118  			Opts: keybase1.SaltpackSignOptions{
   119  				Detached: true,
   120  			},
   121  		}
   122  
   123  		eng := NewSaltpackSign(tc.G, sarg)
   124  		uis := libkb.UIs{
   125  			IdentifyUI: &FakeIdentifyUI{},
   126  			SecretUI:   fu.NewSecretUI(),
   127  		}
   128  		m := NewMetaContextForTest(tc).WithUIs(uis)
   129  		if err := RunEngine2(m, eng); err != nil {
   130  			t.Errorf("(detached) %s: run error: %s", test.name, err)
   131  			continue
   132  		}
   133  
   134  		sig := sink.Bytes()
   135  
   136  		if len(sig) == 0 {
   137  			t.Errorf("(detached) %s: empty sig", test.name)
   138  		}
   139  
   140  		varg := &SaltpackVerifyArg{
   141  			Sink:   libkb.NopWriteCloser{W: &sink},
   142  			Source: strings.NewReader(test.input),
   143  			Opts: keybase1.SaltpackVerifyOptions{
   144  				Signature: sig,
   145  			},
   146  		}
   147  
   148  		veng := NewSaltpackVerify(tc.G, varg)
   149  		m = m.WithSaltpackUI(fakeSaltpackUI{})
   150  		if err := RunEngine2(m, veng); err != nil {
   151  			t.Errorf("(detached) %s: verify error: %s", test.name, err)
   152  			continue
   153  		}
   154  	}
   155  }
   156  
   157  func TestSaltpackSignVerifyBinary(t *testing.T) {
   158  	tc := SetupEngineTest(t, "sign")
   159  	defer tc.Cleanup()
   160  
   161  	fu := CreateAndSignupFakeUser(tc, "sign")
   162  
   163  	// signTests are defined in pgp_sign_test.  Make sure that saltpack sign can
   164  	// sign/verify the same messages as pgp.
   165  	for _, test := range signTests {
   166  		var sink bytes.Buffer
   167  
   168  		sarg := &SaltpackSignArg{
   169  			Sink:   libkb.NopWriteCloser{W: &sink},
   170  			Source: io.NopCloser(bytes.NewBufferString(test.input)),
   171  			Opts: keybase1.SaltpackSignOptions{
   172  				Binary: true,
   173  			},
   174  		}
   175  
   176  		eng := NewSaltpackSign(tc.G, sarg)
   177  		uis := libkb.UIs{
   178  			IdentifyUI: &FakeIdentifyUI{},
   179  			SecretUI:   fu.NewSecretUI(),
   180  		}
   181  		m := NewMetaContextForTest(tc).WithUIs(uis)
   182  		if err := RunEngine2(m, eng); err != nil {
   183  			t.Errorf("%s: run error: %s", test.name, err)
   184  			continue
   185  		}
   186  
   187  		sig := sink.String()
   188  
   189  		if len(sig) == 0 {
   190  			t.Errorf("%s: empty sig", test.name)
   191  		}
   192  
   193  		varg := &SaltpackVerifyArg{
   194  			Sink:   libkb.NopWriteCloser{W: &sink},
   195  			Source: strings.NewReader(sig),
   196  		}
   197  		veng := NewSaltpackVerify(tc.G, varg)
   198  
   199  		m = m.WithSaltpackUI(fakeSaltpackUI{})
   200  
   201  		if err := RunEngine2(m, veng); err != nil {
   202  			t.Errorf("%s: verify error: %s", test.name, err)
   203  			continue
   204  		}
   205  	}
   206  
   207  	// now try the same messages, but generate detached signatures
   208  	for _, test := range signTests {
   209  		var sink bytes.Buffer
   210  
   211  		sarg := &SaltpackSignArg{
   212  			Sink:   libkb.NopWriteCloser{W: &sink},
   213  			Source: io.NopCloser(bytes.NewBufferString(test.input)),
   214  			Opts: keybase1.SaltpackSignOptions{
   215  				Binary:   true,
   216  				Detached: true,
   217  			},
   218  		}
   219  
   220  		eng := NewSaltpackSign(tc.G, sarg)
   221  		uis := libkb.UIs{
   222  			IdentifyUI: &FakeIdentifyUI{},
   223  			SecretUI:   fu.NewSecretUI(),
   224  		}
   225  		m := NewMetaContextForTest(tc).WithUIs(uis)
   226  		if err := RunEngine2(m, eng); err != nil {
   227  			t.Errorf("(detached) %s: run error: %s", test.name, err)
   228  			continue
   229  		}
   230  
   231  		sig := sink.Bytes()
   232  
   233  		if len(sig) == 0 {
   234  			t.Errorf("(detached) %s: empty sig", test.name)
   235  		}
   236  
   237  		varg := &SaltpackVerifyArg{
   238  			Sink:   libkb.NopWriteCloser{W: &sink},
   239  			Source: strings.NewReader(test.input),
   240  			Opts: keybase1.SaltpackVerifyOptions{
   241  				Signature: sig,
   242  			},
   243  		}
   244  		veng := NewSaltpackVerify(tc.G, varg)
   245  		m = m.WithSaltpackUI(fakeSaltpackUI{})
   246  
   247  		if err := RunEngine2(m, veng); err != nil {
   248  			t.Errorf("(detached) %s: verify error: %s", test.name, err)
   249  			continue
   250  		}
   251  	}
   252  }
   253  
   254  func TestSaltpackSignVerifyNotSelf(t *testing.T) {
   255  	tc := SetupEngineTest(t, "sign")
   256  	defer tc.Cleanup()
   257  
   258  	signer := CreateAndSignupFakeUser(tc, "sign")
   259  
   260  	var sink bytes.Buffer
   261  
   262  	sarg := &SaltpackSignArg{
   263  		Sink:   libkb.NopWriteCloser{W: &sink},
   264  		Source: io.NopCloser(bytes.NewBufferString("this is from me")),
   265  	}
   266  
   267  	eng := NewSaltpackSign(tc.G, sarg)
   268  	uis := libkb.UIs{
   269  		IdentifyUI: &FakeIdentifyUI{},
   270  		SecretUI:   signer.NewSecretUI(),
   271  	}
   272  
   273  	m := NewMetaContextForTest(tc).WithUIs(uis)
   274  	if err := RunEngine2(m, eng); err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	sig := sink.String()
   279  
   280  	if len(sig) == 0 {
   281  		t.Fatal("empty sig")
   282  	}
   283  
   284  	Logout(tc)
   285  
   286  	_ = CreateAndSignupFakeUser(tc, "sign")
   287  
   288  	// no user assertion
   289  	varg := &SaltpackVerifyArg{
   290  		Sink:   libkb.NopWriteCloser{W: &sink},
   291  		Source: strings.NewReader(sig),
   292  	}
   293  	veng := NewSaltpackVerify(tc.G, varg)
   294  
   295  	m = m.WithSaltpackUI(fakeSaltpackUI{})
   296  
   297  	if err := RunEngine2(m, veng); err != nil {
   298  		t.Fatalf("verify error: %s", err)
   299  	}
   300  
   301  	// valid user assertion
   302  	varg = &SaltpackVerifyArg{
   303  		Sink:   libkb.NopWriteCloser{W: &sink},
   304  		Source: strings.NewReader(sig),
   305  		Opts: keybase1.SaltpackVerifyOptions{
   306  			SignedBy: signer.Username,
   307  		},
   308  	}
   309  	veng = NewSaltpackVerify(tc.G, varg)
   310  	if err := RunEngine2(m, veng); err != nil {
   311  		t.Fatalf("verify w/ SignedBy error: %s", err)
   312  	}
   313  
   314  	// invalid user assertion
   315  	varg = &SaltpackVerifyArg{
   316  		Sink:   libkb.NopWriteCloser{W: &sink},
   317  		Source: strings.NewReader(sig),
   318  		Opts: keybase1.SaltpackVerifyOptions{
   319  			SignedBy: "unknown",
   320  		},
   321  	}
   322  	veng = NewSaltpackVerify(tc.G, varg)
   323  	if err := RunEngine2(m, veng); err == nil {
   324  		t.Errorf("verify w/ SignedBy unknown didn't fail")
   325  	}
   326  }
   327  
   328  func TestSaltpackVerifyRevoked(t *testing.T) {
   329  	tc := SetupEngineTest(t, "sign")
   330  	defer tc.Cleanup()
   331  
   332  	fu := CreateAndSignupFakeUser(tc, "sign")
   333  
   334  	var sink bytes.Buffer
   335  
   336  	sarg := &SaltpackSignArg{
   337  		Sink:   libkb.NopWriteCloser{W: &sink},
   338  		Source: io.NopCloser(bytes.NewBufferString("test input wooo")),
   339  	}
   340  
   341  	eng := NewSaltpackSign(tc.G, sarg)
   342  	uis := libkb.UIs{
   343  		LogUI:      tc.G.UI.GetLogUI(),
   344  		LoginUI:    &libkb.TestLoginUI{},
   345  		IdentifyUI: &FakeIdentifyUI{},
   346  		SecretUI:   fu.NewSecretUI(),
   347  	}
   348  	m := NewMetaContextForTest(tc).WithUIs(uis)
   349  	if err := RunEngine2(m, eng); err != nil {
   350  		t.Fatal(err)
   351  	}
   352  
   353  	// Get the current device
   354  	devices, _ := getActiveDevicesAndKeys(tc, fu)
   355  	if len(devices) != 1 {
   356  		t.Fatalf("Expected a single device, but found %d", len(devices))
   357  	}
   358  	currentDevice := devices[0]
   359  
   360  	// Delegate a new paper key so that we have something active after we
   361  	// revoke the current device.
   362  	paperEng := NewPaperKey(tc.G)
   363  	if err := RunEngine2(m, paperEng); err != nil {
   364  		t.Fatal(err)
   365  	}
   366  
   367  	// Revoke the current device.
   368  	err := doRevokeDevice(tc, fu, currentDevice.ID, false, false)
   369  	if err == nil {
   370  		tc.T.Fatal("Expected revoking the current device to fail.")
   371  	}
   372  	// force=true is required for the current device
   373  	err = doRevokeDevice(tc, fu, currentDevice.ID, true, false)
   374  	if err != nil {
   375  		tc.T.Fatal(err)
   376  	}
   377  
   378  	// Finally verify the sig. This should be an error, because the signing
   379  	// device is revoked. The revoked status will get passed to our
   380  	// fakeSaltpackUI's SaltpackVerifyBadSender method, made into an error, and
   381  	// propagated all the way back here. Unfortunately we can't really test the
   382  	// force option here, because that's implemented in the real client
   383  	// SaltpackUI.
   384  	sig := sink.String()
   385  	if len(sig) == 0 {
   386  		t.Fatal("empty sig")
   387  	}
   388  	varg := &SaltpackVerifyArg{
   389  		Sink:   libkb.NopWriteCloser{W: &sink},
   390  		Source: strings.NewReader(sig),
   391  	}
   392  	veng := NewSaltpackVerify(tc.G, varg)
   393  	m = m.WithSaltpackUI(fakeSaltpackUI{})
   394  	err = RunEngine2(m, veng)
   395  	if err == nil {
   396  		t.Fatal("expected error during verify")
   397  	}
   398  	verificationError, ok := err.(libkb.VerificationError)
   399  	if !ok {
   400  		t.Fatal("expected VerificationError during verify")
   401  	}
   402  	badSenderError, ok := verificationError.Cause.Err.(*FakeBadSenderError)
   403  	if !ok {
   404  		t.Fatal("expected FakeBadSenderError during verify")
   405  	}
   406  
   407  	if badSenderError.senderType != keybase1.SaltpackSenderType_REVOKED {
   408  		t.Fatalf("expected keybase1.SaltpackSenderType_REVOKED, got %s", badSenderError.senderType.String())
   409  	}
   410  }
   411  
   412  func TestSaltpackSignForceVersion(t *testing.T) {
   413  	tc := SetupEngineTest(t, "sign")
   414  	defer tc.Cleanup()
   415  
   416  	fu := CreateAndSignupFakeUser(tc, "sign")
   417  
   418  	run := func(versionFlag int, majorVersionExpected int) {
   419  		// For each run, test both the attached and detached sig modes.
   420  		for _, isAttached := range []bool{true, false} {
   421  			var sink bytes.Buffer
   422  			sarg := &SaltpackSignArg{
   423  				Sink:   libkb.NopWriteCloser{W: &sink},
   424  				Source: io.NopCloser(bytes.NewBufferString("some test input")),
   425  				Opts: keybase1.SaltpackSignOptions{
   426  					Binary:          true,
   427  					SaltpackVersion: versionFlag,
   428  					Detached:        !isAttached,
   429  				},
   430  			}
   431  			eng := NewSaltpackSign(tc.G, sarg)
   432  			uis := libkb.UIs{
   433  				IdentifyUI: &FakeIdentifyUI{},
   434  				SecretUI:   fu.NewSecretUI(),
   435  			}
   436  			m := NewMetaContextForTest(tc).WithUIs(uis)
   437  			if err := RunEngine2(m, eng); err != nil {
   438  				t.Fatal(err)
   439  			}
   440  
   441  			// Double decode the header and inspect it.
   442  			var header saltpack.EncryptionHeader
   443  			dec := codec.NewDecoderBytes(sink.Bytes(), &codec.MsgpackHandle{WriteExt: true})
   444  			var b []byte
   445  			if err := dec.Decode(&b); err != nil {
   446  				t.Fatal(err)
   447  			}
   448  			dec = codec.NewDecoderBytes(b, &codec.MsgpackHandle{WriteExt: true})
   449  			if err := dec.Decode(&header); err != nil {
   450  				t.Fatal(err)
   451  			}
   452  
   453  			if header.Version.Major != majorVersionExpected {
   454  				t.Fatalf("passed saltpack version %d (attached: %t) and expected major version %d, found %d", versionFlag, isAttached, majorVersionExpected, header.Version.Major)
   455  			}
   456  		}
   457  	}
   458  
   459  	// 0 means the default, which is major version 2.
   460  	run(0, 2)
   461  	run(1, 1)
   462  	run(2, 2)
   463  }