github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/support_libraries/secret_disclosure_support/secret_disclosure.go (about)

     1  // Copyright (c) 2016, 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 secret_disclosure contains functions which create, interpret and verify
    16  // secret disclosure directives of the following form:
    17  // 'PolicyKey/DelegatorProgram says DelegateProgram can Read/Write/Create/Delete/Own ProtectedObjectId'
    18  
    19  package secret_disclosure
    20  
    21  import (
    22  	"bytes"
    23  	"crypto/x509"
    24  	"errors"
    25  
    26  	"github.com/golang/protobuf/proto"
    27  	po "github.com/jlmucb/cloudproxy/go/support_libraries/protected_objects"
    28  	"github.com/jlmucb/cloudproxy/go/tao"
    29  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    30  )
    31  
    32  const (
    33  	SigningContext  = "Policy Secret Disclosure Directive Signature"
    34  	ReadPredicate   = "Read"
    35  	WritePredicate  = "Write"
    36  	CreatePredicate = "Create"
    37  	DeletePredicate = "Delete"
    38  	OwnPredicate    = "Own"
    39  )
    40  
    41  func ProcessDirectiveAndUpdateGuard(domain *tao.Domain, directive *DirectiveMessage) error {
    42  	delegator, delegate, pred, pObj, err := VerifySecretDisclosureDirective(domain.Keys, directive)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	if domain.Guard.IsAuthorized(*delegate, *pred, []string{pObj.String()}) {
    47  		return nil
    48  	}
    49  	if !domain.Guard.IsAuthorized(*delegator, OwnPredicate, []string{pObj.String()}) {
    50  		return errors.New("speaker of directive is not owner of object")
    51  	}
    52  	return domain.Guard.Authorize(*delegate, *pred, []string{pObj.String()})
    53  
    54  }
    55  
    56  // This function returns a secret disclosure directive signed by key with the statement:
    57  // 'delegator says delegate predicate protectedObjectId'.
    58  func CreateSecretDisclosureDirective(key *tao.Keys, delegator, delegate *auth.Prin,
    59  	predicate string, protectedObjId *po.ObjectIdMessage) (*DirectiveMessage, error) {
    60  
    61  	// Construct serialized 'says' statement.
    62  	serializedObjId, err := proto.Marshal(protectedObjId)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	pred := auth.MakePredicate(predicate, *delegate, serializedObjId)
    67  	statement := auth.Says{
    68  		Speaker:    *delegator,
    69  		Time:       nil, // TODO: For now, time and exp not implemented.
    70  		Expiration: nil,
    71  		Message:    pred,
    72  	}
    73  	serializedStatement := auth.Marshal(statement)
    74  
    75  	// Sign serialized statement.
    76  	signature, err := key.SigningKey.Sign(serializedStatement, SigningContext)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	// Construct and return directive.
    82  	directive := &DirectiveMessage{
    83  		Type:                DirectiveMessage_SECRET_DISCLOSURE.Enum(),
    84  		SerializedStatement: serializedStatement,
    85  		Signature:           signature,
    86  		Signer:              auth.Marshal(key.SigningKey.ToPrincipal()),
    87  		Cert:                key.Cert.Raw,
    88  	}
    89  	return directive, nil
    90  }
    91  
    92  // This function performs the following checks on a secret disclosure directive.
    93  // (1) the directive signature is valid with respect to signerKey of directive
    94  // (2) Either
    95  //       - policyKey matches the signerKey of directive
    96  //       - directive cert is a valid program cert (signed by policyKey) certifying the signerKey
    97  //         of directive as belonging to 'delegator'
    98  // (3) the directive message is a statement of the form:
    99  //         'policyKey/'delegator' says delegate can read protectedObjectId'
   100  //     where delegate is a Tao Principal and protectedObjectId is a (serialized) protected
   101  //     object message id.
   102  func VerifySecretDisclosureDirective(policyKey *tao.Keys, directive *DirectiveMessage) (*auth.Prin,
   103  	*auth.Prin, *string, *po.ObjectIdMessage, error) {
   104  
   105  	// Check type of directive
   106  	if directive.Type == nil || *(directive.Type) != DirectiveMessage_SECRET_DISCLOSURE {
   107  		return nil, nil, nil, nil, errors.New(
   108  			"secret_disclosure: directive not of secret disclosure type.")
   109  	}
   110  
   111  	var verifier *tao.Verifier
   112  	var delegatorStr string
   113  	// Check directive signer matches policy key.
   114  	if bytes.Compare(
   115  		auth.Marshal(policyKey.SigningKey.ToPrincipal()), directive.GetSigner()) == 0 {
   116  		verifier = policyKey.SigningKey.GetVerifierFromSigner()
   117  		delegatorStr = verifier.ToPrincipal().String()
   118  
   119  	} else {
   120  		// Check if program cert is valid, signed by policy key,
   121  		// cert public key matches signer and cert name matches speaker
   122  		// of says statement.
   123  		cert, err := x509.ParseCertificate(directive.Cert)
   124  		if err != nil {
   125  			return nil, nil, nil, nil, errors.New(
   126  				"error parsing directive program cert")
   127  		}
   128  		rootCert := x509.NewCertPool()
   129  		rootCert.AddCert(policyKey.Cert)
   130  		verifyOptions := x509.VerifyOptions{Roots: rootCert}
   131  		_, err = cert.Verify(verifyOptions)
   132  		if err != nil {
   133  			return nil, nil, nil, nil, errors.New(
   134  				"program cert not valid")
   135  		}
   136  		verifier, err = tao.VerifierFromX509(cert)
   137  		delegatorStr = cert.Subject.CommonName
   138  		if err != nil {
   139  			return nil, nil, nil, nil, err
   140  		}
   141  		if bytes.Compare(auth.Marshal(verifier.ToPrincipal()), directive.GetSigner()) != 0 {
   142  			return nil, nil, nil, nil, errors.New(
   143  				"secret_disclosure: directive signer doesn't match program key.")
   144  		}
   145  	}
   146  
   147  	// Verify signature.
   148  	ok, err := verifier.Verify(directive.GetSerializedStatement(), SigningContext,
   149  		directive.GetSignature())
   150  	if err != nil {
   151  		return nil, nil, nil, nil, err
   152  	}
   153  	if !ok {
   154  		return nil, nil, nil, nil,
   155  			errors.New("secret_disclosure: directive signature check failed.")
   156  	}
   157  
   158  	// Validate and return statement.
   159  	statement, err := auth.UnmarshalForm(directive.GetSerializedStatement())
   160  	if err != nil {
   161  		return nil, nil, nil, nil, err
   162  	}
   163  	var saysStatement *auth.Says
   164  	if ptr, ok := statement.(*auth.Says); ok {
   165  		saysStatement = ptr
   166  	} else if val, ok := statement.(auth.Says); ok {
   167  		saysStatement = &val
   168  	} else {
   169  		return nil, nil, nil, nil,
   170  			errors.New("secret_disclosure: directive statement not a 'Says'")
   171  	}
   172  	stmtSpeaker, ok := saysStatement.Speaker.(auth.Prin)
   173  	if !ok {
   174  		return nil, nil, nil, nil,
   175  			errors.New("secret_disclosure: directive speaker not a 'Prin'")
   176  	}
   177  	if stmtSpeaker.String() != delegatorStr {
   178  		return nil, nil, nil, nil, errors.New(
   179  			"secret_disclosure: directive statement speaker does not match signer")
   180  	}
   181  	pred, ok := saysStatement.Message.(auth.Pred)
   182  	if !ok {
   183  		return nil, nil, nil, nil,
   184  			errors.New("secret_disclosure: directive message not a 'Pred'")
   185  	}
   186  	predName := pred.Name
   187  	if predName == "" {
   188  		return nil, nil, nil, nil,
   189  			errors.New("secret_disclosure: directive predicate name is empty")
   190  	}
   191  	if len(pred.Arg) != 2 {
   192  		return nil, nil, nil, nil,
   193  			errors.New("secret_disclosure: directive predicate doesn't have 2 terms")
   194  	}
   195  	delegateName, ok := pred.Arg[0].(auth.Prin)
   196  	if !ok {
   197  		return nil, nil, nil, nil, errors.New(
   198  			"secret_disclosure: directive delegateName Term not of type auth.Prin.")
   199  	}
   200  	serializedObjId, ok := pred.Arg[1].(auth.Bytes)
   201  	if !ok {
   202  		return nil, nil, nil, nil, errors.New(
   203  			"secret_disclosure: directive ObjId Term not of type []byte.")
   204  	}
   205  	protectedObjId := po.ObjectIdMessage{}
   206  	err = proto.Unmarshal(serializedObjId, &protectedObjId)
   207  	if err != nil {
   208  		return nil, nil, nil, nil, errors.New(
   209  			"secret_disclosure: error deserializing protected ObjId.")
   210  	}
   211  	return &stmtSpeaker, &delegateName, &predName, &protectedObjId, nil
   212  }