github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/apps/mixnet/directory.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 mixnet
    16  
    17  import (
    18  	"crypto/tls"
    19  	"crypto/x509"
    20  	"crypto/x509/pkix"
    21  	"errors"
    22  	"io"
    23  	"log"
    24  	"net"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/golang/glog"
    29  	"github.com/golang/protobuf/proto"
    30  	"github.com/jlmucb/cloudproxy/go/tao"
    31  )
    32  
    33  type DirectoryContext struct {
    34  	keys     *tao.Keys     // Signing keys of this hosted program.
    35  	domain   *tao.Domain   // Policy guard and public key.
    36  	listener net.Listener  // Socket where server listens for proxies/routers
    37  	network  string        // Network protocol, e.g. "tcp"
    38  	timeout  time.Duration // Timeout on read/write/dial.
    39  
    40  	dirLock    *sync.Mutex
    41  	directory  []string // List of online servers
    42  	serverKeys [][]byte // NaCL keys
    43  }
    44  
    45  func NewDirectoryContext(path, network, addr string, timeout time.Duration,
    46  	x509Identity *pkix.Name, t tao.Tao) (*DirectoryContext, error) {
    47  	dc := new(DirectoryContext)
    48  	var err error
    49  	// Generate keys and get attestation from parent.
    50  	if dc.keys, err = tao.NewTemporaryTaoDelegatedKeys(tao.Signing|tao.Crypting, t); err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	// Create a certificate.
    55  	pkInt := tao.PublicKeyAlgFromSignerAlg(*dc.keys.SigningKey.Header.KeyType)
    56  	sigInt := tao.SignatureAlgFromSignerAlg(*dc.keys.SigningKey.Header.KeyType)
    57  	dc.keys.Cert, err = dc.keys.SigningKey.CreateSelfSignedX509(pkInt, sigInt, int64(1), x509Identity)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	// Load domain from local configuration.
    63  	if dc.domain, err = tao.LoadDomain(path, nil); err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	// Encode TLS certificate.
    68  	cert, err := tao.EncodeTLSCert(dc.keys)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	tlsConfig := &tls.Config{
    74  		RootCAs:            x509.NewCertPool(),
    75  		Certificates:       []tls.Certificate{*cert},
    76  		InsecureSkipVerify: true,
    77  		ClientAuth:         tls.RequestClientCert,
    78  	}
    79  
    80  	if dc.listener, err = Listen(network, addr, tlsConfig,
    81  		dc.domain.Guard, dc.domain.Keys.VerifyingKey, dc.keys.Delegation); err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	dc.network = network
    86  	dc.timeout = timeout
    87  
    88  	dc.dirLock = new(sync.Mutex)
    89  	dc.directory = nil
    90  
    91  	return dc, nil
    92  }
    93  
    94  func (dc *DirectoryContext) Accept() (net.Conn, error) {
    95  	c, err := dc.listener.Accept()
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	go dc.handleConn(c, len(c.(*tls.Conn).ConnectionState().PeerCertificates) > 0)
   100  	return c, nil
   101  }
   102  
   103  func (dc *DirectoryContext) handleConn(c net.Conn, fromRouter bool) {
   104  	msg := make([]byte, MaxMsgBytes+1)
   105  	n, err := c.Read(msg)
   106  	if err == io.EOF {
   107  		return
   108  	} else if err != nil {
   109  		errMsg := &DirectoryMessage{
   110  			Type:  DirectoryMessageType_DIRERROR.Enum(),
   111  			Error: proto.String(err.Error()),
   112  		}
   113  		ret, err := proto.Marshal(errMsg)
   114  		if err != nil {
   115  			glog.Error(err)
   116  		}
   117  		c.Write(ret)
   118  	} else if n > MaxMsgBytes {
   119  		errMsg := &DirectoryMessage{
   120  			Type:  DirectoryMessageType_DIRERROR.Enum(),
   121  			Error: proto.String("Too many bytes in this message"),
   122  		}
   123  		ret, err := proto.Marshal(errMsg)
   124  		if err != nil {
   125  			glog.Error(err)
   126  		}
   127  		c.Write(ret)
   128  	}
   129  
   130  	var dm DirectoryMessage
   131  	if err = proto.Unmarshal(msg[:n], &dm); err != nil {
   132  		errMsg := &DirectoryMessage{
   133  			Type:  DirectoryMessageType_DIRERROR.Enum(),
   134  			Error: proto.String(err.Error()),
   135  		}
   136  		ret, err := proto.Marshal(errMsg)
   137  		if err != nil {
   138  			glog.Error(err)
   139  		}
   140  		c.Write(ret)
   141  	}
   142  
   143  	dc.dirLock.Lock()
   144  	defer dc.dirLock.Unlock()
   145  	if *dm.Type == DirectoryMessageType_REGISTER {
   146  		log.Println("Registering", dm.Addrs)
   147  		if fromRouter {
   148  			dc.directory = append(dc.directory, dm.Addrs...)
   149  			dc.serverKeys = append(dc.serverKeys, dm.Keys...)
   150  		}
   151  		_, err = c.Write([]byte{0}) // Indicate it was successfully written
   152  		if err != nil {
   153  			glog.Error(err)
   154  		}
   155  	} else if *dm.Type == DirectoryMessageType_DELETE {
   156  		log.Println("Deleting", dm.Addrs)
   157  		if fromRouter {
   158  			for _, addr := range dm.Addrs {
   159  				for i := range dc.directory {
   160  					if addr == dc.directory[i] {
   161  						dc.directory[i] = dc.directory[len(dc.directory)-1]
   162  						dc.directory = dc.directory[:len(dc.directory)-1]
   163  						dc.serverKeys[i] = dc.serverKeys[len(dc.serverKeys)-1]
   164  						dc.serverKeys = dc.serverKeys[:len(dc.serverKeys)-1]
   165  						break
   166  					}
   167  				}
   168  			}
   169  		}
   170  		_, err = c.Write([]byte{0}) // Indicate it was successfully written
   171  		if err != nil {
   172  			glog.Error(err)
   173  		}
   174  	} else if *dm.Type == DirectoryMessageType_LIST {
   175  		result := &DirectoryMessage{
   176  			Type:  DirectoryMessageType_DIRECTORY.Enum(),
   177  			Addrs: dc.directory,
   178  			Keys:  dc.serverKeys,
   179  		}
   180  		ret, err := proto.Marshal(result)
   181  		if err != nil {
   182  			glog.Error(err)
   183  		}
   184  
   185  		n, err := c.Write(ret)
   186  		if err != nil {
   187  			glog.Error(err)
   188  		} else if n != len(ret) {
   189  			glog.Error("Could not send back all of the directory")
   190  		}
   191  	}
   192  }
   193  
   194  func (dc *DirectoryContext) Close() {
   195  	if dc.listener != nil {
   196  		dc.listener.Close()
   197  	}
   198  }
   199  
   200  func RegisterRouter(c net.Conn, addrs []string, keys [][]byte) error {
   201  	dm := &DirectoryMessage{
   202  		Type:  DirectoryMessageType_REGISTER.Enum(),
   203  		Addrs: addrs,
   204  		Keys:  keys,
   205  	}
   206  	b, err := proto.Marshal(dm)
   207  	if err != nil {
   208  		return err
   209  	}
   210  	n, err := c.Write(b)
   211  	if err != nil {
   212  		return err
   213  	} else if n != len(b) {
   214  		return errors.New("Couldn't write the whole request")
   215  	}
   216  	c.Read([]byte{0})
   217  	return nil
   218  }
   219  
   220  func GetDirectory(c net.Conn) ([]string, [][]byte, error) {
   221  	dm := &DirectoryMessage{
   222  		Type: DirectoryMessageType_LIST.Enum(),
   223  	}
   224  	b, err := proto.Marshal(dm)
   225  	if err != nil {
   226  		return nil, nil, err
   227  	}
   228  	n, err := c.Write(b)
   229  	if err != nil {
   230  		return nil, nil, err
   231  	} else if n != len(b) {
   232  		return nil, nil, errors.New("Couldn't write the whole request")
   233  	}
   234  
   235  	msg := make([]byte, MaxMsgBytes+1)
   236  	n, err = c.Read(msg)
   237  	if err != nil {
   238  		return nil, nil, err
   239  	} else if n > MaxMsgBytes {
   240  		return nil, nil, errors.New("Couldn't read the whole response")
   241  	}
   242  
   243  	var dir DirectoryMessage
   244  	if err = proto.Unmarshal(msg[:n], &dir); err != nil {
   245  		return nil, nil, err
   246  	}
   247  
   248  	return dir.Addrs, dir.Keys, err
   249  }