github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/listener.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  	"errors"
    21  	"net"
    22  
    23  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    24  	"github.com/jlmucb/cloudproxy/go/util"
    25  )
    26  
    27  // A listener implements net.Listener for Tao connections. Each time it accepts
    28  // a connection, it exchanges Tao attestation chains and checks the attestation
    29  // for the certificate of the client against its Guard. The guard in this
    30  // case should be the guard of the Tao domain. This listener allows connections
    31  // from any program that is authorized under the Tao to execute.
    32  type listener struct {
    33  	gl         net.Listener
    34  	guard      Guard
    35  	verifier   *Verifier
    36  	delegation *Attestation
    37  }
    38  
    39  // anonymousListener is like a listener, except it does not require its peer to
    40  // attest to its identity. This provides a one-way authenticated TLS channel for
    41  // anonymous clients to Tao-based services.
    42  type anonymousListener struct {
    43  	listener
    44  }
    45  
    46  // Listen returns a new Tao-based net.Listener that uses the underlying
    47  // crypto/tls net.Listener and a Guard to check whether or not connections
    48  // are authorized.
    49  func Listen(network, laddr string, config *tls.Config, g Guard, v *Verifier, del *Attestation) (net.Listener, error) {
    50  	config.ClientAuth = tls.RequireAnyClientCert
    51  	inner, err := tls.Listen(network, laddr, config)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	return &listener{inner, g, v, del}, nil
    57  }
    58  
    59  // ListenAnonymous returns a new Tao-based net.Listener that does not require
    60  // its peer to attest to its identity.
    61  func ListenAnonymous(network, laddr string, config *tls.Config, g Guard, v *Verifier, del *Attestation) (net.Listener, error) {
    62  	config.ClientAuth = tls.NoClientCert
    63  	inner, err := tls.Listen(network, laddr, config)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	return &anonymousListener{listener{inner, g, v, del}}, nil
    69  }
    70  
    71  // ValidatePeerAttestation checks a Attestation for a given Listener against
    72  // an X.509 certificate from a TLS channel.
    73  func ValidatePeerAttestation(a *Attestation, cert *x509.Certificate, guard Guard) error {
    74  	stmt, err := a.Validate()
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	// Insist that the message of the statement be a SpeaksFor and that the
    80  	// initial term be an auth.Prin of type key. Note that Validate has already
    81  	// checked the expirations and the times and the general well-formedness of
    82  	// the attestation.
    83  	sf, ok := stmt.Message.(auth.Speaksfor)
    84  	if !ok {
    85  		return errors.New("a peer attestation must have an auth.Speaksfor as a message")
    86  	}
    87  
    88  	// This key must contain the serialized X.509 certificate.
    89  	kprin, ok := sf.Delegate.(auth.Prin)
    90  	if !ok {
    91  		return errors.New("a peer attestation must have an auth.Prin as its delegate")
    92  	}
    93  
    94  	if kprin.Type != "key" {
    95  		return errors.New("a peer attestation must have an auth.Prin of type 'key' as its delegate")
    96  	}
    97  
    98  	if _, ok := kprin.KeyHash.(auth.Bytes); !ok {
    99  		return errors.New("a peer attestation must have a KeyHash of type auth.Bytes")
   100  	}
   101  
   102  	prin, ok := sf.Delegator.(auth.Prin)
   103  	if !ok {
   104  		return errors.New("a peer attestation must have an auth.Prin as its delegator")
   105  	}
   106  
   107  	// Ask the Tao Domain if this program is allowed to execute.
   108  	// TODO(tmroeder): the current implementation assumes that the Tao Guard is
   109  	// already able to check authorization of Execute for both programs. In
   110  	// general, this might not be true.
   111  	if !guard.IsAuthorized(prin, "Execute", nil) {
   112  		return errors.New("a principal delegator in a client attestation must be authorized to Execute")
   113  	}
   114  
   115  	// The bytes of the delegate are the result of ToPrincipal on
   116  	// Keys.SigningKey. Check that this represents the same key as the one
   117  	// in the certificate.
   118  	verifier, err := VerifierFromX509(cert)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if !verifier.ToPrincipal().Identical(kprin) {
   123  		return errors.New("a peer attestation must have an auth.Prin.KeyHash of type auth.Bytes where the bytes match the auth.Prin hash representation of the X.509 certificate")
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // Accept waits for a connect, accepts it using the underlying Conn and checks
   130  // the attestations and the statement.
   131  func (l *listener) Accept() (net.Conn, error) {
   132  	c, err := l.gl.Accept()
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	// Tao handshake Protocol:
   138  	// 0. TLS handshake (executed automatically on first message)
   139  	// 1. Client -> Server: Tao delegation for X.509 certificate.
   140  	// 2. Server: checks for a Tao-authorized program.
   141  	// 3. Server -> Client: Tao delegation for X.509 certificate.
   142  	// 4. Client: checks for a Tao-authorized program.
   143  	ms := util.NewMessageStream(c)
   144  	var a Attestation
   145  	if err := ms.ReadMessage(&a); err != nil {
   146  		c.Close()
   147  		return nil, err
   148  	}
   149  
   150  	if err := AddEndorsements(l.guard, &a, l.verifier); err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	peerCert := c.(*tls.Conn).ConnectionState().PeerCertificates[0]
   155  	if err := ValidatePeerAttestation(&a, peerCert, l.guard); err != nil {
   156  		c.Close()
   157  		return nil, err
   158  	}
   159  
   160  	if _, err := ms.WriteMessage(l.delegation); err != nil {
   161  		c.Close()
   162  		return nil, err
   163  	}
   164  
   165  	return c, nil
   166  }
   167  
   168  // Accept waits for a connect, accepts it using the underlying Conn and checks
   169  // the attestations and the statement.
   170  func (l *anonymousListener) Accept() (net.Conn, error) {
   171  	c, err := l.gl.Accept()
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	// One-way Tao handshake Protocol:
   177  	// 0. TLS handshake (executed automatically on first message)
   178  	// 1. Server -> Client: Tao delegation for X.509 certificate.
   179  	// 2. Client: checks for a Tao-authorized program.
   180  	ms := util.NewMessageStream(c)
   181  
   182  	if _, err := ms.WriteMessage(l.delegation); err != nil {
   183  		c.Close()
   184  		return nil, err
   185  	}
   186  
   187  	return c, nil
   188  }
   189  
   190  // Close closes the listener.
   191  // Any blocked Accept operations will be unblocked and return errors.
   192  // This implementation passes the Close operation down to its inner listener.
   193  func (l *listener) Close() error {
   194  	return l.gl.Close()
   195  }
   196  
   197  // Addr returns the listener's network address.
   198  func (l *listener) Addr() net.Addr {
   199  	return l.gl.Addr()
   200  }