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 }