Skip to content

Commit

Permalink
Implement new crypto protocol with sign RPC
Browse files Browse the repository at this point in the history
This will be used by kbfs. Also add methods to GenericKey
to sign/verify to bytes.

Also plumb through subkey to the CurrentSession RPC.

Remove redundant nil key checks.

Move SecretUI and LoginUI methods to the right place
(service/handler.go).

Remove unused test/main.go file.

This closes keybase#421.
  • Loading branch information
akalin committed May 13, 2015
1 parent 941a75e commit 3da6ce6
Show file tree
Hide file tree
Showing 37 changed files with 575 additions and 220 deletions.
4 changes: 2 additions & 2 deletions go/engine/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func (e *BTCEngine) Run(ctx *Context) error {
Me: me,
KeyType: libkb.DeviceKeyType,
}, ctx.SecretUI, "to register a cryptocurrency address")
if sigKey == nil {
return fmt.Errorf("Signing key is nil.")
if err != nil {
return err
}
if err = sigKey.CheckSecretKey(); err != nil {
return err
Expand Down
65 changes: 65 additions & 0 deletions go/engine/crypto_sign.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package engine

import (
"github.com/keybase/client/go/libkb"
)

type CryptoSignEngine struct {
libkb.Contextified
msg []byte
reason string
sig []byte
}

func NewCryptoSignEngine(ctx *libkb.GlobalContext, msg []byte, reason string) *CryptoSignEngine {
cse := &CryptoSignEngine{msg: msg, reason: reason}
cse.SetGlobalContext(ctx)
return cse
}

func (cse *CryptoSignEngine) Name() string {
return "CryptoSign"
}

func (cse *CryptoSignEngine) GetPrereqs() EnginePrereqs { return EnginePrereqs{} }

func (cse *CryptoSignEngine) RequiredUIs() []libkb.UIKind {
return []libkb.UIKind{
libkb.SecretUIKind,
}
}

func (cse *CryptoSignEngine) SubConsumers() []libkb.UIConsumer {
return []libkb.UIConsumer{}
}

func (cse *CryptoSignEngine) Run(ctx *Context) (cserr error) {
me, err := libkb.LoadMe(libkb.LoadUserArg{})
if err != nil {
return err
}

sigKey, _, err := cse.G().Keyrings.GetSecretKeyWithPrompt(libkb.SecretKeyArg{
Me: me,
KeyType: libkb.DeviceKeyType,
}, ctx.SecretUI, cse.reason)
if err != nil {
return err
}

if err = sigKey.CheckSecretKey(); err != nil {
return err
}

sig, err := sigKey.SignToBytes(cse.msg)
if err != nil {
return err
}

cse.sig = sig
return nil
}

func (cse *CryptoSignEngine) GetSignature() []byte {
return cse.sig
}
46 changes: 46 additions & 0 deletions go/engine/crypto_sign_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package engine

import (
"testing"

"github.com/keybase/client/go/libkb"
)

// Test that CryptoSignEngine yields a signature that the device
// subkey can verify.
//
// (For general tests that valid signatures are accepted and invalid
// signatures are rejected, see naclwrap_test.go.)
func TestCryptoSign(t *testing.T) {
tc := SetupEngineTest(t, "crypto_sign")
defer tc.Cleanup()

fu := CreateAndSignupFakeUser(tc, "sign")

msg := []byte("test message")

me, err := libkb.LoadUser(libkb.LoadUserArg{Name: fu.Username})
if err != nil {
t.Fatal(err)
}

cse := NewCryptoSignEngine(tc.G, msg, "test reason")
secui := libkb.TestSecretUI{Passphrase: fu.Passphrase}
ctx := &Context{
SecretUI: secui,
}
err = RunEngine(cse, ctx)
if err != nil {
t.Fatal(err)
}

sibkey, _, err := me.GetDeviceKeys()
if err != nil {
t.Fatal(err)
}

err = sibkey.VerifyBytes(cse.GetSignature(), msg)
if err != nil {
t.Error(err)
}
}
6 changes: 3 additions & 3 deletions go/engine/device_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ func TestDeviceKey(t *testing.T) {
t.Fatalf("Can't load current user")
}

if subkeyKid, err := u.GetDeviceSubkeyKid(tc.G); err != nil {
if sibkey, subkey, err := u.GetDeviceKeys(); err != nil {
t.Fatal(err)
} else if subkeyKid == nil {
t.Fatalf("Failed to load device key right after signup")
} else if sibkey == nil || subkey == nil {
t.Fatalf("Failed to load device keys right after signup")
}
}
check()
Expand Down
2 changes: 1 addition & 1 deletion go/engine/kexsib.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (k *KexSib) handlePleaseSign(m *kex.Msg) error {
sig := m.Args().Sig

keypair := libkb.NaclSigningKeyPair{Public: eddsa}
sigPayload, _, err := keypair.VerifyAndExtract(sig)
sigPayload, _, err := keypair.VerifyStringAndExtract(sig)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion go/engine/login_device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestLoginNewDeviceKex(t *testing.T) {
t.Fatal(err)
}

testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
wg.Wait()
}

Expand Down
24 changes: 12 additions & 12 deletions go/engine/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestLoginFakeUserNoKeys(t *testing.T) {
}
}

func testUserHasDeviceKey(t *testing.T) {
func testUserHasDeviceKeys(t *testing.T) {
me, err := libkb.LoadMe(libkb.LoadUserArg{PublicKeyOptional: true})
if err != nil {
t.Fatal(err)
Expand All @@ -77,12 +77,12 @@ func testUserHasDeviceKey(t *testing.T) {
t.Errorf("user has no active key")
}

dsk, err := me.GetDeviceSibkey()
sibkey, subkey, err := me.GetDeviceKeys()
if err != nil {
t.Fatal(err)
}
if dsk == nil {
t.Fatal("nil sibkey")
if sibkey == nil || subkey == nil {
t.Fatal("nil sibkey or subkey")
}
}

Expand All @@ -105,7 +105,7 @@ func TestLoginAddsKeys(t *testing.T) {
}

// since this user didn't have any keys, login should have fixed that:
testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

func TestLoginDetKeyOnly(t *testing.T) {
Expand All @@ -127,7 +127,7 @@ func TestLoginDetKeyOnly(t *testing.T) {
}

// since this user didn't have a device key, login should have fixed that:
testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

// TestLoginPGPSignNewDevice
Expand Down Expand Up @@ -169,7 +169,7 @@ func TestLoginPGPSignNewDevice(t *testing.T) {
t.Errorf("doc ui SelectSigner called %d times, expected 1", after-before)
}

testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

func TestLoginPGPPubOnlySignNewDevice(t *testing.T) {
Expand Down Expand Up @@ -211,7 +211,7 @@ func TestLoginPGPPubOnlySignNewDevice(t *testing.T) {
t.Errorf("doc ui SelectSigner called %d times, expected 1", after-before)
}

testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

func TestLoginPGPMultSignNewDevice(t *testing.T) {
Expand Down Expand Up @@ -252,7 +252,7 @@ func TestLoginPGPMultSignNewDevice(t *testing.T) {
t.Errorf("doc ui SelectSigner called %d times, expected 1", after-before)
}

testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

// TestLoginInterrupt* tries to simulate what would happen if the
Expand Down Expand Up @@ -302,7 +302,7 @@ func TestLoginInterruptDeviceRegister(t *testing.T) {
}

// since this user didn't have any keys, login should have fixed that:
testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

// TestLoginInterruptDevicePush interrupts before pushing device
Expand Down Expand Up @@ -361,7 +361,7 @@ func TestLoginInterruptDevicePush(t *testing.T) {
}

// since this user didn't have any keys, login should have fixed that:
testUserHasDeviceKey(t)
testUserHasDeviceKeys(t)
}

func TestUserInfo(t *testing.T) {
Expand All @@ -373,7 +373,7 @@ func TestUserInfo(t *testing.T) {
var username string
var err error
tc.G.LoginState().Account(func(a *libkb.Account) {
_, username, _, _, err = a.UserInfo()
_, username, _, _, _, err = a.UserInfo()
}, "TestUserInfo")
if err != nil {
t.Fatal(err)
Expand Down
3 changes: 0 additions & 3 deletions go/engine/pgp_encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ func (e *PGPEncrypt) Run(ctx *Context) error {
if err != nil {
return err
}
if key == nil {
return errors.New("No secret key available")
}

var ok bool
mykey, ok = key.(*libkb.PgpKeyBundle)
Expand Down
3 changes: 0 additions & 3 deletions go/engine/pgp_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ func (p *PGPSignEngine) Run(ctx *Context) (err error) {
} else if pgp, ok = key.(*libkb.PgpKeyBundle); !ok {
err = fmt.Errorf("Can only sign with PGP keys (for now)")
return
} else if key == nil {
err = fmt.Errorf("No secret key available")
return
}

bo := p.arg.Opts.BinaryOut
Expand Down
2 changes: 1 addition & 1 deletion go/engine/pgp_sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestPgpSign(t *testing.T) {

sig := sink.String()

_, err = key.Verify(sig, []byte(msg))
_, err = key.VerifyString(sig, []byte(msg))
if err != nil {
t.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions go/engine/revoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ func (e *RevokeEngine) Run(ctx *Context) error {
Me: me,
KeyType: libkb.DeviceKeyType,
}, ctx.SecretUI, "to revoke another key")
if sigKey == nil {
return fmt.Errorf("Revocation signing key is nil.")
if err != nil {
return err
}
if err = sigKey.CheckSecretKey(); err != nil {
return err
Expand Down
3 changes: 0 additions & 3 deletions go/engine/untrack.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,6 @@ func (e *UntrackEngine) storeRemoteUntrack(them *libkb.User, ctx *Context) (err
var signingKeyPriv libkb.GenericKey
if signingKeyPriv, _, err = e.G().Keyrings.GetSecretKeyWithPrompt(arg, ctx.SecretUI, "untracking signature"); err != nil {
return
} else if signingKeyPriv == nil {
err = libkb.NoSecretKeyError{}
return
}

var sig string
Expand Down
5 changes: 2 additions & 3 deletions go/libkb/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func (a *Account) EnsureUsername(username string) {

}

func (a *Account) UserInfo() (uid UID, username, token string, deviceSubkeyKid KID, err error) {
func (a *Account) UserInfo() (uid UID, username, token string, deviceSibkey, deviceSubkey GenericKey, err error) {
if !a.LoggedIn() {
err = LoginRequiredError{}
return
Expand All @@ -251,9 +251,8 @@ func (a *Account) UserInfo() (uid UID, username, token string, deviceSubkeyKid K
return
}

deviceSubkeyKid, err = user.GetDeviceSubkeyKid(a.G())
deviceSibkey, deviceSubkey, err = user.GetDeviceKeys()
if err != nil {
deviceSubkeyKid = KID{}
return
}

Expand Down
4 changes: 2 additions & 2 deletions go/libkb/chain_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ func (c *ChainLink) VerifySigWithKeyFamily(ckf ComputedKeyFamily) (cached bool,
return
}

if sigId, err = key.Verify(c.unpacked.sig, []byte(c.unpacked.payloadJsonStr)); err != nil {
if sigId, err = key.VerifyString(c.unpacked.sig, []byte(c.unpacked.payloadJsonStr)); err != nil {
return
}
c.unpacked.sigId = *sigId
Expand All @@ -454,7 +454,7 @@ func (c *ChainLink) VerifySig(k PgpKeyBundle) (cached bool, err error) {
err = fmt.Errorf("Key fingerprint mismatch")
return
}
if sig_id, e2 := k.Verify(c.unpacked.sig,
if sig_id, e2 := k.VerifyString(c.unpacked.sig,
[]byte(c.unpacked.payloadJsonStr)); e2 != nil {
err = e2
return
Expand Down
25 changes: 22 additions & 3 deletions go/libkb/generickey.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,28 @@ type GenericKey interface {
GetKid() KID
GetFingerprintP() *PgpFingerprint
GetAlgoType() AlgoType
SignToString([]byte) (string, *SigId, error)
Verify(string, []byte) (*SigId, error)
VerifyAndExtract(string) ([]byte, *SigId, error)

// Sign to an ASCII signature (which includes the message
// itself) and return it, along with a derived ID.
SignToString(msg []byte) (sig string, id *SigId, err error)

// Verify that the given signature is valid and extracts the
// embedded message from it. Also returns the signature ID.
VerifyStringAndExtract(sig string) (msg []byte, id *SigId, err error)

// Verify that the given signature is valid and that its
// embedded message matches the given one. Also returns the
// signature ID.
VerifyString(sig string, msg []byte) (id *SigId, err error)

// Sign to a binary signature (which doesn't include the
// message) and return it.
SignToBytes(msg []byte) (sig []byte, err error)

// Verify that the given signature is valid and is for the
// given message.
VerifyBytes(sig, msg []byte) (err error)

ToSKB(ts *triplesec.Cipher) (*SKB, error)
ToLksSKB(lks *LKSec) (*SKB, error)
VerboseDescription() string
Expand Down
2 changes: 1 addition & 1 deletion go/libkb/id_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ func (s *SibkeyChainLink) VerifyReverseSig(kf *KeyFamily) (err error) {
}

var p1, p2 []byte
if p1, _, err = key.VerifyAndExtract(s.reverseSig); err != nil {
if p1, _, err = key.VerifyStringAndExtract(s.reverseSig); err != nil {
err = ReverseSigError{fmt.Sprintf("Failed to verify/extract sig: %s", err.Error())}
return
}
Expand Down
2 changes: 1 addition & 1 deletion go/libkb/merkle_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ func (mc *MerkleClient) VerifyRoot(root *MerkleRoot) error {
}

// Actually run the PGP verification over the signature
_, err = key.Verify(root.sig, []byte(root.payloadJsonString))
_, err = key.VerifyString(root.sig, []byte(root.payloadJsonString))
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 3da6ce6

Please sign in to comment.