blob: 09c4fcd0956767125246ac45b34f70ac8c5a4f34 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
"v.io/v23/verror"
"v.io/x/lib/ibe"
vsecurity "v.io/x/ref/lib/security"
"v.io/x/ref/lib/security/bcrypter"
"v.io/x/ref/services/iberoot"
iroot "v.io/x/ref/services/iberoot/iberootd/internal"
"v.io/x/ref/test"
"v.io/x/ref/test/testutil"
_ "v.io/x/ref/runtime/factories/generic"
)
func TestSeekPrivateKeys(t *testing.T) {
// Create a context for starting an IBE
// root service.
ctx, shutdown := test.V23Init()
defer shutdown()
// Create a new IDP.
idpName := "idp"
idp := testutil.NewPrincipal(idpName)
// Make the root service context recognize the IDP.
idpB, _ := idp.BlessingStore().Default()
if err := security.AddToRoots(v23.GetPrincipal(ctx), idpB); err != nil {
t.Fatal(err)
}
// Setup the root service.
_, dir := initIBEMaster(t, ctx)
defer os.RemoveAll(dir)
addr := newRootServer(t, ctx, dir, idpName)
// Obtain the IDP's params.
client := iberoot.RootClient(addr)
wireParams, err := client.Params(ctx)
if err != nil {
t.Fatal(err)
}
var params bcrypter.Params
if err := params.FromWire(wireParams); err != nil {
t.Fatal(err)
}
ptxt := []byte("plaintext")
// Helper function to encrypt 'ptxt' for specific patterns
// using the obtained params.
encrypt := func(ctx *context.T, forPattern security.BlessingPattern) *bcrypter.Ciphertext {
crypter := bcrypter.NewCrypter()
if err := crypter.AddParams(ctx, params); err != nil {
t.Fatal(err)
}
ctxt, err := crypter.Encrypt(ctx, forPattern, ptxt)
if err != nil {
t.Fatal(err)
}
return ctxt
}
// Helper function to check whether 'ctxt' can be decrypted to
// 'ptxt' using one of the provided 'keys'.
decrypt := func(ctx *context.T, ctxt *bcrypter.Ciphertext, keys []bcrypter.WirePrivateKey) error {
crypter := bcrypter.NewCrypter()
// Add all keys to crypter.
for _, wireKey := range keys {
var key bcrypter.PrivateKey
if err := key.FromWire(wireKey); err != nil {
return err
}
if err := crypter.AddKey(ctx, &key); err != nil {
return err
}
}
decrypted, err := crypter.Decrypt(ctx, ctxt)
if err != nil {
return fmt.Errorf("decryption failed: %v", err)
}
if !bytes.Equal(decrypted, ptxt) {
return fmt.Errorf("decryption returned %v, want %v", decrypted, ptxt)
}
return nil
}
// Test private keys obtained using IDP blessings
testcases := []struct {
userExtensions []string
validPatterns []security.BlessingPattern
invalidPatterns []security.BlessingPattern
}{
{
[]string{"user:batman"},
[]security.BlessingPattern{"idp", "idp:user", "idp:user:batman", "idp:user:batman:$"},
[]security.BlessingPattern{"idp:user:batman:phone", "idp:user:brucewayne", "idp:user:brucewayne:phone"},
},
{
[]string{"user:batman", "user:brucewayne"},
[]security.BlessingPattern{"idp", "idp:user", "idp:user:batman", "idp:user:brucewayne", "idp:user:batman:$", "idp:user:brucewayne:$"},
[]security.BlessingPattern{"idp:user:carol", "idp:user:carol:phone"},
},
}
for _, test := range testcases {
user := derive(t, idp, test.userExtensions...)
// Make the user principal recognize the root service.
rootB, _ := v23.GetPrincipal(ctx).BlessingStore().Default()
if err := security.AddToRoots(user, rootB); err != nil {
t.Fatal(err)
}
userCtx, err := v23.WithPrincipal(ctx, user)
if err != nil {
t.Fatal(err)
}
keys, err := client.SeekPrivateKeys(userCtx)
if err != nil {
t.Fatalf("SeekPrivateKeys failed: %v", err)
}
for _, p := range test.validPatterns {
if err := decrypt(userCtx, encrypt(userCtx, p), keys); err != nil {
t.Fatalf("Failed to decrypt ciphertext for pattern %v: %v", p, err)
}
}
for _, p := range test.invalidPatterns {
if err := decrypt(userCtx, encrypt(userCtx, p), keys); err == nil || !strings.Contains(err.Error(), "decryption failed") {
t.Fatalf("Decrypting ciphertext for pattern %v returned %v, want error matching 'decryption failed'", p, err)
}
}
}
// Test that SeekPrivateKeys fails when the client presents
// a blessing not derived from IDP.
user := testutil.NewPrincipal("selfsigned")
rootB, _ := v23.GetPrincipal(ctx).BlessingStore().Default()
if err := security.AddToRoots(user, rootB); err != nil {
t.Fatal(err)
}
userCtx, err := v23.WithPrincipal(ctx, user)
if err != nil {
t.Fatal(err)
}
if _, err = client.SeekPrivateKeys(userCtx); err == nil || verror.ErrorID(err) != iroot.ErrUnrecognizedRemoteBlessings.ID {
t.Fatalf("Got error %v when seeking private keys for a self-signed blessing, wanted error with ID %v", err, "user", iroot.ErrUnrecognizedRemoteBlessings.ID)
}
}
func TestParams(t *testing.T) {
ctx, shutdown := test.V23InitWithMounttable()
defer shutdown()
// Setup an IBE root service.
master, dir := initIBEMaster(t, ctx)
defer os.RemoveAll(dir)
idpName := "idp"
addr := newRootServer(t, ctx, dir, idpName)
// Obtain Params from the IBE root service.
gotWireParams, err := iberoot.RootClient(addr).Params(ctx)
if err != nil {
t.Fatal(err)
}
// Compute expected params from the IBE Master object used by the
// root service.
var wantWireParams bcrypter.WireParams
p := bcrypter.NewRoot(idpName, master).Params()
if err := p.ToWire(&wantWireParams); err != nil {
t.Fatal(err)
}
// Test got == want.
if !reflect.DeepEqual(gotWireParams, wantWireParams) {
t.Fatalf("Got params %v, want %v", gotWireParams, wantWireParams)
}
}
func derive(t *testing.T, idp security.Principal, extensions ...string) security.Principal {
p := testutil.NewPrincipal()
blessings := make([]security.Blessings, len(extensions))
var err error
for i, e := range extensions {
b, _ := idp.BlessingStore().Default()
if blessings[i], err = idp.Bless(p.PublicKey(), b, e, security.UnconstrainedUse()); err != nil {
t.Fatal(err)
}
}
bUnion, err := security.UnionOfBlessings(blessings...)
if err != nil {
t.Fatal(err)
}
if err := vsecurity.SetDefaultBlessings(p, bUnion); err != nil {
t.Fatal(err)
}
return p
}
func newRootServer(t *testing.T, ctx *context.T, dir string, idpName string) string {
root, err := iroot.NewRootServer(dir, idpName)
if err != nil {
t.Fatalf("Cannot create iberoot.Root object: %v", err)
}
ctx, server, err := v23.WithNewServer(ctx, "", root, security.AllowEveryone())
if err != nil {
t.Fatalf("WithNewServer failed: %v", err)
}
return server.Status().Endpoints[0].Name()
}
func initIBEMaster(t *testing.T, ctx *context.T) (ibe.Master, string) {
dir, err := ioutil.TempDir("", "ibe_master_key")
if err != nil {
t.Fatalf("ioutil.TempDir failed: %v", err)
}
master, err := ibe.SetupBB2()
if err != nil {
t.Fatalf("ibe.SetupBB2() failed: %v", err)
}
if err := iroot.SaveMaster(master, dir); err != nil {
t.Fatalf("SaveMaster failed: %v", err)
}
return master, dir
}