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

     1  // Copyright (c) 2014, 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/tls"
    19  	"crypto/x509"
    20  	"crypto/x509/pkix"
    21  	"encoding/pem"
    22  	"errors"
    23  	"fmt"
    24  	"net"
    25  	"time"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    29  	"github.com/jlmucb/cloudproxy/go/util"
    30  )
    31  
    32  // TLS mode client/server
    33  
    34  const (
    35  	x509duration = 24 * time.Hour
    36  	x509keySize  = 2048
    37  )
    38  
    39  // EncodeTLSCert combines a signing key and a certificate in a single tls
    40  // certificate suitable for a TLS config.
    41  func EncodeTLSCert(keys *Keys) (*tls.Certificate, error) {
    42  	if keys.Cert == nil {
    43  		return nil, fmt.Errorf("client: can't encode a nil certificate")
    44  	}
    45  	certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: keys.Cert.Raw})
    46  	keyBytes, err := MarshalSignerDER(keys.SigningKey)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	keyPem := pem.EncodeToMemory(&pem.Block{Type: "ECDSA PRIVATE KEY", Bytes: keyBytes})
    51  
    52  	tlsCert, err := tls.X509KeyPair(certPem, keyPem)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("can't parse cert: %s\n", err.Error())
    55  	}
    56  	return &tlsCert, nil
    57  }
    58  
    59  // generateX509 creates a fresh set of Tao-delegated keys and gets a certificate
    60  // from these keys.
    61  func generateX509() (*Keys, *tls.Certificate, error) {
    62  	keys, err := NewTemporaryTaoDelegatedKeys(Signing, Parent())
    63  	if err != nil {
    64  		return nil, nil, err
    65  	}
    66  
    67  	// TODO(tmroeder): fix the name
    68  	signerAlg := SignerTypeFromSuiteName(TaoCryptoSuite)
    69  	if signerAlg == nil {
    70  		return nil, nil, errors.New("Cant get signer alg from ciphersuite")
    71  	}
    72  	pkInt := PublicKeyAlgFromSignerAlg(*signerAlg)
    73  	skInt := SignatureAlgFromSignerAlg(*signerAlg)
    74  	if pkInt < 0 || skInt < 0 {
    75  		return nil, nil, errors.New("Cant get x509 signer alg from signer alg")
    76  	}
    77  
    78  	cert, err := keys.SigningKey.CreateSelfSignedX509(pkInt, skInt, 1, &pkix.Name{
    79  		Organization: []string{"Google Tao Demo"}})
    80  	if err != nil {
    81  		return nil, nil, err
    82  	}
    83  	// TODO(kwalsh) keys should save cert on disk if keys are on disk
    84  	keys.Cert = cert
    85  	tc, err := EncodeTLSCert(keys)
    86  	return keys, tc, err
    87  }
    88  
    89  // ListenTLS creates a fresh certificate and listens for TLS connections using
    90  // it.
    91  func ListenTLS(network, addr string) (net.Listener, error) {
    92  	_, cert, err := generateX509()
    93  	if err != nil {
    94  		return nil, fmt.Errorf("server: can't create key and cert: %s\n", err.Error())
    95  	}
    96  	return tls.Listen(network, addr, &tls.Config{
    97  		RootCAs:            x509.NewCertPool(),
    98  		Certificates:       []tls.Certificate{*cert},
    99  		InsecureSkipVerify: true,
   100  		ClientAuth:         tls.RequireAnyClientCert,
   101  	})
   102  }
   103  
   104  // DialTLS creates a new X.509 certs from fresh keys and dials a given TLS
   105  // address.
   106  func DialTLS(network, addr string) (net.Conn, error) {
   107  	keys, _, err := generateX509()
   108  	if err != nil {
   109  		return nil, fmt.Errorf("client: can't create key and cert: %s\n", err.Error())
   110  	}
   111  
   112  	return DialTLSWithKeys(network, addr, keys)
   113  }
   114  
   115  // DialTLSWithKeys connects to a TLS server using an existing set of keys.
   116  func DialTLSWithKeys(network, addr string, keys *Keys) (net.Conn, error) {
   117  	tlsCert, err := EncodeTLSCert(keys)
   118  	conn, err := tls.Dial(network, addr, &tls.Config{
   119  		RootCAs:            x509.NewCertPool(),
   120  		Certificates:       []tls.Certificate{*tlsCert},
   121  		InsecureSkipVerify: true,
   122  	})
   123  	return conn, err
   124  }
   125  
   126  // DialWithNewX509 connects to a Tao TLS server, performs a TLS handshake, and
   127  // exchanges Attestation values with the server, checking that this is a Tao
   128  // server that is authorized to Execute. It uses a Tao Guard to perform this
   129  // check.
   130  func DialWithNewX509(network, addr string, guard Guard, v *Verifier) (net.Conn, error) {
   131  	keys, _, err := generateX509()
   132  	if err != nil {
   133  		return nil, fmt.Errorf("client: can't create key and cert: %s\n", err.Error())
   134  	}
   135  
   136  	return Dial(network, addr, guard, v, keys)
   137  }
   138  
   139  // Dial connects to a Tao TLS server, performs a TLS handshake, and verifies
   140  // the Attestation value of the server, checking that the server is authorized
   141  // to execute. If keys are provided (keys!=nil), then it sends an attestation
   142  // of its identity to the peer.
   143  func Dial(network, addr string, guard Guard, v *Verifier, keys *Keys) (net.Conn, error) {
   144  	tlsConfig := &tls.Config{
   145  		RootCAs:            x509.NewCertPool(),
   146  		InsecureSkipVerify: true,
   147  	}
   148  
   149  	// Set up certificate for two-way authentication.
   150  	if keys != nil {
   151  		if keys.Cert == nil {
   152  			return nil, fmt.Errorf("client: can't dial with an empty client certificate\n")
   153  		}
   154  		tlsCert, err := EncodeTLSCert(keys)
   155  		if err != nil {
   156  			return nil, err
   157  		}
   158  		tlsConfig.Certificates = []tls.Certificate{*tlsCert}
   159  	}
   160  
   161  	conn, err := tls.Dial(network, addr, tlsConfig)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	ms := util.NewMessageStream(conn)
   167  
   168  	// Two-way Tao handshake: send client delegation.
   169  	if keys != nil {
   170  		if _, err = ms.WriteMessage(keys.Delegation); err != nil {
   171  			conn.Close()
   172  			return nil, err
   173  		}
   174  	}
   175  
   176  	// Tao handshake: read server delegation.
   177  	var a Attestation
   178  	if err := ms.ReadMessage(&a); err != nil {
   179  		conn.Close()
   180  		return nil, err
   181  	}
   182  
   183  	if err := AddEndorsements(guard, &a, v); err != nil {
   184  		conn.Close()
   185  		return nil, err
   186  	}
   187  
   188  	// Validate the peer certificate according to the guard.
   189  	peerCert := conn.ConnectionState().PeerCertificates[0]
   190  	if err := ValidatePeerAttestation(&a, peerCert, guard); err != nil {
   191  		conn.Close()
   192  		return nil, err
   193  	}
   194  
   195  	return conn, nil
   196  }
   197  
   198  // AddEndorsements reads the SerializedEndorsements in an attestation and adds
   199  // the ones that are predicates signed by a guard's policy key.
   200  func AddEndorsements(guard Guard, a *Attestation, v *Verifier) error {
   201  	// Before validating against the guard, check to see if there are any
   202  	// predicates endorsed by the policy key. This allows truncated principals
   203  	// to get the Tao CA to sign a statement of the form
   204  	// TrustedHash(ext.Program(...)).
   205  	for _, e := range a.SerializedEndorsements {
   206  		var ea Attestation
   207  		if err := proto.Unmarshal(e, &ea); err != nil {
   208  			return err
   209  		}
   210  
   211  		f, err := auth.UnmarshalForm(ea.SerializedStatement)
   212  		if err != nil {
   213  			return err
   214  		}
   215  
   216  		says, ok := f.(auth.Says)
   217  		if !ok {
   218  			return fmt.Errorf("a serialized endorsement must be an auth.Says")
   219  		}
   220  
   221  		// TODO(tmroeder): check that this endorsement hasn't expired.
   222  		pred, ok := says.Message.(auth.Pred)
   223  		if !ok {
   224  			return fmt.Errorf("the message in an endorsement must be a predicate")
   225  		}
   226  
   227  		signerPrin := auth.NewPrin(*ea.SignerType, ea.SignerKey)
   228  
   229  		if !signerPrin.Identical(says.Speaker) {
   230  			return fmt.Errorf("the speaker of an endorsement must be the signer: %v vs %v", signerPrin, says.Speaker)
   231  		}
   232  		if !v.ToPrincipal().Identical(signerPrin) {
   233  			return fmt.Errorf("the signer of an endorsement must be the guard's policy key")
   234  		}
   235  		if ok, err := v.Verify(ea.SerializedStatement, AttestationSigningContext, ea.Signature); (err != nil) || !ok {
   236  			return fmt.Errorf("the signature on an endorsement didn't pass verification")
   237  		}
   238  
   239  		return guard.AddRule(pred.String())
   240  	}
   241  
   242  	return nil
   243  }
   244  
   245  // TruncateAttestation cuts off a delegation chain at its "Program" subprincipal
   246  // extension and replaces its prefix with the given key principal. It also
   247  // returns the PrinExt that represents exactly the program hash.
   248  func TruncateAttestation(kprin auth.Prin, a *Attestation) (auth.Says, auth.PrinExt, error) {
   249  	// This attestation must have a top-level delegation to a key. Return an
   250  	// authorization for this program rooted in the policy key. I don't like
   251  	// this, since it seems like it's much riskier, since this doesn't say
   252  	// anything about the context in which the program is running. Fortunately,
   253  	// local policy rules: if a peer won't accept this cert, then the other
   254  	// program will have to fall back on the longer attestation.
   255  	stmt, err := auth.UnmarshalForm(a.SerializedStatement)
   256  	if err != nil {
   257  		return auth.Says{}, auth.PrinExt{}, err
   258  	}
   259  
   260  	says, ok := stmt.(auth.Says)
   261  	if !ok {
   262  		return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the serialized statement must be a says")
   263  	}
   264  	// Replace the message with one that uses the new principal, taking the last
   265  	// Program subprinicpal, and all its following elements. It should say:
   266  	// policyKey.Program(...)... says key(...) speaksfor
   267  	// policyKey.Program(...)..., signed policyKey.
   268  	sf, ok := says.Message.(auth.Speaksfor)
   269  	if !ok {
   270  		return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the message in the statement must be a speaksfor")
   271  	}
   272  
   273  	delegator, ok := sf.Delegator.(auth.Prin)
   274  	if !ok {
   275  		return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the delegator must be a principal")
   276  	}
   277  
   278  	var prog auth.PrinExt
   279  	found := false
   280  	for _, sprin := range delegator.Ext {
   281  		if !found && (sprin.Name == "Program") {
   282  			found = true
   283  			prog = sprin
   284  		}
   285  
   286  		if found {
   287  			kprin.Ext = append(kprin.Ext, sprin)
   288  		}
   289  	}
   290  
   291  	// TODO(tmroeder): make sure that the delegate is a key and is not, e.g.,
   292  	// the policy key.
   293  	truncSpeaksfor := auth.Speaksfor{
   294  		Delegate:  sf.Delegate,
   295  		Delegator: kprin,
   296  	}
   297  	truncSays := auth.Says{
   298  		Speaker:    kprin,
   299  		Time:       says.Time,
   300  		Expiration: says.Expiration,
   301  		Message:    truncSpeaksfor,
   302  	}
   303  
   304  	return truncSays, prog, nil
   305  }
   306  
   307  // IdenticalDelegations checks to see if two Form values are Says and are
   308  // identical delegations (i.e., the Message must be an auth.Speaksfor).  This
   309  // function is not in the auth package, since it's specific to a particular
   310  // pattern.
   311  func IdenticalDelegations(s, t auth.Form) bool {
   312  	ss, ok := s.(auth.Says)
   313  	if !ok {
   314  		return false
   315  	}
   316  	st, ok := t.(auth.Says)
   317  	if !ok {
   318  		return false
   319  	}
   320  	if !ss.Speaker.Identical(st.Speaker) {
   321  		return false
   322  	}
   323  
   324  	if (ss.Time == nil) != (st.Time == nil) {
   325  		return false
   326  	}
   327  	if (ss.Time != nil) && (*ss.Time != *st.Time) {
   328  		return false
   329  	}
   330  	if (ss.Expiration == nil) != (st.Expiration == nil) {
   331  		return false
   332  	}
   333  	if (ss.Expiration != nil) && (*ss.Expiration != *st.Expiration) {
   334  		return false
   335  	}
   336  
   337  	sfs, ok := ss.Message.(auth.Speaksfor)
   338  	if !ok {
   339  		return false
   340  	}
   341  	sft, ok := ss.Message.(auth.Speaksfor)
   342  	if !ok {
   343  		return false
   344  	}
   345  
   346  	if !sfs.Delegate.Identical(sft.Delegate) || !sfs.Delegator.Identical(sft.Delegator) {
   347  		return false
   348  	}
   349  
   350  	return true
   351  }