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

     1  // Copyright (c) 2014, Kevin Walsh.  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  // This provides client stubs for the Tao interface. This code is (mostly)
    18  // extremely dull and, ideally, would be generated automatically.
    19  
    20  import (
    21  	"errors"
    22  	"io"
    23  	"math"
    24  	"net/rpc"
    25  	"strings"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    29  	"github.com/jlmucb/cloudproxy/go/util"
    30  	"github.com/jlmucb/cloudproxy/go/util/protorpc"
    31  )
    32  
    33  // RPC sends requests between this hosted program and the host Tao.
    34  type RPC struct {
    35  	rpc         *rpc.Client
    36  	serviceName string
    37  }
    38  
    39  // DeserializeRPC produces a RPC from a string.
    40  func DeserializeRPC(s string) (*RPC, error) {
    41  	if s == "" {
    42  		return nil, newError("taorpc: missing host Tao spec" +
    43  			" (ensure $" + HostSpecEnvVar + " is set)")
    44  	}
    45  	r := strings.TrimPrefix(s, "tao::RPC+")
    46  	if r == s {
    47  		return nil, newError("taorpc: unrecognized $" + HostSpecEnvVar + " string " + s)
    48  	}
    49  	ms, err := util.DeserializeFDMessageStream(r)
    50  	if err != nil {
    51  		return nil, newError("taorpc: unrecognized $" + HostSpecEnvVar + " string " + s +
    52  			" (" + err.Error() + ")")
    53  	}
    54  	return &RPC{protorpc.NewClient(ms), "Tao"}, nil
    55  }
    56  
    57  // DeserializeFileRPC produces a RPC from a string representing a file.
    58  func DeserializeFileRPC(s string) (*RPC, error) {
    59  	if s == "" {
    60  		return nil, newError("taorpc: missing host Tao spec" +
    61  			" (ensure $" + HostSpecEnvVar + " is set)")
    62  	}
    63  	r := strings.TrimPrefix(s, "tao::RPC+")
    64  	if r == s {
    65  		return nil, newError("taorpc: unrecognized $" + HostSpecEnvVar + " string " + s)
    66  	}
    67  	ms, err := util.DeserializeFileMessageStream(r)
    68  	if err != nil {
    69  		return nil, newError("taorpc: unrecognized $" + HostSpecEnvVar + " string " + s +
    70  			" (" + err.Error() + ")")
    71  	}
    72  	return &RPC{protorpc.NewClient(ms), "Tao"}, nil
    73  }
    74  
    75  // DeserializeUnixSocketRPC produces a RPC from a path string.
    76  func DeserializeUnixSocketRPC(p string) (*RPC, error) {
    77  	if p == "" {
    78  		return nil, newError("taorpc: missing host Tao spec" +
    79  			" (ensure $" + HostSpecEnvVar + " is set)")
    80  	}
    81  
    82  	ms, err := util.DeserializeUnixSocketMessageStream(p)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	return &RPC{protorpc.NewClient(ms), "Tao"}, nil
    88  }
    89  
    90  // NewRPC constructs a RPC for the default gob encoding rpc client using
    91  // an io.ReadWriteCloser.
    92  func NewRPC(rwc io.ReadWriteCloser, serviceName string) (*RPC, error) {
    93  	return &RPC{rpc.NewClient(rwc), serviceName}, nil
    94  }
    95  
    96  type expectedResponse int
    97  
    98  const (
    99  	wantNothing expectedResponse = 0
   100  	wantData    expectedResponse = 1 << iota
   101  	wantPolicy
   102  	wantLabel
   103  	wantCounter
   104  )
   105  
   106  // An ErrMalformedResponse is returned as an error for an invalid response.
   107  var ErrMalformedResponse = errors.New("taorpc: malformed response")
   108  
   109  // call issues an rpc request, obtains the response, checks the response for
   110  // errors, and checks that the response contains exactly the expected values.
   111  func (t *RPC) call(method string, r *RPCRequest, e expectedResponse) (data []byte, policy string,
   112  	counter int64, err error) {
   113  	s := new(RPCResponse)
   114  	err = t.rpc.Call(method, r, s)
   115  	if err != nil {
   116  		return
   117  	}
   118  	if (s.Data != nil) != (e&wantData != 0) ||
   119  		(s.Policy != nil) != (e&wantPolicy != 0) {
   120  		err = ErrMalformedResponse
   121  		return
   122  	}
   123  	if s.Data != nil {
   124  		data = s.Data
   125  	}
   126  	if s.Policy != nil {
   127  		policy = *s.Policy
   128  	}
   129  	if s.Counter != nil {
   130  		counter = *s.Counter
   131  	}
   132  	return
   133  }
   134  
   135  // GetTaoName implements part of the Tao interface.
   136  func (t *RPC) GetTaoName() (auth.Prin, error) {
   137  	r := &RPCRequest{}
   138  	data, _, _, err := t.call(t.serviceName+".GetTaoName", r, wantData)
   139  	if err != nil {
   140  		return auth.Prin{}, err
   141  	}
   142  	return auth.UnmarshalPrin(data)
   143  }
   144  
   145  // ExtendTaoName implements part of the Tao interface.
   146  func (t *RPC) ExtendTaoName(subprin auth.SubPrin) error {
   147  	r := &RPCRequest{Data: auth.Marshal(subprin)}
   148  	_, _, _, err := t.call(t.serviceName+".ExtendTaoName", r, wantNothing)
   149  	return err
   150  }
   151  
   152  type taoRandReader RPC
   153  
   154  // Read implements part of the Tao interface.
   155  func (t *taoRandReader) Read(p []byte) (n int, err error) {
   156  	bytes, err := (*RPC)(t).GetRandomBytes(len(p))
   157  	if err != nil {
   158  		return 0, err
   159  	}
   160  	copy(p, bytes)
   161  	return len(p), nil
   162  }
   163  
   164  // TODO(kwalsh) Can Rand be made generic, or does it need to be defined for the
   165  // concrete type RPC?
   166  
   167  // Rand implements part of the Tao interface.
   168  func (t *RPC) Rand() io.Reader {
   169  	return (*taoRandReader)(t)
   170  }
   171  
   172  // GetRandomBytes implements part of the Tao interface.
   173  func (t *RPC) GetRandomBytes(n int) ([]byte, error) {
   174  	if n > math.MaxUint32 {
   175  		return nil, newError("taorpc: request for too many random bytes")
   176  	}
   177  	r := &RPCRequest{Size: proto.Int32(int32(n))}
   178  	bytes, _, _, err := t.call(t.serviceName+".GetRandomBytes", r, wantData)
   179  	return bytes, err
   180  }
   181  
   182  // GetSharedSecret implements part of the Tao interface.
   183  func (t *RPC) GetSharedSecret(n int, policy string) ([]byte, error) {
   184  	if n > math.MaxUint32 {
   185  		return nil, newError("taorpc: request for too many secret bytes")
   186  	}
   187  	r := &RPCRequest{Size: proto.Int32(int32(n)), Policy: proto.String(policy)}
   188  	bytes, _, _, err := t.call(t.serviceName+".GetSharedSecret", r, wantData)
   189  	return bytes, err
   190  }
   191  
   192  // Attest implements part of the Tao interface.
   193  func (t *RPC) Attest(issuer *auth.Prin, time, expiration *int64, message auth.Form) (*Attestation, error) {
   194  	var issuerBytes []byte
   195  	if issuer != nil {
   196  		issuerBytes = auth.Marshal(*issuer)
   197  	}
   198  	r := &RPCRequest{
   199  		Issuer:     issuerBytes,
   200  		Time:       time,
   201  		Expiration: expiration,
   202  		Data:       auth.Marshal(message),
   203  	}
   204  	bytes, _, _, err := t.call(t.serviceName+".Attest", r, wantData)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	var a Attestation
   209  	err = proto.Unmarshal(bytes, &a)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	return &a, nil
   214  }
   215  
   216  // Seal implements part of the Tao interface.
   217  func (t *RPC) Seal(data []byte, policy string) (sealed []byte, err error) {
   218  	r := &RPCRequest{Data: data, Policy: proto.String(policy)}
   219  	sealed, _, _, err = t.call(t.serviceName+".Seal", r, wantData)
   220  	return
   221  }
   222  
   223  // Unseal implements part of the Tao interface.
   224  func (t *RPC) Unseal(sealed []byte) (data []byte, policy string, err error) {
   225  	r := &RPCRequest{Data: sealed}
   226  	data, policy, _, err = t.call(t.serviceName+".Unseal", r, wantData|wantPolicy)
   227  	return
   228  }
   229  
   230  func (t *RPC) InitCounter(label string, c int64) (err error) {
   231  	r := &RPCRequest{Label: &label, Counter: &c}
   232  	_, _, _, err = t.call(t.serviceName+".InitCounter", r, wantNothing)
   233  	return
   234  }
   235  
   236  func (t *RPC) GetCounter(label string) (c int64, err error) {
   237  	r := &RPCRequest{Label: &label}
   238  	_, _, c, err = t.call(t.serviceName+".GetCounter", r, wantCounter)
   239  	return
   240  }
   241  
   242  func (t *RPC) RollbackProtectedSeal(label string, data []byte, policy string) (sealed []byte, err error) {
   243  	r := &RPCRequest{Label: &label, Data: data, Policy: &policy}
   244  	sealed, _, _, err = t.call(t.serviceName+".RollbackProtectedSeal", r, wantData)
   245  	return
   246  }
   247  
   248  func (t *RPC) RollbackProtectedUnseal(sealed []byte) (data []byte, policy string, err error) {
   249  	r := &RPCRequest{Data: sealed}
   250  	data, policy, _, err = t.call(t.serviceName+".RollbackProtectedUnseal", r, wantData|wantPolicy)
   251  	return
   252  }