github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/cached_guard_test.go (about)

     1  // Copyright (c) 2015, Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tao
    16  
    17  import (
    18  	"crypto/x509/pkix"
    19  	"fmt"
    20  	"net"
    21  	"os"
    22  	"path"
    23  	"testing"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    27  )
    28  
    29  // TODO(cjpatton) Add a test case to show it fails properly when the rules
    30  // can't be loaded, e.g. when there is no network config.
    31  // TODO(cjaptton) Use t.Error() to log errors instead of t.Fatal() in the case
    32  // that a recoverable error occured.
    33  // TODO(cjpatton) Write request to poll every few seconds until a connection is
    34  // established,
    35  // TODO(cjpatton) Modify CreatePublicCachedDomain() to accept either (network,addr) or a
    36  // net.Conn. Modify this test to use net.Pipe instead of the loopback interface here.
    37  
    38  var password = make([]byte, 32)
    39  var prin = auth.NewKeyPrin([]byte("Alice"))
    40  
    41  func makeTestDomains(configDir, network, addr string, ttl int64) (policy *Domain, public *Domain, err error) {
    42  	password[0] = 1
    43  
    44  	// Create a domain with a Datalog guard and policy keys.
    45  	var policyDomainConfig DomainConfig
    46  	policyDomainConfig.SetDefaults()
    47  	policyDomainConfig.DomainInfo.GuardType = proto.String("Datalog")
    48  	policyDomainConfig.DatalogGuardInfo = &DatalogGuardDetails{
    49  		SignedRulesPath: proto.String("rules"),
    50  	}
    51  	configPath := path.Join(configDir, "tao.config")
    52  
    53  	policy, err = CreateDomain(policyDomainConfig, configPath, password)
    54  	if err != nil {
    55  		return nil, nil, err
    56  	}
    57  
    58  	// Add some bogus rules.
    59  	err = policy.Guard.AddRule(
    60  		`(forall P: forall F: IsFood(F) and IsPerson(P) implies Authorized(P, "eat", F))`)
    61  	if err != nil {
    62  		return nil, nil, err
    63  	}
    64  	if err = policy.Guard.AddRule(fmt.Sprintf(`IsPerson(%v)`, prin)); err != nil {
    65  		return nil, nil, err
    66  	}
    67  	if err = policy.Guard.AddRule(`IsFood("sandwich")`); err != nil {
    68  		return nil, nil, err
    69  	}
    70  
    71  	// Create a public domain with a Cached Datalog guard.
    72  	public, err = policy.CreatePublicCachedDomain(network, addr, ttl)
    73  	if err != nil {
    74  		return nil, nil, err
    75  	}
    76  
    77  	return
    78  }
    79  
    80  func TestCachingDatalogLoad(t *testing.T) {
    81  	network := "tcp"
    82  	addr := "localhost:0"
    83  	ttl := int64(1)
    84  	configDir := "/tmp/domain_test"
    85  
    86  	ch := make(chan bool)
    87  	cal, err := net.Listen(network, addr)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	defer cal.Close()
    92  	addr = cal.Addr().String()
    93  
    94  	policy, _, err := makeTestDomains(configDir, network, addr, ttl)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	defer os.RemoveAll(configDir)
    99  	defer os.RemoveAll(configDir + ".pub")
   100  	public, err := LoadDomain(path.Join(configDir+".pub", "tao.config"), nil)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	go runTCCA(t, cal, policy.Keys, policy.Guard, ch)
   106  
   107  	// This should cause an implicit reload. If the request to the TaoCA fails,
   108  	// IsAuthorized() will return false and not propagate an error.
   109  	if public.Guard.IsAuthorized(prin, "eat", []string{"sandwich"}) == false {
   110  		t.Fatal("IsAuthorized() failed, good rule should have been authorized")
   111  	}
   112  	<-ch
   113  }
   114  
   115  func TestCachingDatalogReload(t *testing.T) {
   116  
   117  	network := "tcp"
   118  	addr := "localhost:0"
   119  	ttl := int64(10)
   120  
   121  	// Run the TaoCA. This handles one request and then exits.
   122  	ch := make(chan bool)
   123  	cal, err := net.Listen(network, addr)
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  	defer cal.Close()
   128  	addr = cal.Addr().String()
   129  
   130  	configDir := "/tmp/domain_test"
   131  	policyDomain, publicDomain, err := makeTestDomains(configDir, network, addr, ttl)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	defer os.RemoveAll(configDir)
   136  	defer os.RemoveAll(configDir + ".pub")
   137  
   138  	// Sanity check.
   139  	if policyDomain.Guard.IsAuthorized(prin, "eat", []string{"sandwich"}) == false {
   140  		t.Fatal("Policy guard IsAuthorized() failed, good rule should have been authorized")
   141  	}
   142  
   143  	go runTCCA(t, cal, policyDomain.Keys, policyDomain.Guard, ch)
   144  
   145  	// Explicitly call Reload(), generating a policy request.
   146  	if err = publicDomain.Guard.(*CachedGuard).Reload(); err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	// Print rules.
   151  	ct := publicDomain.Guard.RuleCount()
   152  	for i := 0; i < ct; i++ {
   153  		t.Logf("rule %d: %s", i, publicDomain.Guard.GetRule(i))
   154  	}
   155  	<-ch
   156  
   157  	// Force Reload() by clearing the guard.
   158  	publicDomain.Guard.Clear()
   159  	go runTCCA(t, cal, policyDomain.Keys, policyDomain.Guard, ch)
   160  
   161  	// This should cause an implicit reload. If the request to the TaoCA fails,
   162  	// IsAuthorized() will return false and not propagate an error.
   163  	if publicDomain.Guard.IsAuthorized(prin, "eat", []string{"sandwich"}) == false {
   164  		t.Fatal("IsAuthorized() failed, good rule should have been authorized")
   165  	}
   166  	<-ch
   167  
   168  	// Simulate time-to-live running out.
   169  	publicDomain.Guard.(*CachedGuard).timeUpdated -= ttl + 1
   170  	go runTCCA(t, cal, policyDomain.Keys, policyDomain.Guard, ch)
   171  
   172  	if publicDomain.Guard.IsAuthorized(prin, "eat", []string{"salad"}) == true {
   173  		t.Fatal("IsAuthorized() succeeded, bad rule should have been denied")
   174  	}
   175  	<-ch
   176  }
   177  
   178  // Test that a client can correctly verify that the server is allowed to
   179  // execute according to the policy. The policy is set up and the policy
   180  // key is used to attest to the identity of the server. The attestation
   181  // includes an endorsement of the service itself. The client verifies the
   182  // endorsement and adds the predicate to the policy before checking it.
   183  func TestCachingDatalogValidatePeerAttestation(t *testing.T) {
   184  	network := "tcp"
   185  	addr := "localhost:0"
   186  	ttl := int64(1)
   187  	tmpDir := "/tmp/domain_test"
   188  
   189  	// Set up the TaoCA.
   190  	ch := make(chan bool)
   191  	cal, err := net.Listen(network, addr)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	defer cal.Close()
   196  	addr = cal.Addr().String()
   197  
   198  	// Set up the policy domain and a public, cached version.
   199  	policy, pub, err := makeTestDomains(tmpDir, network, addr, ttl)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	defer os.RemoveAll(tmpDir)
   204  	defer os.RemoveAll(tmpDir + ".pub")
   205  
   206  	// Set up policy. A key being authorized to execute is of course nonsense;
   207  	// this is only meant to test that ValidatePeerAttestation() properly adds
   208  	// the endoresement to the policy.
   209  	rule := "(forall K: TrustedKey(K) implies Authorized(K, \"Execute\"))"
   210  	if err := policy.Guard.AddRule(rule); err != nil {
   211  		t.Errorf("could not add rule : %s", err)
   212  		return
   213  	}
   214  
   215  	// Generate a set of keys for the Tao-delegated server.
   216  	k, err := NewTemporaryTaoDelegatedKeys(Signing|Crypting|Deriving, nil)
   217  	if err != nil {
   218  		t.Error("failed to generate keys:", err)
   219  		return
   220  	}
   221  	k.dir = tmpDir
   222  
   223  	// Generate an attesation of the statements: "k.VerifyingKey speaks for
   224  	// key(K)" and "TrustedKey(key(K))" signed by the policy key and set to
   225  	// k.Delegation.
   226  	prin := auth.NewKeyPrin([]byte("This is a terrible key."))
   227  
   228  	pred := auth.Pred{
   229  		Name: "TrustedKey",
   230  		Arg:  []auth.Term{prin},
   231  	}
   232  
   233  	sf := auth.Speaksfor{
   234  		Delegate:  k.SigningKey.ToPrincipal(),
   235  		Delegator: prin,
   236  	}
   237  
   238  	stmt := auth.Says{
   239  		Speaker:    policy.Keys.SigningKey.ToPrincipal(),
   240  		Time:       nil,
   241  		Expiration: nil,
   242  		Message:    sf,
   243  	}
   244  
   245  	if k.Delegation, err = GenerateAttestation(policy.Keys.SigningKey, nil, stmt); err != nil {
   246  		t.Error("failed to attest to speaksfor:", err)
   247  		return
   248  	}
   249  
   250  	e := auth.Says{
   251  		Speaker: policy.Keys.SigningKey.ToPrincipal(),
   252  		Message: pred,
   253  	}
   254  
   255  	ea, err := GenerateAttestation(policy.Keys.SigningKey, nil, e)
   256  	if err != nil {
   257  		t.Error("failed to attest to endorsement:", err)
   258  		return
   259  	}
   260  
   261  	eab, err := proto.Marshal(ea)
   262  	if err != nil {
   263  		t.Error("failed to marshal attested endorsement:", err)
   264  		return
   265  	}
   266  	k.Delegation.SerializedEndorsements = [][]byte{eab}
   267  
   268  	// Generate an x509 certificate for the Tao-delegated server.
   269  	signerAlg := SignerTypeFromSuiteName(TaoCryptoSuite)
   270  	if signerAlg == nil {
   271  		t.Error("Cant get signer alg from ciphersuite")
   272  	}
   273  	pkInt := PublicKeyAlgFromSignerAlg(*signerAlg)
   274  	skInt := SignatureAlgFromSignerAlg(*signerAlg)
   275  	if pkInt < 0 || skInt < 0 {
   276  		t.Error("Cant get x509 signer alg from signer alg")
   277  	}
   278  	k.Cert, err = k.SigningKey.CreateSelfSignedX509(pkInt, skInt, 1,
   279  		&pkix.Name{Organization: []string{"Identity of some Tao service"}})
   280  	if err != nil {
   281  		t.Error("failed to generate x509 certificate:", err)
   282  		return
   283  	}
   284  
   285  	// Run the TaoCA. This handles one request and then exits.
   286  	go runTCCA(t, cal, policy.Keys, policy.Guard, ch)
   287  
   288  	// Add any verified predicates to the policy. This will cause a
   289  	// policy query to the TaoCA.
   290  	if err = AddEndorsements(pub.Guard, k.Delegation, pub.Keys.VerifyingKey); err != nil {
   291  		t.Error("failed to add endorsements:", err)
   292  		t.Errorf("pub verifier key is %v\n", pub.Keys.VerifyingKey.ToPrincipal())
   293  		t.Errorf("policy ssigning key  is %v\n", policy.Keys.SigningKey.ToPrincipal())
   294  		t.Errorf("k signing key is %v\n", k.SigningKey.ToPrincipal())
   295  		return
   296  	}
   297  
   298  	<-ch
   299  
   300  	// Finally, the client verifies the Tao-delegated server is allowed to
   301  	// execute.
   302  	if err = ValidatePeerAttestation(k.Delegation, k.Cert, pub.Guard); err != nil {
   303  		t.Error("failed to verity attestation:", err)
   304  	}
   305  }