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 }