blob: 7744cb5d482da4b5153e0be94cd673091091a29d [file] [log] [blame]
// Copyright 2015 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 security
import (
"reflect"
"testing"
"v.io/v23/context"
)
func TestDischargeToAndFromWire(t *testing.T) {
var (
p = newPrincipal(t)
cav = newCaveat(NewPublicKeyCaveat(p.PublicKey(), "peoria", ThirdPartyRequirements{}, UnconstrainedUse()))
)
discharge, err := p.MintDischarge(cav, UnconstrainedUse())
if err != nil {
t.Fatal(err)
}
// Should be able to round-trip from native type to a copy
var d2 Discharge
if err := roundTrip(discharge, &d2); err != nil || !reflect.DeepEqual(discharge, d2) {
t.Errorf("Got (%#v, %v) want (%#v, nil)", d2, err, discharge)
}
// And from native type to a wire type
var wire1, wire2 WireDischarge
if err := roundTrip(discharge, &wire1); err != nil {
t.Fatal(err)
}
// And from wire to another wire type
if err := roundTrip(wire1, &wire2); err != nil || !reflect.DeepEqual(wire1, wire2) {
t.Fatalf("Got (%#v, %v) want (%#v, nil)", wire2, err, wire1)
}
// And from wire to a native type
var d3 Discharge
if err := roundTrip(wire2, &d3); err != nil || !reflect.DeepEqual(discharge, d3) {
t.Errorf("Got (%#v, %v) want (%#v, nil)", d3, err, discharge)
}
}
func TestDischargeSignatureCaching(t *testing.T) {
var (
p1 = newPrincipal(t)
p2 = newPrincipal(t)
cav = newCaveat(NewPublicKeyCaveat(p1.PublicKey(), "peoria", ThirdPartyRequirements{}, UnconstrainedUse()))
ctx, cancel = context.RootContext()
mkCall = func(d Discharge) Call {
return NewCall(&CallParams{
RemoteDischarges: map[string]Discharge{cav.ThirdPartyDetails().ID(): d},
})
}
)
defer cancel()
discharge1, err := p1.MintDischarge(cav, UnconstrainedUse())
if err != nil {
t.Fatal(err)
}
// Another principal (p2) may mint a discharge for the same caveat, but it should not be accepted.
discharge2, err := p2.MintDischarge(cav, UnconstrainedUse())
if err != nil {
t.Fatal(err)
}
if err := cav.Validate(ctx, mkCall(discharge1)); err != nil {
t.Error(err)
}
if err := cav.Validate(ctx, mkCall(discharge2)); err == nil {
t.Errorf("Caveat that required a discharge from one principal was validated by a discharge created by another!")
}
}
func BenchmarkDischargeEquality(b *testing.B) {
p, err := CreatePrincipal(newSigner(), nil, nil)
if err != nil {
b.Fatal(err)
}
cav := newCaveat(NewPublicKeyCaveat(p.PublicKey(), "moline", ThirdPartyRequirements{}, UnconstrainedUse()))
discharge, err := p.MintDischarge(cav, UnconstrainedUse())
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
discharge.Equivalent(discharge)
}
}
func benchmarkPublicKeyDischargeVerification(caching bool, b *testing.B) {
if !caching {
dischargeSignatureCache.disable()
defer dischargeSignatureCache.enable()
}
p, err := CreatePrincipal(newSigner(), nil, nil)
if err != nil {
b.Fatal(err)
}
cav := newCaveat(NewPublicKeyCaveat(p.PublicKey(), "moline", ThirdPartyRequirements{}, UnconstrainedUse()))
discharge, err := p.MintDischarge(cav, UnconstrainedUse())
if err != nil {
b.Fatal(err)
}
ctx, cancel := context.RootContext()
defer cancel()
call := NewCall(&CallParams{
RemoteDischarges: map[string]Discharge{
cav.ThirdPartyDetails().ID(): discharge,
}})
// Validate once for the initial expensive signature validation (not stored in the cache).
if err := cav.Validate(ctx, call); err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := cav.Validate(ctx, call); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkPublicKeyDischargeVerification_Cached(b *testing.B) {
benchmarkPublicKeyDischargeVerification(true, b)
}
func BenchmarkPublicKeyDischargeVerification(b *testing.B) {
benchmarkPublicKeyDischargeVerification(false, b)
}