├── .gitignore ├── LICENSE ├── README.md ├── aes ├── aes.go └── aes_test.go ├── cell.go ├── cellbuf.go ├── cellv3.go ├── cellv4.go ├── circuit.go ├── cmdrouter.go ├── config.go ├── connectionhint.go ├── create.go ├── debug.go ├── destroy.go ├── dns.go ├── error.go ├── exitpolicy.go ├── extend.go ├── handshake.go ├── hybrid.go ├── kdf.go ├── kdf_test.go ├── main.go ├── onionconnection.go ├── or.go ├── proto_definitions.go ├── rand.go ├── relay.go ├── relaycell.go ├── relaydata.go ├── sha1 ├── README ├── example_test.go ├── sha1.go ├── sha1_test.go ├── sha1block.go ├── sha1block_386.s ├── sha1block_amd64.s ├── sha1block_amd64p32.s ├── sha1block_arm.s ├── sha1block_decl.go ├── sha1block_generic.go └── textflag.h ├── stats.go ├── stream.go ├── streamcontrol.go ├── streamdata.go ├── tls.go ├── tordir ├── descriptor.go └── descriptor_test.go └── window.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | gotor 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, The GoTor Authors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GoTor is my attempt at implementing a full Tor relay in the Go language. I ended up dropping the project, but a full writeup can be found [on my blog](http://www.tvdw.eu/blog/2015/01/24/implementing-a-tor-relay-from-scratch/). 2 | 3 | The code is licensed under the BSD 3-clause license, see the file called 'LICENSE'. 4 | 5 | **Please do not use this code on a production relay. It is insecure, unstable, and potentially harmful to the network.** 6 | -------------------------------------------------------------------------------- /aes/aes.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package aes 6 | 7 | // #cgo pkg-config: libssl 8 | // #include 9 | import "C" 10 | 11 | import ( 12 | "errors" 13 | "github.com/tvdw/cgolock" 14 | "runtime" 15 | ) 16 | 17 | type Cipher interface { 18 | Crypt(source, target []byte) ([]byte, error) 19 | } 20 | 21 | type cipher struct { 22 | evp C.EVP_CIPHER_CTX 23 | } 24 | 25 | func New(key, iv []byte) Cipher { 26 | c := &cipher{} 27 | cgolock.Lock() 28 | defer cgolock.Unlock() 29 | 30 | C.EVP_CIPHER_CTX_init(&c.evp) 31 | runtime.SetFinalizer(c, func(c *cipher) { 32 | C.EVP_CIPHER_CTX_cleanup(&c.evp) 33 | }) 34 | 35 | C.EVP_EncryptInit_ex(&c.evp, C.EVP_aes_128_ctr(), nil, (*C.uchar)(&key[0]), (*C.uchar)(&iv[0])) 36 | 37 | return c 38 | } 39 | 40 | func (c *cipher) Crypt(source, target []byte) ([]byte, error) { 41 | if len(source) > cap(target) { 42 | return nil, errors.New("aes: target must be at least as long as the source") 43 | } 44 | 45 | var outl C.int 46 | cgolock.Lock() 47 | C.EVP_EncryptUpdate(&c.evp, (*C.uchar)(&target[0]), &outl, (*C.uchar)(&source[0]), C.int(len(source))) 48 | cgolock.Unlock() 49 | 50 | return target[:int(outl)], nil 51 | } 52 | -------------------------------------------------------------------------------- /aes/aes_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package aes 6 | 7 | import ( 8 | "github.com/tvdw/cgolock" 9 | "runtime" 10 | "testing" 11 | ) 12 | 13 | func init() { 14 | cgolock.Init(runtime.GOMAXPROCS(0)) 15 | } 16 | 17 | func benchmarkWithSize(size int, b *testing.B) { 18 | buffer := make(chan []byte, 50000) 19 | for i := 0; i < cap(buffer); i++ { 20 | buffer <- make([]byte, size) 21 | } 22 | 23 | b.SetBytes(int64(size)) 24 | b.RunParallel(func(pb *testing.PB) { 25 | var key, iv [16]byte 26 | 27 | aes := New(key[:], iv[:]) 28 | for pb.Next() { 29 | data := <-buffer 30 | target := <-buffer 31 | aes.Crypt(target, data) 32 | buffer <- data 33 | buffer <- target 34 | } 35 | }) 36 | } 37 | 38 | func Benchmark1(b *testing.B) { 39 | benchmarkWithSize(1, b) 40 | } 41 | 42 | func Benchmark64(b *testing.B) { 43 | benchmarkWithSize(64, b) 44 | } 45 | 46 | func Benchmark128(b *testing.B) { 47 | benchmarkWithSize(128, b) 48 | } 49 | 50 | func Benchmark256(b *testing.B) { 51 | benchmarkWithSize(256, b) 52 | } 53 | 54 | func Benchmark512(b *testing.B) { 55 | benchmarkWithSize(512, b) 56 | } 57 | 58 | func Benchmark1024(b *testing.B) { 59 | benchmarkWithSize(1024, b) 60 | } 61 | 62 | func Benchmark2048(b *testing.B) { 63 | benchmarkWithSize(2048, b) 64 | } 65 | -------------------------------------------------------------------------------- /cell.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "encoding/binary" 9 | ) 10 | 11 | var BigEndian = binary.BigEndian 12 | 13 | type Cell interface { 14 | CircID() CircuitID 15 | Command() Command 16 | Data() []byte 17 | ReleaseBuffers() 18 | Bytes() []byte 19 | } 20 | 21 | func NewCell(vers LinkVersion, id CircuitID, cmd Command, data []byte) Cell { 22 | if vers < 4 { 23 | return NewCell3(id, cmd, data) 24 | } else { 25 | return NewCell4(id, cmd, data) 26 | } 27 | } 28 | 29 | func NewVarCell(vers LinkVersion, id CircuitID, cmd Command, data []byte, length int) Cell { 30 | if vers < 4 { 31 | return NewVarCell3(id, cmd, data, length) 32 | } else { 33 | return NewVarCell4(id, cmd, data, length) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cellbuf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | const MAX_CELL_SIZE = 514 8 | 9 | // Optimizations to avoid constantly allocating and deallocating... 10 | var cellBufChan = make(chan []byte, 100000) 11 | 12 | func SeedCellBuf() { 13 | // Doing this at the start makes our memory usage far more predictable 14 | for i := 0; i < 1000; i++ { 15 | ReturnCellBuf(make([]byte, MAX_CELL_SIZE)) 16 | } 17 | } 18 | 19 | func GetCellBuf(wiped bool) []byte { 20 | var buf []byte 21 | select { 22 | case buf = <-cellBufChan: 23 | // Done 24 | default: 25 | buf = make([]byte, MAX_CELL_SIZE) 26 | } 27 | 28 | buf = buf[:MAX_CELL_SIZE] 29 | 30 | if wiped { 31 | for i := 0; i < cap(buf); i++ { 32 | buf[i] = 0 33 | } 34 | } 35 | 36 | return buf 37 | } 38 | 39 | func ReturnCellBuf(buf []byte) { 40 | if cap(buf) == MAX_CELL_SIZE { 41 | select { 42 | case cellBufChan <- buf: 43 | // Done 44 | default: 45 | // Pool full... Release it 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /cellv3.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type Cell3 []byte 8 | 9 | func (c Cell3) Command() Command { 10 | return Command(c[2]) 11 | } 12 | 13 | func (c Cell3) Data() []byte { 14 | return c[3:len(c)] 15 | } 16 | 17 | func (c Cell3) CircID() CircuitID { 18 | return CircuitID(BigEndian.Uint16(c[0:2])) 19 | } 20 | 21 | func (c Cell3) ReleaseBuffers() { 22 | ReturnCellBuf([]byte(c)) 23 | } 24 | 25 | func (c Cell3) Bytes() []byte { 26 | return []byte(c) 27 | } 28 | 29 | func NewCell3(id CircuitID, cmd Command, d []byte) Cell { 30 | c := Cell3(GetCellBuf(false)) 31 | 32 | BigEndian.PutUint16(c[0:2], uint16(id)) 33 | c[2] = byte(cmd) 34 | if len(d) > 509 { 35 | panic("Code error: creating massive cell") 36 | } 37 | if d != nil { 38 | copy(c[3:], d) 39 | } 40 | // Now wipe all other data 41 | for i := 3 + len(d); i < 512; i++ { 42 | c[i] = 0 43 | } 44 | c = c[0:512] 45 | return &c 46 | } 47 | 48 | func NewVarCell3(id CircuitID, cmd Command, d []byte, l int) Cell { 49 | if d != nil && l > 0 { 50 | panic("Don't specify both data and length") 51 | } 52 | 53 | if l == 0 { 54 | l = len(d) 55 | } 56 | 57 | var buf []byte 58 | if l+5 > MAX_CELL_SIZE { 59 | buf = make([]byte, l+5) 60 | } else { 61 | buf = GetCellBuf(false) 62 | } 63 | c := Cell3(buf) 64 | BigEndian.PutUint16(c[0:2], uint16(id)) 65 | c[2] = byte(cmd) 66 | BigEndian.PutUint16(c[3:5], uint16(l)) 67 | 68 | if d != nil { 69 | copy(c[5:], d) 70 | } else if l <= MAX_CELL_SIZE { // Go will do this for us when using make() 71 | for i := 5; i < 5+l; i++ { 72 | c[i] = 0 73 | } 74 | } 75 | c = c[0 : 5+l] 76 | return &c 77 | } 78 | -------------------------------------------------------------------------------- /cellv4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type Cell4 []byte 8 | 9 | func (c Cell4) Command() Command { 10 | return Command(c[4]) 11 | } 12 | 13 | func (c Cell4) Data() []byte { 14 | return c[5:len(c)] 15 | } 16 | 17 | func (c Cell4) CircID() CircuitID { 18 | return CircuitID(BigEndian.Uint32(c[0:4])) 19 | } 20 | 21 | func (c Cell4) ReleaseBuffers() { 22 | ReturnCellBuf([]byte(c)) 23 | } 24 | 25 | func (c Cell4) Bytes() []byte { 26 | return []byte(c) 27 | } 28 | 29 | func NewCell4(id CircuitID, cmd Command, d []byte) Cell { 30 | c := Cell4(GetCellBuf(false)) 31 | BigEndian.PutUint32(c[0:4], uint32(id)) 32 | c[4] = byte(cmd) 33 | if len(d) > 509 { 34 | panic("Code error: creating massive cell") 35 | } 36 | if d != nil { 37 | copy(c[5:], d) 38 | } 39 | // Now wipe all other data 40 | for i := 5 + len(d); i < 514; i++ { 41 | c[i] = 0 42 | } 43 | c = c[0:514] 44 | return &c 45 | } 46 | 47 | func NewVarCell4(id CircuitID, cmd Command, d []byte, l int) Cell { 48 | if d != nil && l > 0 { 49 | panic("Don't specify both data and length") 50 | } 51 | 52 | if l == 0 { 53 | l = len(d) 54 | } 55 | 56 | var buf []byte 57 | if l+7 > MAX_CELL_SIZE { 58 | buf = make([]byte, l+7) 59 | } else { 60 | buf = GetCellBuf(false) 61 | } 62 | c := Cell4(buf) 63 | BigEndian.PutUint32(c[0:4], uint32(id)) 64 | c[4] = byte(cmd) 65 | BigEndian.PutUint16(c[5:7], uint16(l)) 66 | if d != nil { 67 | copy(c[7:], d) 68 | } else if l <= MAX_CELL_SIZE { // Go will do this for us when using make() 69 | for i := 7; i < 7+l; i++ { 70 | c[i] = 0 71 | } 72 | } 73 | c = c[0 : 7+l] 74 | return &c 75 | } 76 | -------------------------------------------------------------------------------- /circuit.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "github.com/tvdw/gotor/aes" 9 | "github.com/tvdw/gotor/sha1" 10 | "sync" 11 | ) 12 | 13 | type CircuitID uint32 14 | 15 | func (id CircuitID) MSB(vers LinkVersion) bool { 16 | if vers < 4 { 17 | if id&0x8000 == 0x8000 { 18 | return true // outgoing 19 | } else { 20 | return false // incoming 21 | } 22 | } else { 23 | if id&0x80000000 == 0x80000000 { 24 | return true // outgoing 25 | } else { 26 | return false // incoming 27 | } 28 | } 29 | } 30 | 31 | type DirectionalCircuitState struct { 32 | cipher aes.Cipher 33 | digest *sha1.Digest 34 | } 35 | 36 | type DataDirection bool 37 | 38 | const ( 39 | ForwardDirection = true 40 | BackwardDirection = false 41 | ) 42 | 43 | type Circuit struct { 44 | id CircuitID 45 | forward, backward DirectionalCircuitState 46 | forwardWindow int 47 | backwardWindow *Window 48 | nextHop CircReadQueue 49 | nextHopID CircuitID 50 | 51 | streams map[StreamID]*Stream 52 | extendState *CircuitHandshakeState 53 | } 54 | 55 | type RelayCircuit struct { 56 | id, theirID CircuitID 57 | previousHop CircReadQueue 58 | } 59 | 60 | type CircuitHandshakeState struct { 61 | lock sync.Mutex 62 | aborted bool 63 | nextHop CircReadQueue 64 | nextHopID CircuitID 65 | } 66 | 67 | type CircuitRequest struct { 68 | NeverForRelay 69 | localID CircuitID 70 | connHint ConnectionHint 71 | successQueue CircReadQueue 72 | handshakeType uint16 73 | handshakeData []byte 74 | newHandshake bool 75 | handshakeState *CircuitHandshakeState 76 | } 77 | 78 | type CircuitCreated struct { 79 | NeverForRelay 80 | id CircuitID 81 | handshakeData []byte 82 | newHandshake bool 83 | } 84 | 85 | func (c *CircuitRequest) CircID() CircuitID { 86 | return 0 87 | } 88 | 89 | func (c *CircuitRequest) ReleaseBuffers() { 90 | ReturnCellBuf(c.handshakeData) 91 | c.handshakeState = nil 92 | c.handshakeData = nil 93 | c.successQueue = nil 94 | } 95 | 96 | func (c *CircuitCreated) CircID() CircuitID { 97 | return c.id 98 | } 99 | 100 | func (c *CircuitCreated) ReleaseBuffers() { 101 | ReturnCellBuf(c.handshakeData) 102 | } 103 | 104 | var zeroIv [16]byte 105 | 106 | func NewCircuit(id CircuitID, fSeed, bSeed, fKey, bKey []byte) *Circuit { 107 | if id == 0 { 108 | panic("wtf?") 109 | } 110 | 111 | StatsNewCircuit() 112 | 113 | aes_fwd := aes.New(fKey, zeroIv[:]) 114 | aes_rev := aes.New(bKey, zeroIv[:]) 115 | 116 | dig_fwd := sha1.New() 117 | dig_fwd.Write(fSeed) 118 | dig_rev := sha1.New() 119 | dig_rev.Write(bSeed) 120 | 121 | circ := &Circuit{ 122 | id: id, 123 | forward: DirectionalCircuitState{ 124 | cipher: aes_fwd, 125 | digest: dig_fwd, 126 | }, 127 | backward: DirectionalCircuitState{ 128 | cipher: aes_rev, 129 | digest: dig_rev, 130 | }, 131 | backwardWindow: NewWindow(1000), 132 | forwardWindow: 1000, 133 | streams: make(map[StreamID]*Stream), 134 | } 135 | 136 | return circ 137 | } 138 | 139 | func (c *OnionConnection) destroyCircuit(circ *Circuit, announce, shouldRemove bool, reason DestroyReason) { 140 | if shouldRemove { 141 | delete(c.circuits, circ.id) 142 | } 143 | 144 | circ.backwardWindow.Abort() 145 | for _, stream := range circ.streams { 146 | stream.Destroy() 147 | } 148 | 149 | StatsDestroyCircuit() 150 | 151 | if circ.extendState != nil { 152 | circ.extendState.lock.Lock() 153 | circ.extendState.aborted = true 154 | if circ.extendState.nextHop != nil { 155 | if circ.nextHop != nil { 156 | panic("wtf-case") 157 | } 158 | circ.nextHop = circ.extendState.nextHop 159 | circ.nextHopID = circ.extendState.nextHopID 160 | } 161 | circ.extendState.lock.Unlock() 162 | circ.extendState = nil 163 | } 164 | 165 | if announce && circ.nextHop != nil { 166 | circ.nextHop <- &CircuitDestroyed{ 167 | id: circ.nextHopID, 168 | reason: reason, 169 | forRelay: true, 170 | } 171 | } 172 | 173 | // Set things to nil to mitigate possible memory leaks caused by other objects retaining this circuit (which is obviously a bug) 174 | circ.nextHop = nil 175 | circ.forward = DirectionalCircuitState{} 176 | circ.backward = DirectionalCircuitState{} 177 | circ.streams = nil 178 | circ.backwardWindow = nil 179 | } 180 | 181 | func (c *OnionConnection) destroyRelayCircuit(circ *RelayCircuit, announce, shouldRemove bool, reason DestroyReason) { 182 | if shouldRemove { 183 | delete(c.relayCircuits, circ.id) 184 | } 185 | 186 | if announce && circ.previousHop != nil { 187 | circ.previousHop <- &CircuitDestroyed{ 188 | id: circ.theirID, 189 | reason: reason, 190 | forRelay: false, 191 | //truncate: true, // XXX? 192 | } 193 | } 194 | } 195 | 196 | func (c *OnionConnection) NewCircID() CircuitID { 197 | for { 198 | var b [4]byte 199 | CRandBytes(b[:]) 200 | if c.isOutbound { 201 | b[0] |= 0x80 202 | } else { 203 | b[0] &= 0x7f 204 | } 205 | cID := CircuitID(BigEndian.Uint32(b[:])) 206 | if c.negotiatedVersion < 4 { 207 | cID = (cID & 0xffff0000) >> 16 // Cut off the last 16 bits as we can't transmit them 208 | } 209 | 210 | _, exists := c.circuits[cID] 211 | if !exists { // XXX check infinite loop 212 | return cID 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /cmdrouter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | type CircuitCommand interface { 13 | CircID() CircuitID 14 | ForRelay() bool 15 | Handle(*OnionConnection, *Circuit) ActionableError 16 | HandleRelay(*OnionConnection, *RelayCircuit) ActionableError 17 | ReleaseBuffers() 18 | } 19 | 20 | type NeverForRelay struct { 21 | } 22 | 23 | type NoBuffers struct { 24 | } 25 | 26 | func (c *NeverForRelay) ForRelay() bool { 27 | return false 28 | } 29 | 30 | func (c *NoBuffers) ReleaseBuffers() { 31 | } 32 | 33 | func (c *NeverForRelay) HandleRelay(*OnionConnection, *RelayCircuit) ActionableError { 34 | panic("reached unreachable code") 35 | } 36 | 37 | func (c *OnionConnection) routeCellToFunction(cell Cell) ActionableError { 38 | switch cell.Command() { 39 | case CMD_CREATE_FAST: 40 | return c.handleCreateFast(cell) 41 | 42 | case CMD_RELAY, CMD_RELAY_EARLY: 43 | // XXX CircType() 44 | circID := cell.CircID() 45 | circ, ok := c.circuits[circID] 46 | if ok { 47 | return c.handleRelayForward(circ, cell) 48 | } 49 | 50 | rcirc, ok := c.relayCircuits[circID] 51 | if ok { 52 | if cell.Command() == CMD_RELAY_EARLY { 53 | return CloseConnection(errors.New("Dropping the connection - no way we're routing a RELAY_EARLY cell back")) 54 | } 55 | return c.handleRelayBackward(rcirc, cell) 56 | } 57 | 58 | // Not an error 59 | Log(LOG_INFO, "Received a %s cell for an unknown circuit - dropping", cell.Command()) 60 | 61 | case CMD_CREATE, CMD_CREATE2: 62 | newHandshake := cell.Command() == CMD_CREATE2 63 | return c.handleCreate(cell, newHandshake) 64 | 65 | case CMD_DESTROY: 66 | return c.handleDestroy(cell) 67 | 68 | case CMD_CREATED, CMD_CREATED2: 69 | return c.handleCreated(cell, cell.Command() == CMD_CREATED2) 70 | 71 | case CMD_PADDING, CMD_VPADDING: 72 | // Can be ignored 73 | 74 | case CMD_CERTS, CMD_NETINFO, CMD_AUTH_CHALLENGE, CMD_AUTHORIZE, CMD_AUTHENTICATE: 75 | return CloseConnection(errors.New(fmt.Sprintf("Command %s not allowed at this point. Disconnecting", cell.Command()))) 76 | 77 | default: 78 | Log(LOG_NOTICE, "Got a cell with command %s - dropping", cell.Command()) 79 | Log(LOG_DEBUG, "%v", cell) 80 | } 81 | 82 | return nil 83 | } 84 | 85 | func (c *OnionConnection) routeCircuitCommandToFunction(cmd CircuitCommand) ActionableError { 86 | circID := cmd.CircID() 87 | forRelay := cmd.ForRelay() 88 | 89 | if !forRelay { 90 | if circID == 0 { // Control command 91 | return cmd.Handle(c, nil) 92 | } 93 | 94 | // Look in c.circuits 95 | circ, ok := c.circuits[circID] 96 | if !ok { 97 | Log(LOG_INFO, "got internal command for nonexisting circuit %v", cmd) 98 | return nil // It happens, nothing to worry about 99 | } 100 | 101 | return cmd.Handle(c, circ) 102 | } else { 103 | if circID == 0 { // Control command 104 | return cmd.HandleRelay(c, nil) 105 | } 106 | 107 | // Look in c.relayCircuits 108 | circ, ok := c.relayCircuits[circID] 109 | if !ok { 110 | Log(LOG_INFO, "got internal command for nonexisting relayCircuit %v", cmd) 111 | return nil // It happens, nothing to worry about 112 | } 113 | 114 | return cmd.HandleRelay(c, circ) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "fmt" 11 | "log" 12 | "os" 13 | "regexp" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | type Config struct { 19 | IsPublicServer bool 20 | ORPort uint16 21 | DirPort uint16 22 | DataDirectory string 23 | 24 | // Descriptor related only 25 | Contact, Nickname, Platform, Address string 26 | BandwidthAvg, BandwidthBurst, BandwidthObserved int 27 | Family []string 28 | 29 | ExitPolicy ExitPolicy 30 | } 31 | 32 | func (c *Config) ReadFile(filename string) error { 33 | file, err := os.Open(filename) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | re := regexp.MustCompile(`^\s*(?:([a-zA-Z0-9]+)\s+([^#]+?))?\s*(?:#.*)?$`) 39 | policyRe := regexp.MustCompile(`^((?:accept|reject)(?:6?))\s+(\*|(?:[0-9]{1,3}\.){3}[0-9]{1,3}):(\*|[1-9][0-9]{0,4})$`) 40 | familyRe := regexp.MustCompile(`^(?:(?:\$[a-fA-F0-9]{40})[ ,]?)+$`) 41 | familySplit := regexp.MustCompile(`[, ]+`) 42 | bandwidthRe := regexp.MustCompile(`^(?i)([0-9]+)\s*(bytes?|kbytes?|mbytes?|gbytes?|kbits?|mbits?|gbits?)$`) 43 | 44 | sc := bufio.NewScanner(file) 45 | for sc.Scan() { 46 | matches := re.FindStringSubmatch(sc.Text()) 47 | if matches == nil { 48 | return errors.New(fmt.Sprintf("Could not parse line: %q", sc.Text())) 49 | } 50 | if len(matches[1]) == 0 && len(matches[2]) != 0 { 51 | panic("Parser bug?") 52 | } 53 | if len(matches[1]) == 0 { 54 | continue 55 | } 56 | 57 | lower := strings.ToLower(matches[1]) 58 | switch lower { 59 | case "orport": 60 | port, err := strconv.ParseUint(matches[2], 0, 16) 61 | if err != nil { 62 | return err //XXX 63 | } 64 | c.ORPort = uint16(port) 65 | 66 | case "bandwidthrate", "bandwidthburst", "maxadvertisedbandwidth": 67 | bw := bandwidthRe.FindStringSubmatch(matches[2]) 68 | if bw == nil { 69 | return fmt.Errorf("Could not parse %s %q", matches[1], matches[2]) 70 | } 71 | 72 | val_, err := strconv.ParseInt(bw[1], 0, 16) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | val := int(val_) 78 | 79 | switch strings.ToLower(bw[2]) { 80 | case "byte", "bytes": 81 | val *= 1 82 | case "kbyte", "kbytes": 83 | val *= 1000 84 | case "mbyte", "mbytes": 85 | val *= 1000000 86 | case "gbyte", "gbytes": 87 | val *= 1000000000 88 | case "kbit", "kbits": 89 | val *= 125 90 | case "mbit", "mbits": 91 | val *= 125000 92 | case "gbit", "gbits": 93 | val *= 125000000 94 | } 95 | 96 | if lower == "bandwidthrate" { 97 | c.BandwidthAvg = val 98 | } else if lower == "bandwidthburst" { 99 | c.BandwidthBurst = val 100 | } else if lower == "maxadvertisedbandwidth" { 101 | c.BandwidthObserved = val 102 | } 103 | 104 | case "datadirectory": 105 | c.DataDirectory = matches[2] 106 | 107 | case "nickname": 108 | c.Nickname = matches[2] 109 | 110 | case "contactinfo": 111 | c.Contact = matches[2] 112 | 113 | case "myfamily": 114 | m := familyRe.FindStringSubmatch(matches[2]) 115 | if len(m) == 0 { 116 | return errors.New(fmt.Sprintf("could not parse MyFamily %q\n", matches[2])) 117 | } 118 | c.Family = familySplit.Split(m[0], -1) 119 | 120 | case "exitpolicy": 121 | m := policyRe.FindStringSubmatch(matches[2]) 122 | if m == nil { 123 | return errors.New(fmt.Sprintf("Could not parse ExitPolicy %q\n", matches[2])) 124 | } 125 | rule := ExitRule{} 126 | if m[1] == "accept" || m[1] == "accept6" { 127 | rule.Action = true 128 | } else { 129 | rule.Action = false 130 | } 131 | if m[len(m)-1] == "6" { 132 | rule.V6 = true 133 | } 134 | if m[3] != "*" { 135 | port, err := strconv.ParseUint(m[3], 0, 16) 136 | if err != nil { 137 | return err //XXX 138 | } 139 | rule.Port = uint16(port) 140 | } 141 | if m[2] != "*" { 142 | log.Panicln("not implemented: address parsing") //XXX 143 | } 144 | c.ExitPolicy.Rules = append(c.ExitPolicy.Rules, rule) 145 | 146 | case "address": 147 | c.Address = matches[2] 148 | 149 | default: 150 | log.Printf("Configuration option %q not recognized. Ignoring its value\n", matches[1]) 151 | } 152 | } 153 | 154 | return nil 155 | } 156 | -------------------------------------------------------------------------------- /connectionhint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | type ConnectionHint struct { 13 | fp *Fingerprint 14 | address [][]byte 15 | } 16 | 17 | func (c *ConnectionHint) AddFingerprint(fp []byte) error { 18 | if c.fp != nil { 19 | return errors.New("already have a fingerprint") 20 | } 21 | 22 | if len(fp) != 20 { 23 | return errors.New("that's no fingerprint") 24 | } 25 | 26 | c.fp = new(Fingerprint) 27 | copy(c.fp[:], fp) 28 | 29 | return nil 30 | } 31 | 32 | func (c *ConnectionHint) GetFingerprint() *Fingerprint { 33 | return c.fp 34 | } 35 | 36 | func (c *ConnectionHint) AddAddress(addr []byte) error { 37 | if len(addr) != 6 && len(addr) != 18 { 38 | return errors.New("not an address we recognize") 39 | } 40 | 41 | dup := make([]byte, len(addr)) 42 | copy(dup, addr) 43 | if c.address == nil { 44 | c.address = make([][]byte, 0, 2) 45 | } 46 | 47 | c.address = append(c.address, dup) 48 | 49 | return nil 50 | } 51 | 52 | func (c *ConnectionHint) GetAddresses() []string { 53 | if c.address == nil { 54 | return nil 55 | } 56 | 57 | addrs := make([]string, 0, len(c.address)) 58 | for _, addr := range c.address { 59 | if len(addr) == 6 { 60 | v4 := fmt.Sprintf("%d.%d.%d.%d:%d", addr[0], addr[1], addr[2], addr[3], ((int(addr[4]) << 8) + int(addr[5]))) 61 | addrs = append(addrs, v4) 62 | } else if len(addr) == 18 { 63 | v6 := fmt.Sprintf("[%X:%X:%X:%X:%X:%X:%X:%X]:%d", 64 | addr[0:2], addr[2:4], addr[4:6], addr[6:8], 65 | addr[8:10], addr[10:12], addr[12:14], addr[14:16], 66 | (int(addr[16])<<8)+int(addr[17])) 67 | addrs = append(addrs, v6) 68 | } 69 | } 70 | 71 | return addrs 72 | } 73 | -------------------------------------------------------------------------------- /create.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "crypto/hmac" 10 | "crypto/sha256" 11 | "encoding/hex" 12 | "errors" 13 | "fmt" 14 | "github.com/tvdw/openssl" 15 | "golang.org/x/crypto/curve25519" 16 | ) 17 | 18 | type HandshakeType uint16 19 | 20 | const ( 21 | HANDSHAKE_TAP HandshakeType = 0x00 22 | HANDSHAKE_NTOR HandshakeType = 0x02 23 | ) 24 | 25 | var dhKeyStr = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" 26 | var dhKey []byte 27 | var funnyNtorHandshake = []byte("ntorNTORntorNTOR") 28 | 29 | func (c *OnionConnection) handleCreateFast(cell Cell) ActionableError { 30 | // XXX check for weAuthenticated (why?) 31 | 32 | circID := cell.CircID() 33 | Log(LOG_CIRC, "Got a CREATE_FAST for CircID %d", circID) 34 | 35 | if circID == 0 { 36 | return CloseConnection(errors.New("refusing to create CircID=0")) 37 | } 38 | 39 | if circID.MSB(c.negotiatedVersion) == c.isOutbound { 40 | return CloseConnection(fmt.Errorf("refusing an invalid CircID %d %t", circID, c.isOutbound)) 41 | } 42 | 43 | _, alreadyExists := c.circuits[cell.CircID()] 44 | if alreadyExists { 45 | return CloseConnection(errors.New("Circuit already exists")) 46 | } 47 | 48 | writeCell := NewCell(c.negotiatedVersion, circID, CMD_CREATED_FAST, nil) 49 | writeCellData := writeCell.Data() 50 | 51 | CRandBytes(writeCellData[0:20]) 52 | 53 | // Generate a key 54 | var tmp [40]byte 55 | copy(tmp[0:20], cell.Data()[0:20]) 56 | copy(tmp[20:40], writeCellData[0:20]) 57 | keyData := KDFTOR(92, tmp[:]) 58 | 59 | copy(writeCellData[20:40], keyData[0:20]) 60 | 61 | circ := NewCircuit(circID, keyData[20:40], keyData[40:60], keyData[60:76], keyData[76:92]) 62 | c.circuits[circID] = circ 63 | 64 | c.writeQueue <- writeCell.Bytes() 65 | 66 | return nil 67 | } 68 | 69 | func (c *OnionConnection) handleCreate(cell Cell, newHandshake bool) ActionableError { 70 | data := cell.Data() 71 | handshake := HANDSHAKE_TAP 72 | 73 | Log(LOG_CIRC, "Got a CREATE") 74 | 75 | circID := cell.CircID() 76 | if circID.MSB(c.negotiatedVersion) == c.isOutbound { 77 | return CloseConnection(fmt.Errorf("refusing an invalid CircID %d %t", circID, c.isOutbound)) 78 | } 79 | 80 | if circID == 0 { 81 | return CloseConnection(errors.New("Not creating a circuit with id=0")) 82 | } 83 | 84 | var handshakeData []byte 85 | 86 | if newHandshake { 87 | handshake = HandshakeType(BigEndian.Uint16(data[0:2])) 88 | length := int(BigEndian.Uint16(data[2:4])) 89 | if length > len(data)-4 { 90 | return RefuseCircuit(errors.New("malformed CREATE cell"), DESTROY_REASON_PROTOCOL) 91 | } 92 | handshakeData = data[4 : length+4] 93 | } else { 94 | isNtor := true 95 | for i, v := range funnyNtorHandshake { 96 | if data[i] != v { 97 | isNtor = false 98 | break 99 | } 100 | } 101 | if isNtor { 102 | handshake = HANDSHAKE_NTOR 103 | handshakeData = data[16 : len(data)-16] 104 | } else { 105 | handshake = HANDSHAKE_TAP 106 | handshakeData = data 107 | } 108 | } 109 | 110 | if handshake == HANDSHAKE_TAP { 111 | return c.handleCreateTAP(cell.CircID(), handshakeData, newHandshake) 112 | } else if handshake == HANDSHAKE_NTOR { 113 | return c.handleCreateNTOR(cell.CircID(), handshakeData, newHandshake) 114 | } 115 | 116 | return RefuseCircuit(errors.New("unknown handshake"), DESTROY_REASON_PROTOCOL) 117 | } 118 | 119 | func (c *OnionConnection) handleCreateTAP(id CircuitID, data []byte, newHandshake bool) ActionableError { 120 | theirData, err := HybridDecrypt(c.parentOR.onionKey, data[0:186]) 121 | if err != nil { 122 | return RefuseCircuit(err, DESTROY_REASON_INTERNAL) 123 | } 124 | 125 | if len(theirData) != 128 { 126 | return RefuseCircuit(errors.New("invalid TAP handshake found"), DESTROY_REASON_INTERNAL) 127 | } 128 | 129 | if dhKey == nil { 130 | key, err := hex.DecodeString(dhKeyStr) 131 | if err != nil || key[0] != 255 || key[8] != 0xc9 { 132 | panic(err) 133 | } 134 | dhKey = key 135 | } 136 | 137 | dh, err := openssl.LoadDHFromBignumWithGenerator(dhKey, 2) 138 | if err != nil { 139 | return RefuseCircuit(err, DESTROY_REASON_INTERNAL) 140 | } 141 | 142 | pub, err := dh.GetPublicKey() 143 | if err != nil { 144 | return RefuseCircuit(err, DESTROY_REASON_INTERNAL) 145 | } 146 | 147 | secr, err := dh.GetSharedKey(theirData) 148 | if err != nil { 149 | return RefuseCircuit(err, DESTROY_REASON_INTERNAL) 150 | } 151 | 152 | keyData := KDFTOR(92, secr) 153 | 154 | cmd := CMD_CREATED2 155 | if !newHandshake { 156 | cmd = CMD_CREATED 157 | } 158 | writeCell := NewCell(c.negotiatedVersion, id, cmd, nil) 159 | buf := writeCell.Data() 160 | 161 | if !newHandshake { 162 | copy(buf[0:128], pub) 163 | copy(buf[128:148], keyData[0:20]) 164 | } else { 165 | buf[0] = 0 166 | buf[1] = 148 167 | copy(buf[2:130], pub) 168 | copy(buf[130:150], keyData[0:20]) 169 | } 170 | 171 | circ := NewCircuit(id, keyData[20:40], keyData[40:60], keyData[60:76], keyData[76:92]) 172 | c.circuits[id] = circ 173 | 174 | c.writeQueue <- writeCell.Bytes() 175 | return nil 176 | } 177 | 178 | func (c *OnionConnection) handleCreateNTOR(circID CircuitID, data []byte, newHandshake bool) ActionableError { 179 | if len(data) < 84 { 180 | return RefuseCircuit(errors.New("didn't get enough data"), DESTROY_REASON_PROTOCOL) 181 | } 182 | 183 | _, alreadyThere := c.circuits[circID] 184 | if alreadyThere { 185 | return CloseConnection(errors.New("nope")) 186 | } 187 | 188 | fingerprint := data[0:20] 189 | myFingerprint := c.usedTLSCtx.Fingerprint 190 | for i, v := range fingerprint { 191 | if v != myFingerprint[i] { 192 | Log(LOG_INFO, "FP mismatch %s != %s", myFingerprint, fingerprint) 193 | return RefuseCircuit(errors.New("that's not me"), DESTROY_REASON_PROTOCOL) 194 | } 195 | } 196 | 197 | var key_X [32]byte 198 | copy(key_X[:], data[52:84]) 199 | 200 | mExpand := []byte("ntor-curve25519-sha256-1:key_expand") 201 | tKey := []byte("ntor-curve25519-sha256-1:key_extract") 202 | tMac := []byte("ntor-curve25519-sha256-1:mac") 203 | tVerify := []byte("ntor-curve25519-sha256-1:verify") 204 | 205 | var key_y [32]byte 206 | CRandBytes(key_y[:]) 207 | key_y[0] &= 248 208 | key_y[31] &= 127 209 | key_y[31] |= 64 210 | var key_Y [32]byte 211 | curve25519.ScalarBaseMult(&key_Y, &key_y) 212 | 213 | var buffer bytes.Buffer 214 | 215 | var tmpHolder [32]byte 216 | curve25519.ScalarMult(&tmpHolder, &key_y, &key_X) 217 | buffer.Write(tmpHolder[:]) 218 | 219 | curve25519.ScalarMult(&tmpHolder, &c.parentOR.ntorPrivate, &key_X) 220 | buffer.Write(tmpHolder[:]) 221 | 222 | buffer.Write(fingerprint) 223 | buffer.Write(c.parentOR.ntorPublic[:]) 224 | buffer.Write(key_X[:]) 225 | buffer.Write(key_Y[:]) 226 | buffer.Write([]byte("ntor-curve25519-sha256-1")) 227 | 228 | secretInput := buffer.Bytes() 229 | kdf := KDFHKDF(72, secretInput, tKey, mExpand) 230 | 231 | hhmac := hmac.New(sha256.New, tVerify) 232 | hhmac.Write(secretInput) 233 | verify := hhmac.Sum(nil) 234 | 235 | buffer.Reset() 236 | buffer.Write(verify) 237 | buffer.Write(fingerprint) 238 | buffer.Write(c.parentOR.ntorPublic[:]) 239 | buffer.Write(key_Y[:]) 240 | buffer.Write(key_X[:]) 241 | buffer.Write([]byte("ntor-curve25519-sha256-1Server")) 242 | authInput := buffer.Bytes() 243 | 244 | hhmac = hmac.New(sha256.New, tMac) 245 | hhmac.Write(authInput) 246 | auth := hhmac.Sum(nil) 247 | 248 | // XXX check for infinity 249 | 250 | cmd := CMD_CREATED2 251 | if !newHandshake { 252 | cmd = CMD_CREATED 253 | } 254 | writeCell := NewCell(c.negotiatedVersion, circID, cmd, nil) 255 | writeCellBuf := writeCell.Data() 256 | if newHandshake { 257 | writeCellBuf[0] = 0 258 | writeCellBuf[1] = 64 259 | copy(writeCellBuf[2:34], key_Y[:]) 260 | copy(writeCellBuf[34:], auth) 261 | } else { 262 | copy(writeCellBuf[0:32], key_Y[:]) 263 | copy(writeCellBuf[32:], auth) 264 | } 265 | 266 | circ := NewCircuit(circID, kdf[0:20], kdf[20:40], kdf[40:56], kdf[56:72]) 267 | c.circuits[circID] = circ 268 | 269 | c.writeQueue <- writeCell.Bytes() 270 | 271 | return nil 272 | } 273 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | ) 11 | 12 | const debugLevel = LOG_NOTICE 13 | 14 | const ( 15 | LOG_DEBUG = 6 16 | LOG_PROTO = 5 17 | LOG_CIRC = 4 18 | LOG_INFO = 3 19 | LOG_NOTICE = 2 20 | LOG_WARN = 1 21 | ) 22 | 23 | var levels = []string{ 24 | "warn", 25 | "notice", 26 | "info", 27 | "circ", 28 | "proto", 29 | "debug", 30 | } 31 | 32 | func Log(level byte, format string, args ...interface{}) { 33 | if level <= debugLevel { 34 | text := fmt.Sprintf(format, args...) 35 | log.Print(levels[level-1], " ", text) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /destroy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type CircuitDestroyed struct { 8 | NoBuffers 9 | id CircuitID 10 | reason DestroyReason 11 | forRelay bool 12 | truncate bool 13 | } 14 | 15 | func (c *CircuitDestroyed) CircID() CircuitID { 16 | return c.id 17 | } 18 | 19 | func (data *CircuitDestroyed) ForRelay() bool { 20 | return data.forRelay 21 | } 22 | 23 | func (data *CircuitDestroyed) Handle(c *OnionConnection, circ *Circuit) ActionableError { 24 | Log(LOG_CIRC, "CircuitDestroy (front)") 25 | 26 | if data.truncate { 27 | panic("not implemented properly") // XXX needs cleanup of fields like nextHop/nextHopID 28 | return c.sendRelayCell(circ, 0, BackwardDirection, RELAY_TRUNCATED, []byte{byte(data.reason)}) 29 | } else { 30 | c.destroyCircuit(circ, false, true, data.reason) 31 | c.writeQueue <- NewCell(c.negotiatedVersion, circ.id, CMD_DESTROY, []byte{byte(data.reason)}).Bytes() 32 | return nil 33 | } 34 | } 35 | 36 | func (data *CircuitDestroyed) HandleRelay(c *OnionConnection, circ *RelayCircuit) ActionableError { 37 | Log(LOG_CIRC, "CircuitDestroy (relay)") 38 | c.destroyRelayCircuit(circ, false, true, data.reason) 39 | 40 | c.writeQueue <- NewCell(c.negotiatedVersion, circ.id, CMD_DESTROY, []byte{byte(data.reason)}).Bytes() 41 | return nil 42 | } 43 | 44 | func (c *OnionConnection) handleDestroy(cell Cell) ActionableError { 45 | Log(LOG_CIRC, "Got a destroy for circ %d with reason %s", cell.CircID(), DestroyReason(cell.Data()[0])) 46 | 47 | circID := cell.CircID() 48 | if circID.MSB(c.negotiatedVersion) != c.isOutbound { 49 | circ, ok := c.circuits[circID] 50 | if !ok { 51 | Log(LOG_INFO, "Got a DESTROY but we don't know the circuit they're talking about. Ignoring") 52 | } else { 53 | c.destroyCircuit(circ, true, true, DestroyReason(cell.Data()[0])) 54 | } 55 | return nil 56 | } 57 | 58 | rcirc, ok := c.relayCircuits[circID] 59 | if ok { 60 | c.destroyRelayCircuit(rcirc, true, true, DestroyReason(cell.Data()[0])) 61 | return nil 62 | } 63 | 64 | Log(LOG_INFO, "Got a DESTROY but we don't know the circuit they're talking about. Ignoring") 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /dns.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "net" 9 | "github.com/miekg/dns" 10 | ) 11 | 12 | type DNSAddress struct { 13 | Type byte 14 | TTL int 15 | Value []byte 16 | } 17 | 18 | type DNSResult struct { 19 | NeverForRelay 20 | NoBuffers 21 | circuitID CircuitID 22 | streamID StreamID 23 | 24 | Results []DNSAddress 25 | } 26 | 27 | func (dr *DNSResult) CircID() CircuitID { 28 | return dr.circuitID 29 | } 30 | 31 | func (da DNSAddress) String() string { 32 | if da.Type == 4 { 33 | return net.IPv4(da.Value[0], da.Value[1], da.Value[2], da.Value[3]).String() 34 | } else if da.Type == 6 { 35 | return "[" + net.IP(da.Value).String() + "]" 36 | } else { 37 | return "error" 38 | } 39 | } 40 | 41 | var dnsClient = new(dns.Client) 42 | var config, _ = dns.ClientConfigFromFile("/etc/resolv.conf") 43 | 44 | func ResolveDNS(host string) []DNSAddress { 45 | parsedIP := net.ParseIP(host) 46 | if parsedIP != nil { 47 | v := parsedIP.To16() 48 | t := byte(6) 49 | if parsedIP.To4() != nil { 50 | v = parsedIP.To4() 51 | t = 4 52 | } 53 | return []DNSAddress{ 54 | DNSAddress{ 55 | Value: []byte(v), 56 | Type: t, 57 | TTL: 86400, // XXX 58 | }, 59 | } 60 | } 61 | 62 | m := new(dns.Msg) 63 | m.SetQuestion(dns.Fqdn(host), dns.TypeA) //XXX will this stop us from getting AAAA? 64 | in, _, err := dnsClient.Exchange(m, config.Servers[0]+":"+config.Port) 65 | if err != nil { 66 | return []DNSAddress{DNSAddress{0xF0, 0, nil}} 67 | } 68 | 69 | var r []DNSAddress 70 | for _, answer := range in.Answer { 71 | if a, ok := answer.(*dns.A); ok { 72 | r = append(r, DNSAddress{ 73 | Value: []byte(a.A.To4()), 74 | Type: 4, 75 | TTL: int(a.Hdr.Ttl), 76 | }) 77 | } 78 | if aaaa, ok := answer.(*dns.AAAA); ok { 79 | r = append(r, DNSAddress{ 80 | Value: []byte(aaaa.AAAA.To16()), 81 | Type: 6, 82 | TTL: int(aaaa.Hdr.Ttl), 83 | }) 84 | } 85 | } 86 | if len(r) == 0 { 87 | return []DNSAddress{DNSAddress{0xF1, 0, nil}} 88 | } 89 | return r 90 | } 91 | 92 | func ResolveDNSAsync(host string, circ CircuitID, stream StreamID, resultChan CircReadQueue) { 93 | go func() { // XXX this can be a lot faster and we really don't need a goroutine for each. 94 | result := ResolveDNS(host) 95 | resultChan <- &DNSResult{ 96 | circuitID: circ, 97 | streamID: stream, 98 | Results: result, 99 | } 100 | }() 101 | } 102 | 103 | func (dr *DNSResult) Handle(c *OnionConnection, circ *Circuit) ActionableError { 104 | var buf [MAX_RELAY_LEN]byte 105 | pos := 0 106 | for _, item := range dr.Results { 107 | if len(item.Value) > 255 { 108 | panic("Huh? I thought we're talking IP addresses") 109 | } 110 | if len(buf)-pos-6-len(item.Value) < 0 { 111 | break 112 | } 113 | buf[pos] = item.Type 114 | buf[pos+1] = byte(len(item.Value)) 115 | copy(buf[pos+2:], []byte(item.Value)) 116 | pos += 2 + len(item.Value) 117 | BigEndian.PutUint32(buf[pos:pos+4], uint32(item.TTL)) 118 | pos += 4 119 | } 120 | 121 | return c.sendRelayCell(circ, dr.streamID, BackwardDirection, RELAY_RESOLVED, buf[:pos]) 122 | } 123 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type ErrorHandleMethod byte 8 | 9 | const ( 10 | _ = iota 11 | ERROR_CLOSE_CONNECTION ErrorHandleMethod = iota 12 | ERROR_CLOSE_CIRCUIT 13 | ERROR_CLOSE_STREAM 14 | ERROR_REFUSE_CIRCUIT 15 | ERROR_REFUSE_STREAM 16 | ) 17 | 18 | type ActionableError interface { 19 | error 20 | Handle() ErrorHandleMethod 21 | CircDestroyReason() DestroyReason 22 | StreamEndReason() StreamEndReason 23 | } 24 | 25 | type wrappedError struct { 26 | wrappedError error 27 | handleType ErrorHandleMethod 28 | circDestroyReason DestroyReason 29 | streamEndReason StreamEndReason 30 | } 31 | 32 | func (e *wrappedError) Handle() ErrorHandleMethod { 33 | return e.handleType 34 | } 35 | 36 | func (e *wrappedError) Error() string { 37 | return e.wrappedError.Error() 38 | } 39 | 40 | func (e *wrappedError) CircDestroyReason() DestroyReason { 41 | return e.circDestroyReason 42 | } 43 | 44 | func (e *wrappedError) StreamEndReason() StreamEndReason { 45 | return e.streamEndReason 46 | } 47 | 48 | func CloseCircuit(e error, reason DestroyReason) ActionableError { 49 | return &wrappedError{e, ERROR_CLOSE_CIRCUIT, reason, 0} 50 | } 51 | 52 | func RefuseCircuit(e error, reason DestroyReason) ActionableError { 53 | return &wrappedError{e, ERROR_REFUSE_CIRCUIT, reason, 0} 54 | } 55 | 56 | func CloseConnection(e error) ActionableError { 57 | return &wrappedError{e, ERROR_CLOSE_CONNECTION, 0, 0} 58 | } 59 | 60 | func CloseStream(e error, reason StreamEndReason) ActionableError { 61 | return &wrappedError{e, ERROR_CLOSE_STREAM, 0, reason} 62 | } 63 | 64 | func RefuseStream(e error, reason StreamEndReason) ActionableError { 65 | return &wrappedError{e, ERROR_REFUSE_STREAM, 0, reason} 66 | } 67 | -------------------------------------------------------------------------------- /exitpolicy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | ) 11 | 12 | type ExitRule struct { 13 | Address []byte 14 | Port uint16 15 | Action bool 16 | V6 bool 17 | } 18 | 19 | type ExitPolicy struct { 20 | // The "zero value" of this struct is a "reject *:*" 21 | Rules []ExitRule 22 | DefaultAction bool 23 | } 24 | 25 | func (ep *ExitPolicy) AllowsConnect(addr []byte, port uint16) bool { 26 | for _, rule := range ep.Rules { 27 | if rule.Port == port || rule.Port == 0 { // ":port" or ":*" 28 | if rule.Address == nil { // "*:port" or "*:*" 29 | return rule.Action 30 | } 31 | 32 | if len(rule.Address) == len(addr) { 33 | matches := true 34 | for i := 0; i < len(addr); i++ { 35 | if rule.Address[i] != addr[i] { 36 | matches = false 37 | break 38 | } 39 | } 40 | if matches { 41 | return rule.Action 42 | } 43 | } 44 | } 45 | } 46 | 47 | return ep.DefaultAction 48 | } 49 | 50 | func (ep *ExitPolicy) Describe() (string, error) { 51 | var buf bytes.Buffer 52 | var v6buf bytes.Buffer 53 | 54 | for _, rule := range ep.Rules { 55 | if rule.V6 { 56 | 57 | } else { 58 | if rule.Action { 59 | buf.WriteString("accept ") 60 | } else { 61 | buf.WriteString("reject ") 62 | } 63 | 64 | if rule.Address != nil { 65 | panic("todo") // XXX BUG 66 | } else { 67 | buf.WriteString("*:") 68 | } 69 | 70 | if rule.Port != 0 { 71 | buf.WriteString(fmt.Sprintf("%d\n", rule.Port)) 72 | } else { 73 | buf.WriteString("*\n") 74 | } 75 | } 76 | } 77 | 78 | return buf.String() + v6buf.String(), nil 79 | } 80 | -------------------------------------------------------------------------------- /extend.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "errors" 9 | ) 10 | 11 | func (c *OnionConnection) handleRelayExtend(circ *Circuit, cell *RelayCell) ActionableError { 12 | data := cell.Data() 13 | 14 | Log(LOG_CIRC, "Got extend!") 15 | 16 | if circ.nextHop != nil { 17 | return CloseCircuit(errors.New("We already have a next hop."), DESTROY_REASON_PROTOCOL) 18 | } 19 | 20 | if circ.extendState != nil { 21 | return CloseCircuit(errors.New("Refusing attempt to extend a circuit twice"), DESTROY_REASON_PROTOCOL) 22 | } 23 | 24 | if len(data) != 212 { 25 | return CloseCircuit(errors.New("malformed EXTEND cell"), DESTROY_REASON_PROTOCOL) 26 | } 27 | 28 | // Check that we're not connecting back to the source 29 | if c.theyAuthenticated { 30 | sameFP := true 31 | for i := 0; i < 20; i++ { 32 | if c.theirFingerprint[i] != data[192+i] { 33 | sameFP = false 34 | break 35 | } 36 | } 37 | if sameFP { 38 | return CloseCircuit(errors.New("not extending to the source"), DESTROY_REASON_PROTOCOL) 39 | } 40 | } 41 | 42 | circReq := &CircuitRequest{} 43 | circReq.connHint.AddAddress(data[0:6]) 44 | circReq.connHint.AddFingerprint(data[192:212]) 45 | 46 | circReq.handshakeData = make([]byte, 186) 47 | copy(circReq.handshakeData, data[6:192]) 48 | 49 | circReq.handshakeType = uint16(HANDSHAKE_TAP) 50 | circReq.successQueue = c.circuitReadQueue 51 | circReq.newHandshake = false 52 | circReq.localID = circ.id 53 | circReq.handshakeState = &CircuitHandshakeState{} 54 | 55 | circ.extendState = circReq.handshakeState 56 | 57 | if err := c.parentOR.RequestCircuit(circReq); err != nil { 58 | return CloseCircuit(err, DESTROY_REASON_INTERNAL) 59 | } 60 | 61 | return nil 62 | } 63 | 64 | func (c *OnionConnection) handleRelayExtend2(circ *Circuit, cell *RelayCell) ActionableError { 65 | Log(LOG_CIRC, "got extend") 66 | 67 | data := cell.Data() 68 | nspec := int(data[0]) 69 | if 1+(nspec*2)+4 > len(data) { 70 | return CloseCircuit(errors.New("malformed EXTEND cell"), DESTROY_REASON_PROTOCOL) 71 | } 72 | 73 | if circ.nextHop != nil { 74 | return CloseCircuit(errors.New("We already have a next hop."), DESTROY_REASON_PROTOCOL) 75 | } 76 | 77 | if circ.extendState != nil { 78 | return CloseCircuit(errors.New("Refusing attempt to extend a circuit twice"), DESTROY_REASON_PROTOCOL) 79 | } 80 | 81 | circReq := &CircuitRequest{} 82 | circReq.newHandshake = true 83 | 84 | readPos := 1 85 | for i := 0; i < nspec; i++ { 86 | lstype := data[readPos] 87 | lslen := int(data[readPos+1]) 88 | readPos += 2 89 | if readPos+lslen > len(data)-4 { 90 | return CloseCircuit(errors.New("malformed EXTEND cell"), DESTROY_REASON_PROTOCOL) 91 | } 92 | 93 | lsdata := data[readPos : readPos+lslen] 94 | readPos += lslen 95 | 96 | if lstype == 0 || lstype == 1 { 97 | if err := circReq.connHint.AddAddress(lsdata); err != nil { 98 | return CloseCircuit(err, DESTROY_REASON_PROTOCOL) 99 | } 100 | 101 | } else if lstype == 2 { 102 | if err := circReq.connHint.AddFingerprint(lsdata); err != nil { 103 | return CloseCircuit(err, DESTROY_REASON_PROTOCOL) 104 | } 105 | 106 | // Check that we're not connecting back to the source 107 | if c.theyAuthenticated { 108 | sameFP := true 109 | for i := 0; i < 20; i++ { 110 | if c.theirFingerprint[i] != lsdata[i] { 111 | sameFP = false 112 | break 113 | } 114 | } 115 | if sameFP { 116 | return CloseCircuit(errors.New("not extending to the source"), DESTROY_REASON_PROTOCOL) 117 | } 118 | } 119 | 120 | } else { 121 | Log(LOG_INFO, "ignoring unknown link specifier type %d", lstype) 122 | } 123 | } 124 | 125 | htype := BigEndian.Uint16(data[readPos : readPos+2]) 126 | hlen := int(BigEndian.Uint16(data[readPos+2 : readPos+4])) 127 | readPos += 4 128 | if len(data) < readPos+hlen { 129 | return CloseCircuit(errors.New("malformed EXTEND cell"), DESTROY_REASON_PROTOCOL) 130 | } 131 | 132 | if nspec < 2 { 133 | return CloseCircuit(errors.New("EXTEND cell is super small.."), DESTROY_REASON_PROTOCOL) 134 | } 135 | 136 | circReq.handshakeData = make([]byte, hlen) // XXX use a cellbuf 137 | copy(circReq.handshakeData, data[readPos:readPos+hlen]) 138 | 139 | circReq.handshakeType = htype 140 | circReq.successQueue = c.circuitReadQueue 141 | circReq.localID = circ.id 142 | circReq.handshakeState = &CircuitHandshakeState{} 143 | 144 | circ.extendState = circReq.handshakeState 145 | 146 | if err := c.parentOR.RequestCircuit(circReq); err != nil { 147 | return CloseCircuit(err, DESTROY_REASON_INTERNAL) 148 | } 149 | 150 | return nil 151 | } 152 | 153 | func (c *OnionConnection) handleCreated(cell Cell, newHandshake bool) ActionableError { 154 | circ, ok := c.relayCircuits[cell.CircID()] 155 | if !ok { 156 | return RefuseCircuit(errors.New(cell.Command().String()+": no such circuit?"), DESTROY_REASON_PROTOCOL) 157 | } 158 | 159 | Log(LOG_CIRC, "got a created: %d", cell.CircID()) 160 | 161 | data := cell.Data() 162 | hlen := 148 163 | pos := 0 164 | if newHandshake { 165 | hlen = int(BigEndian.Uint16(data[0:2])) 166 | pos = 2 167 | } 168 | if hlen+pos > len(data) { 169 | return CloseCircuit(errors.New(cell.Command().String()+" cell badly formed"), DESTROY_REASON_PROTOCOL) 170 | } 171 | 172 | hdata := make([]byte, hlen) // XXX use a cellbuf 173 | copy(hdata, data[pos:pos+hlen]) 174 | 175 | // Relay the good news 176 | circ.previousHop <- &CircuitCreated{ 177 | id: circ.theirID, 178 | handshakeData: hdata, 179 | newHandshake: newHandshake, 180 | } 181 | 182 | return nil 183 | } 184 | 185 | func (data *CircuitCreated) Handle(c *OnionConnection, circ *Circuit) ActionableError { 186 | if circ.nextHop != nil { 187 | panic("We managed to create two circuits?") 188 | } 189 | if circ.extendState == nil { 190 | panic("we didn't expect to extend") // XXX this could maybe be triggered by a client? 191 | } 192 | 193 | extendState := circ.extendState 194 | circ.nextHop = extendState.nextHop 195 | circ.nextHopID = extendState.nextHopID 196 | circ.extendState = nil 197 | 198 | if data.newHandshake { 199 | cell := GetCellBuf(false) 200 | defer ReturnCellBuf(cell) // XXX such a waste 201 | BigEndian.PutUint16(cell[0:2], uint16(len(data.handshakeData))) 202 | copy(cell[2:], data.handshakeData) 203 | 204 | // circuit streamid direction command data 205 | return c.sendRelayCell(circ, 0, BackwardDirection, RELAY_EXTENDED2, cell[0:2+len(data.handshakeData)]) 206 | } else { 207 | // circuit streamid direction command data 208 | return c.sendRelayCell(circ, 0, BackwardDirection, RELAY_EXTENDED, data.handshakeData) 209 | } 210 | } 211 | 212 | func (req *CircuitRequest) Handle(c *OnionConnection, notreallyanthingatall *Circuit) ActionableError { 213 | newID := c.NewCircID() 214 | 215 | req.handshakeState.lock.Lock() 216 | aborted := req.handshakeState.aborted 217 | if !aborted { 218 | req.handshakeState.nextHop = c.circuitReadQueue 219 | req.handshakeState.nextHopID = newID 220 | } 221 | req.handshakeState.lock.Unlock() 222 | 223 | if aborted { 224 | Log(LOG_INFO, "Aborting CREATE - origin is gone") 225 | return nil 226 | } 227 | 228 | cmd := CMD_CREATE2 229 | if !req.newHandshake { 230 | cmd = CMD_CREATE 231 | } 232 | writeCell := NewCell(c.negotiatedVersion, newID, cmd, nil) 233 | data := writeCell.Data() 234 | if req.newHandshake { 235 | BigEndian.PutUint16(data[0:2], uint16(req.handshakeType)) 236 | BigEndian.PutUint16(data[2:4], uint16(len(req.handshakeData))) 237 | copy(data[4:], req.handshakeData) 238 | } else { 239 | copy(data, req.handshakeData) 240 | } 241 | 242 | // XXX if they send data before the created2, it'll nicely work 243 | c.relayCircuits[writeCell.CircID()] = &RelayCircuit{ 244 | id: writeCell.CircID(), 245 | theirID: req.localID, 246 | previousHop: req.successQueue, 247 | } 248 | 249 | c.writeQueue <- writeCell.Bytes() 250 | 251 | return nil 252 | } 253 | -------------------------------------------------------------------------------- /handshake.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "crypto/hmac" 10 | "crypto/sha1" 11 | "crypto/sha256" 12 | "errors" 13 | "github.com/tvdw/openssl" 14 | "hash" 15 | "io" 16 | "net" 17 | "time" 18 | ) 19 | 20 | const OUR_MIN_VERSION = 4 21 | const OUR_MAX_VERSION = 4 22 | 23 | type LinkVersion uint16 24 | 25 | func (c *OnionConnection) negotiateVersionServer(conn io.Reader) error { 26 | readCell := GetCellBuf(false) 27 | defer ReturnCellBuf(readCell) 28 | 29 | // We expect a VERSIONS cell first... 30 | totalRead := 0 31 | for totalRead < 5 { 32 | bytes, err := conn.Read(readCell[totalRead:5]) 33 | totalRead += bytes 34 | if err != nil { 35 | return err 36 | } 37 | } 38 | 39 | // We now have the head of the variable length cell. Check whether it makes any sense 40 | circID := CircuitID(BigEndian.Uint16(readCell[0:2])) 41 | command := Command(readCell[2]) 42 | length := int(BigEndian.Uint16(readCell[3:5])) 43 | if (command != CMD_VERSIONS) || length == 0 || (length > 1024) || (length%2 != 0) || (circID != 0) { 44 | return errors.New("Dropping connection - VERSIONS cell seems weird") 45 | } 46 | 47 | // Read the rest of the VERSIONS cell 48 | buf := make([]byte, length) 49 | 50 | totalRead = 0 51 | for totalRead < length { 52 | bytes, err := conn.Read(buf[totalRead:]) 53 | totalRead += bytes 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | 59 | bestVersion := LinkVersion(0) 60 | for i := 0; i < (length / 2); i++ { 61 | version := LinkVersion(BigEndian.Uint16(buf[(i * 2):(i*2 + 2)])) 62 | if version < OUR_MIN_VERSION { 63 | continue 64 | } 65 | if version > OUR_MAX_VERSION { 66 | continue 67 | } 68 | if version > bestVersion { 69 | bestVersion = version 70 | } 71 | } 72 | 73 | if bestVersion == 0 { 74 | ssl := conn.(*openssl.Conn) 75 | Log(LOG_INFO, "unknown versions data: %v %v", buf, ssl.RemoteAddr()) 76 | return errors.New("Failed to negotiate a version") 77 | } 78 | 79 | c.negotiatedVersion = bestVersion 80 | 81 | writeCell := GetCellBuf(false) 82 | writeCell = writeCell[0:7] 83 | writeCell[0] = 0 84 | writeCell[1] = 0 85 | writeCell[2] = byte(CMD_VERSIONS) 86 | writeCell[3] = 0 87 | writeCell[4] = 2 88 | BigEndian.PutUint16(writeCell[5:7], uint16(c.negotiatedVersion)) 89 | 90 | c.writeQueue <- writeCell 91 | 92 | return nil 93 | } 94 | 95 | func (c *OnionConnection) negotiateVersionClient(conn io.Reader, readHash, writeHash hash.Hash) error { 96 | // Send a VERSIONS cell with the versions we support, then wait for their reply 97 | writeCell := GetCellBuf(false) 98 | writeCell = writeCell[0 : 5+(2*(OUR_MAX_VERSION-OUR_MIN_VERSION+1))] 99 | writeCell[0] = 0 100 | writeCell[1] = 0 101 | writeCell[2] = byte(CMD_VERSIONS) 102 | writeCell[3] = 0 103 | writeCell[4] = 2 * (OUR_MAX_VERSION - OUR_MIN_VERSION + 1) 104 | for i, v := 0, OUR_MIN_VERSION; v <= OUR_MAX_VERSION; v++ { 105 | writeCell[5+i] = 0 106 | writeCell[6+i] = byte(v) 107 | 108 | i += 2 109 | } 110 | writeHash.Write(writeCell) 111 | c.writeQueue <- writeCell 112 | 113 | var head [5]byte 114 | gotBytes := 0 115 | for gotBytes < 5 { 116 | bytes, err := conn.Read(head[gotBytes:]) 117 | gotBytes += bytes 118 | if err != nil { 119 | return err 120 | } 121 | } 122 | readHash.Write(head[:]) 123 | 124 | if head[0] != 0 || head[1] != 0 || head[2] != 7 { 125 | return errors.New("Doesn't look like a VERSIONS cell") 126 | } 127 | length := int(BigEndian.Uint16(head[3:5])) 128 | if length <= 0 { 129 | return errors.New("that's no VERSIONS cell") 130 | } 131 | if length > 1024 { 132 | return errors.New("incredibly long VERSIONS cell found") 133 | } 134 | 135 | readBuf := make([]byte, length) 136 | gotBytes = 0 137 | for gotBytes < length { 138 | bytes, err := conn.Read(readBuf[gotBytes:]) 139 | gotBytes += bytes 140 | if err != nil { 141 | return err 142 | } 143 | } 144 | readHash.Write(readBuf) 145 | 146 | best := 0 147 | for i := 0; i < gotBytes; i += 2 { 148 | vers := int(BigEndian.Uint16(readBuf[i : i+2])) 149 | if vers >= OUR_MIN_VERSION && vers <= OUR_MAX_VERSION && vers > best { 150 | best = vers 151 | } 152 | } 153 | 154 | if best == 0 { 155 | return errors.New("No versions in common") 156 | } 157 | 158 | c.negotiatedVersion = LinkVersion(best) 159 | 160 | return nil 161 | } 162 | 163 | func (c *OnionConnection) sendCerts(writeHash hash.Hash) error { // Now that we've established a version, we need to send our CERTS 164 | var der1, der2 []byte 165 | var type1, type2 byte 166 | if c.isOutbound { 167 | type1 = 3 168 | der1 = c.usedTLSCtx.AuthCertDER 169 | } else { 170 | type1 = 1 171 | der1 = c.usedTLSCtx.LinkCertDER 172 | } 173 | type2 = 2 174 | der2 = c.usedTLSCtx.IdCertDER 175 | 176 | certsLen := 1 + (1 + 2 + len(der1)) + (1 + 2 + len(der2)) 177 | cell := NewVarCell(c.negotiatedVersion, 0, CMD_CERTS, nil, certsLen) 178 | buf := cell.Data() // XXX we still have the 2 length bytes there, lol 179 | 180 | buf[2] = 2 // 2 certs 181 | buf[3] = type1 182 | BigEndian.PutUint16(buf[4:6], uint16(len(der1))) 183 | copy(buf[6:], der1) 184 | ptr := 6 + len(der1) 185 | buf[ptr] = type2 186 | BigEndian.PutUint16(buf[ptr+1:ptr+3], uint16(len(der2))) 187 | copy(buf[ptr+3:], der2) 188 | 189 | if writeHash != nil { 190 | writeHash.Write(cell.Bytes()) 191 | } 192 | c.writeQueue <- cell.Bytes() 193 | 194 | return nil 195 | } 196 | 197 | func (c *OnionConnection) sendNetinfo(writeHash hash.Hash) error { 198 | cell := NewCell(c.negotiatedVersion, 0, CMD_NETINFO, nil) 199 | buf := cell.Data() 200 | 201 | // XXX TODO 202 | t := time.Now().Unix() 203 | BigEndian.PutUint32(buf[0:4], uint32(t)) 204 | buf[4] = 4 205 | buf[5] = 4 206 | buf[6] = 10 207 | buf[7] = 0 208 | buf[8] = 0 209 | buf[9] = 1 210 | 211 | myIP := net.ParseIP(c.parentOR.config.Address) 212 | buf[10] = 1 213 | buf[11] = 4 214 | buf[12] = 4 215 | 216 | ip := myIP.To4() 217 | copy(buf[13:], ip) //XXX v6 218 | 219 | if writeHash != nil { // XXX 220 | writeHash.Write(cell.Bytes()) 221 | } 222 | c.writeQueue <- cell.Bytes() 223 | 224 | return nil 225 | } 226 | 227 | func (c *OnionConnection) sendAuthChallenge() error { 228 | var buf bytes.Buffer 229 | if c.negotiatedVersion >= 4 { 230 | buf.Write([]byte{0, 0}) // XXX This is a pretty dirty hack. use NewVarCell() instead 231 | } 232 | buf.Write([]byte{0, 0, byte(CMD_AUTH_CHALLENGE), 0, (4 + 32)}) 233 | 234 | var challenge [32]byte 235 | CRandBytes(challenge[:]) 236 | buf.Write(challenge[:]) 237 | buf.Write([]byte{0, 1, 0, 1}) 238 | 239 | c.writeQueue <- buf.Bytes() 240 | 241 | return nil 242 | } 243 | 244 | func (c *OnionConnection) handleAuthChallenge(cell Cell, hashInbound, hashOutbound hash.Hash, conn *openssl.Conn) error { 245 | if c.weAuthenticated { 246 | return errors.New("But we already authenticated...") 247 | } 248 | if !c.theyAuthenticated { 249 | return errors.New("But we have no idea who they are...") 250 | } 251 | c.weAuthenticated = true 252 | 253 | // Start inspecting the actual data 254 | data := cell.Data() 255 | if len(data) < 38 { // This includes the 2 length bytes of the varlen cell 256 | return errors.New("cell too impossibly short") 257 | } 258 | //challengeData := data[2:34] 259 | methodCount := int(BigEndian.Uint16(data[34:36])) 260 | if len(data) != 36+(2*methodCount) { 261 | return errors.New("cell size is wrong") 262 | } 263 | 264 | canAuth := false 265 | for i := 0; i < methodCount; i++ { 266 | if data[36+2*i] == 0 && data[37+2*i] == 1 { 267 | canAuth = true 268 | } 269 | } 270 | 271 | if !canAuth { 272 | Log(LOG_INFO, "looks like they invented a new AUTHENTICATE thing") 273 | return nil // It's fine 274 | } 275 | 276 | if err := c.sendCerts(hashOutbound); err != nil { 277 | return err 278 | } 279 | 280 | // Send AUTHENTICATE 281 | var buf bytes.Buffer 282 | sha := sha256.New() 283 | 284 | buf.Write([]byte{0, 1, 0, 0}) 285 | buf.Write([]byte("AUTH0001")) 286 | buf.Write(c.usedTLSCtx.Fingerprint256) 287 | buf.Write(c.theirFingerprint256) 288 | buf.Write(hashInbound.Sum(nil)) 289 | buf.Write(hashOutbound.Sum(nil)) 290 | 291 | theirCert, err := conn.PeerCertificate() 292 | if err != nil { 293 | return err 294 | } 295 | DER, err := theirCert.MarshalDER() 296 | if err != nil { 297 | return err 298 | } 299 | sha.Write(DER) 300 | buf.Write(sha.Sum(nil)) 301 | 302 | mac := hmac.New(sha256.New, conn.GetTLSSecret()) 303 | mac.Write(conn.GetClientServerHelloRandom()) 304 | mac.Write([]byte("Tor V3 handshake TLS cross-certification\x00")) 305 | buf.Write(mac.Sum(nil)) 306 | 307 | // Add 24 random bytes 308 | var rand [24]byte 309 | CRandBytes(rand[:]) 310 | buf.Write(rand[:]) 311 | 312 | // Sign the rest and add the signature 313 | sha.Reset() 314 | sha.Write(buf.Bytes()[4:]) 315 | digest := sha.Sum(nil) 316 | sig, err := c.usedTLSCtx.AuthKey.PrivateEncrypt(digest[:]) 317 | if err != nil { 318 | return err 319 | } 320 | buf.Write(sig) 321 | 322 | tmpdata := buf.Bytes() 323 | BigEndian.PutUint16(tmpdata[2:4], uint16(len(tmpdata)-4)) 324 | 325 | c.writeQueue <- NewVarCell(c.negotiatedVersion, 0, CMD_AUTHENTICATE, tmpdata, 0).Bytes() 326 | 327 | return nil 328 | } 329 | 330 | func (c *OnionConnection) handleCerts(cell Cell, cert *openssl.Certificate) error { 331 | data := cell.Data() 332 | if len(data) < 3 { 333 | return errors.New("way too short") 334 | } 335 | 336 | var typeHad [4]bool 337 | var fp Fingerprint 338 | var fp256 []byte 339 | 340 | numCerts := int(data[2]) 341 | readPos := 3 342 | for i := 0; i < numCerts; i++ { 343 | if len(data) < readPos+3 { 344 | return errors.New("malformed CERTS") 345 | } 346 | 347 | cType := data[readPos] 348 | if cType < 1 || cType > 3 { 349 | return errors.New("no idea what to do with that certificate") 350 | } 351 | 352 | if typeHad[cType] { 353 | return errors.New("duplicate certificate in CERTS") 354 | } 355 | typeHad[cType] = true 356 | 357 | length := int(BigEndian.Uint16(data[readPos+1 : readPos+3])) 358 | readPos += 3 359 | if len(data) < readPos+length { 360 | return errors.New("malformed CERTS") 361 | } 362 | 363 | theCert, err := openssl.LoadCertificateFromDER(data[readPos : readPos+length]) 364 | if err != nil { 365 | return err 366 | } 367 | 368 | // XXX todo: lots of checks 369 | 370 | if cType == 2 { // ID 371 | // Find the fingerprint 372 | pubkey, err := theCert.PublicKey() 373 | if err != nil { 374 | return err 375 | } 376 | 377 | keyDer, err := pubkey.MarshalPKCS1PublicKeyDER() 378 | if err != nil { 379 | return err 380 | } 381 | 382 | fingerprint := sha1.Sum(keyDer) 383 | copy(fp[:], fingerprint[:]) 384 | 385 | sha := sha256.New() 386 | sha.Write(keyDer) 387 | fp256 = sha.Sum(nil) 388 | } 389 | 390 | readPos += length 391 | } 392 | 393 | Log(LOG_CIRC, "CERTS are looking good") 394 | 395 | if typeHad[2] { // ID 396 | c.theyAuthenticated = true 397 | copy(c.theirFingerprint[:], fp[:]) 398 | c.theirFingerprint256 = fp256 399 | } 400 | 401 | return nil 402 | } 403 | -------------------------------------------------------------------------------- /hybrid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "github.com/tvdw/gotor/aes" 9 | "github.com/tvdw/openssl" 10 | ) 11 | 12 | func HybridDecrypt(priv openssl.PrivateKey, d []byte) ([]byte, error) { 13 | // XXX this could probably be optimized a little 14 | 15 | res, err := priv.Decrypt(d[0:128]) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | if len(res) < 86 { 21 | return res, nil 22 | } 23 | 24 | data1 := res[16:86] 25 | aes := aes.New(res[0:16], make([]byte, 16)) 26 | 27 | res2 := make([]byte, len(d)-128) 28 | res2, err = aes.Crypt(d[128:len(d)], res2) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | finalRes := make([]byte, len(data1)+len(res2)) 34 | copy(finalRes, data1) 35 | copy(finalRes[len(data1):], res2) 36 | 37 | return finalRes, nil 38 | } 39 | -------------------------------------------------------------------------------- /kdf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "crypto/hmac" 9 | "crypto/sha1" 10 | "crypto/sha256" 11 | ) 12 | 13 | func KDFTOR(bytes int, random []byte) []byte { 14 | tmp := make([]byte, len(random)+1) 15 | copy(tmp, random) 16 | 17 | result := make([]byte, bytes+(20-(bytes%20))) 18 | for i, left := 0, bytes; left > 0; left -= 20 { 19 | tmp[len(random)] = byte(i) 20 | sha := sha1.Sum(tmp) 21 | copy(result[20*i:20*(i+1)], sha[:]) 22 | 23 | i++ 24 | } 25 | 26 | return result[:bytes] 27 | } 28 | 29 | func KDFHKDF(bytes int, secretInput, key, mExpand []byte) []byte { 30 | if bytes == 0 { 31 | return nil 32 | } 33 | 34 | result := make([]byte, bytes+(32-(bytes%32))) 35 | 36 | // Calculate "KEY_SEED" 37 | kSeed := hmac.New(sha256.New, key) 38 | kSeed.Write(secretInput) 39 | keySeed := kSeed.Sum(nil) 40 | mac := hmac.New(sha256.New, keySeed) 41 | 42 | var singleByte [1]byte 43 | singleByte[0] = 1 44 | 45 | mac.Write(mExpand) 46 | mac.Write(singleByte[:]) 47 | copy(result[0:32], mac.Sum(nil)) 48 | 49 | gotBytes := 32 50 | i := 0 51 | for bytes > gotBytes { 52 | mac.Reset() 53 | i++ 54 | 55 | mac.Write(result[gotBytes-32 : gotBytes]) 56 | mac.Write(mExpand) 57 | singleByte[0] = byte(i + 1) 58 | mac.Write(singleByte[:]) 59 | 60 | copy(result[gotBytes:gotBytes+32], mac.Sum(nil)) 61 | 62 | gotBytes += 32 63 | } 64 | 65 | return result[0:bytes] 66 | } 67 | -------------------------------------------------------------------------------- /kdf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "testing" 11 | ) 12 | 13 | func TestKDFHKDF(t *testing.T) { 14 | key := []byte("ntor-curve25519-sha256-1:key_extract") 15 | expand := []byte("ntor-curve25519-sha256-1:key_expand") 16 | 17 | // Test cases shamelessly stolen from the Tor source 18 | 19 | result := fmt.Sprintf("%x", KDFHKDF(100, []byte(""), key, expand)) 20 | expect := "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cdd7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8" 21 | if result != expect { 22 | log.Println(result) 23 | log.Println(expect) 24 | t.FailNow() 25 | } 26 | 27 | result = fmt.Sprintf("%x", KDFHKDF(100, []byte("Tor"), key, expand)) 28 | expect = "5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d66c4a3c4d6225429b3a016e3c3d45911152fc87bc2de9630c3961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac" 29 | 30 | if result != expect { 31 | log.Println(result) 32 | log.Println(expect) 33 | t.FailNow() 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "github.com/tvdw/cgolock" 9 | "log" 10 | "net/http" 11 | "os" 12 | "runtime" 13 | "time" 14 | ) 15 | 16 | import _ "net/http/pprof" 17 | import _ "expvar" 18 | 19 | func main() { 20 | cgolock.Init(runtime.NumCPU()) 21 | runtime.GOMAXPROCS(runtime.NumCPU()) 22 | SetupRand() 23 | SeedCellBuf() 24 | 25 | torConfig := Config{ 26 | IsPublicServer: true, 27 | Platform: "Tor 0.2.6.2-alpha on Go", 28 | BandwidthAvg: 1073741824, 29 | BandwidthBurst: 1073741824, 30 | BandwidthObserved: 1 << 16, 31 | } 32 | if err := torConfig.ReadFile(os.Args[1]); err != nil { 33 | log.Panicln(err) 34 | } 35 | 36 | or, err := NewOR(&torConfig) 37 | if err != nil { 38 | log.Panicln(err) 39 | } 40 | 41 | /* 42 | go func() { 43 | or.RequestCircuit(&CircuitRequest{ 44 | localID: 5, 45 | connHint: ConnectionHint{ 46 | address: [][]byte{[]byte{127,0,0,1,35,41}}, 47 | }, 48 | }) 49 | }() 50 | */ 51 | 52 | anythingFinished := make(chan int) 53 | go func() { 54 | or.Run() 55 | anythingFinished <- 1 56 | }() 57 | go func() { 58 | Log(LOG_WARN, "%v", http.ListenAndServe("localhost:6060", nil)) 59 | }() 60 | 61 | or.PublishDescriptor() 62 | 63 | nextRotate := time.After(time.Hour * 1) 64 | nextPublish := time.After(time.Hour * 18) 65 | for { 66 | select { 67 | case <-nextRotate: //XXX randomer intervals 68 | if err := or.RotateKeys(); err != nil { 69 | Log(LOG_WARN, "%v", err) 70 | } 71 | nextRotate = time.After(time.Hour * 1) 72 | 73 | case <-nextPublish: 74 | or.PublishDescriptor() 75 | nextPublish = time.After(time.Hour * 18) 76 | 77 | case <-anythingFinished: 78 | log.Panicln("Somehow a main.go goroutine we spawned managed to finish, which is not good") 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /onionconnection.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "crypto/sha256" 9 | "io" 10 | "net" 11 | ) 12 | 13 | const READ_QUEUE_LENGTH = 100 14 | const WRITE_QUEUE_LENGTH = 2000 15 | const CIRC_QUEUE_LENGTH = 2000 16 | 17 | type CircReadQueue chan CircuitCommand 18 | 19 | type OnionConnection struct { 20 | parentOR *ORCtx 21 | readQueue chan Cell 22 | circuitReadQueue CircReadQueue 23 | writeQueue chan []byte 24 | circuits map[CircuitID]*Circuit 25 | relayCircuits map[CircuitID]*RelayCircuit 26 | 27 | usedTLSCtx *TorTLS 28 | negotiatedVersion LinkVersion 29 | 30 | isOutbound bool 31 | weAuthenticated bool 32 | theyAuthenticated bool 33 | theirFingerprint Fingerprint 34 | theirFingerprint256 []byte 35 | } 36 | 37 | func newOnionConnection(tlsctx *TorTLS, or *ORCtx) *OnionConnection { 38 | StatsAddConnection() 39 | 40 | return &OnionConnection{ 41 | usedTLSCtx: tlsctx, 42 | circuits: make(map[CircuitID]*Circuit), 43 | relayCircuits: make(map[CircuitID]*RelayCircuit), 44 | readQueue: make(chan Cell, READ_QUEUE_LENGTH), 45 | writeQueue: make(chan []byte, WRITE_QUEUE_LENGTH), 46 | circuitReadQueue: make(CircReadQueue, CIRC_QUEUE_LENGTH), 47 | parentOR: or, 48 | } 49 | } 50 | 51 | func (c *OnionConnection) cleanup() { 52 | StatsRemoveConnection() 53 | 54 | if c.theyAuthenticated { 55 | if err := c.parentOR.EndConnection(c.theirFingerprint, c); err != nil { 56 | Log(LOG_NOTICE, "Warning during deregistration: %s", err) 57 | } 58 | } 59 | 60 | close(c.writeQueue) 61 | 62 | for _, circ := range c.relayCircuits { 63 | c.destroyRelayCircuit(circ, true, false, DESTROY_REASON_OR_CONN_CLOSED) 64 | } 65 | c.relayCircuits = nil 66 | 67 | for _, circ := range c.circuits { 68 | c.destroyCircuit(circ, true, false, DESTROY_REASON_OR_CONN_CLOSED) 69 | } 70 | c.circuits = nil 71 | 72 | // It is guaranteed that after calling EndConnection we will no longer receive any CircuitRequest 73 | // So just process whatever was left. 74 | readTheQueue: 75 | for { 76 | select { 77 | case cmd := <-c.circuitReadQueue: 78 | creationRequest, ok := cmd.(*CircuitRequest) 79 | if ok { 80 | creationRequest.successQueue <- &CircuitDestroyed{ 81 | reason: 8, // OR_CONN_CLOSED 82 | id: creationRequest.localID, 83 | //truncate: true, 84 | } 85 | } 86 | 87 | cmd.ReleaseBuffers() 88 | default: 89 | break readTheQueue 90 | } 91 | } 92 | } 93 | 94 | func HandleORConnClient(or *ORCtx, conn net.Conn, req *CircuitRequest) { 95 | // XXX WTF BUG: The Tor spec requires us to allow AUTHORIZE/VPADDING before VERSIONS 96 | 97 | tlsConn, usedTLSCtx, err := or.WrapTLS(conn, true) 98 | if err != nil { 99 | Log(LOG_WARN, "%s", err) 100 | if req != nil { 101 | req.successQueue <- &CircuitDestroyed{ 102 | reason: 2, //INTERNAL 103 | id: req.localID, 104 | //truncate: true, 105 | } 106 | } 107 | return 108 | } 109 | defer tlsConn.Close() 110 | 111 | me := newOnionConnection(usedTLSCtx, or) 112 | me.isOutbound = true 113 | 114 | if req != nil { 115 | me.circuitReadQueue <- req 116 | req = nil 117 | } 118 | 119 | defer me.cleanup() 120 | 121 | hash_inbound := sha256.New() 122 | hash_outbound := sha256.New() 123 | 124 | // Spawn the reader later - we still need to negotiate the version 125 | go me.writer(tlsConn) 126 | 127 | if err := me.negotiateVersionClient(tlsConn, hash_inbound, hash_outbound); err != nil { 128 | Log(LOG_INFO, "%s", err) 129 | return 130 | } 131 | 132 | go me.reader(tlsConn) 133 | 134 | Log(LOG_CIRC, "Negotiated version %d", me.negotiatedVersion) 135 | 136 | handshake: 137 | for { 138 | cell, ok := <-me.readQueue 139 | if !ok { 140 | Log(LOG_CIRC, "Connection closed") 141 | return 142 | } 143 | 144 | hash_inbound.Write(cell.Bytes()) 145 | 146 | Log(LOG_CIRC, "pre-runloop got a %s", cell.Command()) 147 | 148 | switch cell.Command() { 149 | case CMD_NETINFO: 150 | me.sendNetinfo(hash_outbound) 151 | break handshake 152 | 153 | case CMD_PADDING, CMD_VPADDING: 154 | // Ignore 155 | 156 | case CMD_AUTH_CHALLENGE: 157 | err := me.handleAuthChallenge(cell, hash_inbound, hash_outbound, tlsConn) 158 | if err != nil { 159 | Log(LOG_INFO, "%s", err) 160 | return 161 | } 162 | 163 | case CMD_CERTS: 164 | peerCert, err := tlsConn.PeerCertificate() 165 | if err = me.handleCerts(cell, peerCert); err != nil { 166 | Log(LOG_INFO, "%s", err) 167 | return 168 | } 169 | 170 | default: 171 | Log(LOG_NOTICE, "Cell %s not allowed. Disconnecting", cell.Command()) 172 | return 173 | } 174 | 175 | cell.ReleaseBuffers() 176 | } 177 | 178 | if me.theyAuthenticated { 179 | if err := or.RegisterConnection(me.theirFingerprint, me); err != nil { 180 | // No worries 181 | Log(LOG_INFO, "register warning: %s", err) 182 | } 183 | } 184 | 185 | hash_inbound = nil 186 | hash_outbound = nil 187 | me.Runloop() 188 | } 189 | 190 | func HandleORConnServer(or *ORCtx, conn net.Conn) { 191 | tlsConn, usedTLSCtx, err := or.WrapTLS(conn, false) 192 | if err != nil { 193 | Log(LOG_WARN, "%s", err) 194 | return 195 | } 196 | defer tlsConn.Close() // As soon as we leave this function, we make sure the connection is closed 197 | 198 | me := newOnionConnection(usedTLSCtx, or) 199 | me.isOutbound = false 200 | defer me.cleanup() 201 | 202 | // Spawn the reader later - we still need to negotiate the version 203 | go me.writer(tlsConn) 204 | 205 | if err := me.negotiateVersionServer(tlsConn); err != nil { 206 | Log(LOG_INFO, "%s", err) 207 | return 208 | } 209 | 210 | go me.reader(tlsConn) 211 | 212 | Log(LOG_CIRC, "Negotiated version %d", me.negotiatedVersion) 213 | 214 | if err := me.sendCerts(nil); err != nil { 215 | Log(LOG_INFO, "%s", err) 216 | return 217 | } 218 | me.weAuthenticated = true 219 | 220 | if err := me.sendAuthChallenge(); err != nil { 221 | Log(LOG_INFO, "%s", err) 222 | return 223 | } 224 | 225 | if err := me.sendNetinfo(nil); err != nil { 226 | Log(LOG_INFO, "%s", err) 227 | return 228 | } 229 | 230 | handshake: 231 | for { 232 | cell, ok := <-me.readQueue 233 | if !ok { 234 | Log(LOG_INFO, "readqueue stopped working") 235 | return 236 | } 237 | 238 | switch cell.Command() { 239 | case CMD_AUTHORIZE, CMD_PADDING, CMD_VPADDING: 240 | // Ignore 241 | case CMD_CERTS: 242 | if err := me.handleCerts(cell, nil); err != nil { 243 | Log(LOG_INFO, "%s", err) 244 | return 245 | } 246 | case CMD_AUTHENTICATE: 247 | // XXX 248 | case CMD_NETINFO: 249 | // Good 250 | break handshake 251 | default: 252 | // Not good 253 | Log(LOG_NOTICE, "Unexpected %s - dropping connection", cell.Command()) 254 | return 255 | } 256 | 257 | cell.ReleaseBuffers() 258 | } 259 | 260 | me.Runloop() 261 | } 262 | 263 | func (me *OnionConnection) Runloop() { 264 | Log(LOG_CIRC, "handshake done, runloop starting") 265 | 266 | for { 267 | var err ActionableError 268 | var circID CircuitID // XXX This is messed up. 269 | 270 | select { 271 | case cell, ok := <-me.readQueue: 272 | if !ok { 273 | return 274 | } 275 | 276 | circID = cell.CircID() 277 | 278 | if cell.Command() != CMD_PADDING { 279 | Log(LOG_DEBUG, "%s got a %s: %v", me.theirFingerprint, cell.Command(), cell) 280 | } 281 | 282 | err = me.routeCellToFunction(cell) 283 | cell.ReleaseBuffers() 284 | 285 | case circData := <-me.circuitReadQueue: 286 | circID = circData.CircID() 287 | 288 | err = me.routeCircuitCommandToFunction(circData) 289 | circData.ReleaseBuffers() 290 | } 291 | 292 | if err != nil { 293 | switch err.Handle() { 294 | case ERROR_CLOSE_CONNECTION: 295 | Log(LOG_NOTICE, "Closing connection: %s", err) 296 | return 297 | 298 | case ERROR_CLOSE_CIRCUIT: 299 | if circID == 0 { 300 | Log(LOG_WARN, "Got a ERROR_CLOSE_CIRCUIT for CircID=0. Disconnecting") 301 | return 302 | } 303 | 304 | me.writeQueue <- NewCell(me.negotiatedVersion, circID, CMD_DESTROY, []byte{byte(err.CircDestroyReason())}).Bytes() 305 | 306 | if circID.MSB(me.negotiatedVersion) != me.isOutbound { // Front 307 | circ, ok := me.circuits[circID] 308 | if !ok { 309 | Log(LOG_WARN, "Got a ERROR_CLOSE_CIRCUIT but don't know the circuit. Disconnecting. Original: %s", err) 310 | return 311 | } 312 | 313 | me.destroyCircuit(circ, true, true, err.CircDestroyReason()) 314 | Log(LOG_NOTICE, "Closing circuit: %s", err) 315 | 316 | } else { 317 | circ, ok := me.relayCircuits[circID] 318 | if !ok { 319 | Log(LOG_WARN, "Got a ERROR_CLOSE_CIRCUIT but don't know the circuit. Disconnecting. Original: %s", err) 320 | return 321 | } 322 | 323 | me.destroyRelayCircuit(circ, true, true, err.CircDestroyReason()) 324 | Log(LOG_NOTICE, "Closing relayCircuit: %s", err) 325 | } 326 | 327 | case ERROR_REFUSE_CIRCUIT: 328 | if circID == 0 { 329 | Log(LOG_WARN, "Got a ERROR_CLOSE_CIRCUIT for CircID=0. Disconnecting") 330 | return 331 | } 332 | 333 | me.writeQueue <- NewCell(me.negotiatedVersion, circID, CMD_DESTROY, []byte{byte(err.CircDestroyReason())}).Bytes() 334 | 335 | default: 336 | Log(LOG_WARN, "Disconnecting: not sure what to do with error %v", err) 337 | return 338 | } 339 | } 340 | } 341 | } 342 | 343 | func (c *OnionConnection) reader(conn io.Reader) { 344 | defer close(c.readQueue) 345 | 346 | var buffer [SSLRecordSize]byte 347 | readPos, decodePos := 0, 0 348 | for { 349 | bytes, err := conn.Read(buffer[readPos:]) 350 | if err != nil && bytes <= 0 { 351 | Log(LOG_INFO, "%s", err) 352 | return 353 | } 354 | readPos += bytes 355 | circLen := 4 356 | if c.negotiatedVersion < 4 { 357 | circLen = 2 358 | } 359 | 360 | for decodePos+3+circLen < readPos { // while we have enough data to figure out command && length 361 | if buffer[decodePos+circLen] == 7 || buffer[decodePos+circLen]&0x80 != 0 { // Variable length 362 | varLen := (int(buffer[decodePos+circLen+1]) << 8) + int(buffer[decodePos+circLen+2]) 363 | varLen += circLen + 3 // Don't forget about the cell overhead 364 | 365 | if varLen >= SSLRecordSize { 366 | Log(LOG_INFO, "Dropping connection with variable-length cell that is WAY too large") 367 | return 368 | } 369 | 370 | if readPos-decodePos >= varLen { 371 | var varCell []byte 372 | if varLen <= MAX_CELL_SIZE { 373 | varCell = GetCellBuf(false)[0:varLen] 374 | } else { 375 | varCell = make([]byte, varLen) 376 | } 377 | copy(varCell, buffer[decodePos:decodePos+varLen]) 378 | decodePos += varLen 379 | if c.negotiatedVersion < 4 { 380 | c.readQueue <- (*Cell3)(&varCell) 381 | } else { 382 | c.readQueue <- (*Cell4)(&varCell) 383 | } 384 | } else { 385 | break 386 | } 387 | 388 | } else { // Constant (514) length cell 389 | if readPos-decodePos >= 510+circLen { 390 | cell := GetCellBuf(false) 391 | copy(cell, buffer[decodePos:decodePos+510+circLen]) 392 | cell = cell[0 : 510+circLen] 393 | decodePos += 510 + circLen 394 | if c.negotiatedVersion < 4 { 395 | c.readQueue <- (*Cell3)(&cell) 396 | } else { 397 | c.readQueue <- (*Cell4)(&cell) 398 | } 399 | } else { 400 | break 401 | } 402 | } 403 | } 404 | 405 | if decodePos == readPos { 406 | decodePos = 0 407 | readPos = 0 408 | } else if decodePos > readPos { 409 | panic("BUG: we decoded more than we read") 410 | } else if decodePos != 0 { 411 | copy(buffer[:], buffer[decodePos:readPos]) 412 | readPos -= decodePos 413 | decodePos = 0 414 | } 415 | } 416 | } 417 | 418 | func (c *OnionConnection) writer(conn net.Conn) { 419 | defer func() { 420 | Log(LOG_INFO, "writer ended") 421 | conn.Close() 422 | }() 423 | 424 | var buffer [SSLRecordSize]byte 425 | var nextItem []byte 426 | 427 | for { 428 | if nextItem != nil { 429 | _, err := conn.Write(nextItem) 430 | if err != nil { 431 | Log(LOG_INFO, "%s", err) 432 | return 433 | } 434 | ReturnCellBuf(nextItem) 435 | nextItem = nil 436 | } 437 | 438 | select { 439 | case data, ok := <-c.writeQueue: 440 | if !ok { 441 | return 442 | } 443 | 444 | Log(LOG_DEBUG, "writing %d: %v", len(data), data) 445 | 446 | datalen := len(data) 447 | copy(buffer[:], data) 448 | ReturnCellBuf(data) 449 | 450 | extradata: 451 | for { // See if we got any extra data 452 | select { 453 | case data2, ok := <-c.writeQueue: 454 | if !ok { 455 | break extradata 456 | } 457 | 458 | if datalen+len(data2) > cap(buffer) { 459 | nextItem = data2 460 | break extradata 461 | } 462 | 463 | copy(buffer[datalen:], data2) 464 | datalen += len(data2) 465 | ReturnCellBuf(data2) 466 | 467 | if datalen+MAX_CELL_SIZE > cap(buffer) { 468 | break extradata 469 | } 470 | default: 471 | break extradata 472 | } 473 | } 474 | 475 | _, err := conn.Write(buffer[:datalen]) 476 | if err != nil { 477 | Log(LOG_INFO, "%s", err) 478 | return 479 | } 480 | } 481 | } 482 | } 483 | -------------------------------------------------------------------------------- /or.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "github.com/tvdw/gotor/tordir" 12 | "github.com/tvdw/openssl" 13 | "golang.org/x/crypto/curve25519" 14 | "io/ioutil" 15 | "net" 16 | "os" 17 | "sync" 18 | "time" 19 | ) 20 | 21 | type Fingerprint [20]byte 22 | 23 | func (fp Fingerprint) String() string { 24 | return fmt.Sprintf("%X", fp[:]) 25 | } 26 | 27 | type ORCtx struct { 28 | // For convenience we use net.Listen instead of delegating to openssl itself. 29 | // This allows us to very easily swap certificates as our listening socket doesn't reference a tls context 30 | listener net.Listener 31 | config *Config 32 | 33 | // Hold Fingerprint to OnionConnection mappings 34 | authenticatedConnections map[Fingerprint]*OnionConnection 35 | authConnLock sync.Mutex 36 | 37 | descriptor tordir.Descriptor 38 | 39 | identityKey, onionKey openssl.PrivateKey 40 | ntorPrivate, ntorPublic [32]byte 41 | 42 | clientTlsCtx, serverTlsCtx *TorTLS 43 | tlsLock sync.Mutex 44 | } 45 | 46 | func NewOR(torConf *Config) (*ORCtx, error) { 47 | connStr := fmt.Sprintf(":%d", torConf.ORPort) 48 | listener, err := net.Listen("tcp", connStr) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | ctx := &ORCtx{ 54 | listener: listener, 55 | authenticatedConnections: make(map[Fingerprint]*OnionConnection), 56 | config: torConf, 57 | } 58 | 59 | if _, err := os.Stat(torConf.DataDirectory + "/keys/secret_id_key"); os.IsNotExist(err) { 60 | Log(LOG_INFO, "Generating new keys") 61 | os.Mkdir(torConf.DataDirectory, 0755) 62 | os.Mkdir(torConf.DataDirectory+"/keys", 0700) 63 | 64 | { 65 | newIDKey, err := openssl.GenerateRSAKeyWithExponent(1024, 65537) 66 | if err != nil { 67 | return nil, err 68 | } 69 | newIDKeyPEM, err := newIDKey.MarshalPKCS1PrivateKeyPEM() 70 | if err != nil { 71 | return nil, err 72 | } 73 | if err := ioutil.WriteFile(torConf.DataDirectory+"/keys/secret_id_key", newIDKeyPEM, 0600); err != nil { 74 | return nil, err 75 | } 76 | } 77 | 78 | { 79 | newOnionKey, err := openssl.GenerateRSAKeyWithExponent(1024, 65537) 80 | if err != nil { 81 | return nil, err 82 | } 83 | newOnionKeyPEM, err := newOnionKey.MarshalPKCS1PrivateKeyPEM() 84 | if err != nil { 85 | return nil, err 86 | } 87 | if err := ioutil.WriteFile(torConf.DataDirectory+"/keys/secret_onion_key", newOnionKeyPEM, 0600); err != nil { 88 | return nil, err 89 | } 90 | } 91 | 92 | { 93 | var curveDataPriv [32]byte 94 | var curveDataPub [32]byte 95 | CRandBytes(curveDataPriv[0:32]) 96 | curveDataPriv[0] &= 248 97 | curveDataPriv[31] &= 127 98 | curveDataPriv[31] |= 64 99 | curve25519.ScalarBaseMult(&curveDataPub, &curveDataPriv) 100 | 101 | var buf bytes.Buffer 102 | buf.WriteString("== c25519v1: onion ==") 103 | for i := buf.Len(); i < 32; i++ { 104 | buf.Write([]byte{0}) 105 | } 106 | buf.Write(curveDataPriv[:]) 107 | buf.Write(curveDataPub[:]) 108 | if err := ioutil.WriteFile(torConf.DataDirectory+"/keys/secret_onion_key_ntor", buf.Bytes(), 0600); err != nil { 109 | return nil, err 110 | } 111 | } 112 | } 113 | 114 | { 115 | identityPem, err := ioutil.ReadFile(torConf.DataDirectory + "/keys/secret_id_key") 116 | if err != nil { 117 | return nil, err 118 | } 119 | identityPk, err := openssl.LoadPrivateKeyFromPEM(identityPem) 120 | if err != nil { 121 | return nil, err 122 | } 123 | ctx.identityKey = identityPk 124 | } 125 | { 126 | onionPem, err := ioutil.ReadFile(torConf.DataDirectory + "/keys/secret_onion_key") 127 | if err != nil { 128 | return nil, err 129 | } 130 | onionPk, err := openssl.LoadPrivateKeyFromPEM(onionPem) 131 | if err != nil { 132 | return nil, err 133 | } 134 | ctx.onionKey = onionPk 135 | } 136 | { 137 | ntorData, err := ioutil.ReadFile(torConf.DataDirectory + "/keys/secret_onion_key_ntor") 138 | if err != nil { 139 | return nil, err 140 | } 141 | if len(ntorData) != 96 { 142 | return nil, errors.New("ntor data corrupt") 143 | } 144 | copy(ctx.ntorPrivate[:], ntorData[32:64]) 145 | copy(ctx.ntorPublic[:], ntorData[64:96]) 146 | } 147 | 148 | if err := SetupTLS(ctx); err != nil { 149 | return nil, err 150 | } 151 | 152 | ctx.descriptor.UptimeStart = time.Now() 153 | 154 | return ctx, nil 155 | } 156 | 157 | func (or *ORCtx) RotateKeys() error { 158 | return SetupTLS(or) 159 | } 160 | 161 | func (or *ORCtx) UpdateDescriptor() { 162 | d := &or.descriptor 163 | d.Nickname = or.config.Nickname 164 | d.Contact = or.config.Contact 165 | d.Platform = or.config.Platform 166 | d.Address = net.ParseIP(or.config.Address) 167 | d.ORPort = or.config.ORPort 168 | d.OnionKey = or.onionKey 169 | d.SigningKey = or.identityKey 170 | d.BandwidthAvg = or.config.BandwidthAvg 171 | d.BandwidthBurst = or.config.BandwidthBurst 172 | d.BandwidthObserved = or.config.BandwidthObserved 173 | d.NTORKey = or.ntorPublic[:] 174 | d.Family = or.config.Family 175 | policy, err := or.config.ExitPolicy.Describe() 176 | if err != nil { 177 | Log(LOG_WARN, "%s", err) 178 | return 179 | } 180 | d.ExitPolicy = policy 181 | 182 | signed, err := d.SignedDescriptor() 183 | if err != nil { 184 | Log(LOG_WARN, "%s", err) 185 | return 186 | } 187 | 188 | Log(LOG_DEBUG, "%s", signed) 189 | } 190 | 191 | func (or *ORCtx) PublishDescriptor() error { 192 | if or.config.IsPublicServer { 193 | or.UpdateDescriptor() 194 | authorities := []string{"171.25.193.9:443", "86.59.21.38:80", "208.83.223.34:443", "199.254.238.52:80", "194.109.206.212:80", "131.188.40.189:80", "128.31.0.34:9131", "193.23.244.244:80", "154.35.32.5:80"} 195 | for _, auth := range authorities { 196 | if err := or.descriptor.Publish(auth); err != nil { 197 | Log(LOG_NOTICE, "%s", err) // XXX 198 | } 199 | } 200 | } 201 | return nil 202 | } 203 | 204 | func (or *ORCtx) Run() { 205 | for { 206 | conn, err := or.listener.Accept() 207 | if err != nil { 208 | Log(LOG_WARN, "%s", err) 209 | continue 210 | } 211 | 212 | // Handshake, etc 213 | go func() { 214 | defer conn.Close() 215 | Log(LOG_DEBUG, "%s says hi", conn.RemoteAddr()) 216 | HandleORConnServer(or, conn) 217 | }() 218 | } 219 | } 220 | 221 | func (or *ORCtx) RegisterConnection(fp Fingerprint, conn *OnionConnection) error { 222 | or.authConnLock.Lock() 223 | defer or.authConnLock.Unlock() 224 | 225 | _, ok := or.authenticatedConnections[fp] 226 | if ok { 227 | return errors.New("we already have this fingerprint registered") 228 | } 229 | 230 | Log(LOG_INFO, "registering a connection for fp %s", fp) 231 | or.authenticatedConnections[fp] = conn 232 | 233 | return nil 234 | } 235 | 236 | func (or *ORCtx) EndConnection(fp Fingerprint, conn *OnionConnection) error { 237 | or.authConnLock.Lock() 238 | defer or.authConnLock.Unlock() 239 | 240 | cur, ok := or.authenticatedConnections[fp] 241 | if !ok { 242 | return nil // Not an error 243 | } 244 | 245 | if cur != conn { 246 | return errors.New("mismatch: another connection is registered") 247 | } 248 | 249 | delete(or.authenticatedConnections, fp) 250 | 251 | return nil 252 | } 253 | 254 | func (or *ORCtx) RequestCircuit(req *CircuitRequest) error { 255 | or.authConnLock.Lock() 256 | defer or.authConnLock.Unlock() 257 | 258 | fp := req.connHint.GetFingerprint() 259 | if fp != nil { 260 | // XXX This needs to be a lot smarter (check IP addresses, etc) 261 | conn, ok := or.authenticatedConnections[*fp] 262 | if ok { 263 | conn.circuitReadQueue <- req 264 | return nil 265 | } 266 | } 267 | 268 | // Try and dial 269 | go func() { 270 | addresses := req.connHint.GetAddresses() 271 | for _, addr := range addresses { 272 | // Allow aborting connection attempts 273 | req.handshakeState.lock.Lock() 274 | aborted := req.handshakeState.aborted 275 | req.handshakeState.lock.Unlock() 276 | if aborted { 277 | Log(LOG_INFO, "Aborting connection attempt") 278 | return 279 | } 280 | 281 | // Now connect 282 | Log(LOG_INFO, "connecting to %s", addr) 283 | dialer := net.Dialer{Timeout: 5 * time.Second} 284 | conn, err := dialer.Dial("tcp", addr) 285 | if err != nil { 286 | Log(LOG_INFO, "%s", err) 287 | continue // Next address 288 | } 289 | 290 | defer conn.Close() 291 | HandleORConnClient(or, conn, req) 292 | return 293 | } 294 | 295 | // Bad luck but it does need to be reported 296 | req.successQueue <- &CircuitDestroyed{ 297 | id: req.localID, 298 | reason: 6, //CONNECTFAILED 299 | //truncate: true, 300 | } 301 | }() 302 | 303 | return nil 304 | } 305 | -------------------------------------------------------------------------------- /proto_definitions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import "fmt" 8 | 9 | type Command byte 10 | type RelayCommand byte 11 | type DestroyReason byte 12 | type StreamEndReason byte 13 | 14 | const ( 15 | CMD_PADDING Command = 0 16 | CMD_CREATE Command = 1 17 | CMD_CREATED Command = 2 18 | CMD_RELAY Command = 3 19 | CMD_DESTROY Command = 4 20 | CMD_CREATE_FAST Command = 5 21 | CMD_CREATED_FAST Command = 6 22 | CMD_VERSIONS Command = 7 23 | CMD_NETINFO Command = 8 24 | CMD_RELAY_EARLY Command = 9 25 | CMD_CREATE2 Command = 10 26 | CMD_CREATED2 Command = 11 27 | CMD_VPADDING Command = 128 28 | CMD_CERTS Command = 129 29 | CMD_AUTH_CHALLENGE Command = 130 30 | CMD_AUTHENTICATE Command = 131 31 | CMD_AUTHORIZE Command = 132 32 | ) 33 | 34 | const ( 35 | RELAY_BEGIN RelayCommand = 1 36 | RELAY_DATA RelayCommand = 2 37 | RELAY_END RelayCommand = 3 38 | RELAY_CONNECTED RelayCommand = 4 39 | RELAY_SENDME RelayCommand = 5 40 | RELAY_EXTEND RelayCommand = 6 41 | RELAY_EXTENDED RelayCommand = 7 42 | RELAY_TRUNCATE RelayCommand = 8 43 | RELAY_TRUNCATED RelayCommand = 9 44 | RELAY_DROP RelayCommand = 10 45 | RELAY_RESOLVE RelayCommand = 11 46 | RELAY_RESOLVED RelayCommand = 12 47 | RELAY_BEGIN_DIR RelayCommand = 13 48 | RELAY_EXTEND2 RelayCommand = 14 49 | RELAY_EXTENDED2 RelayCommand = 15 50 | ) 51 | 52 | const ( 53 | DESTROY_REASON_NONE DestroyReason = iota 54 | DESTROY_REASON_PROTOCOL 55 | DESTROY_REASON_INTERNAL 56 | DESTROY_REASON_REQUESTED 57 | DESTROY_REASON_HIBERNATING 58 | DESTROY_REASON_RESOURCELIMIT 59 | DESTROY_REASON_CONNECTFAILED 60 | DESTROY_REASON_OR_IDENTITY 61 | DESTROY_REASON_OR_CONN_CLOSED 62 | DESTROY_REASON_FINISHED 63 | DESTROY_REASON_TIMEOUT 64 | DESTROY_REASON_DESTROYED 65 | DESTROY_REASON_NOSUCHSERVICE 66 | ) 67 | 68 | const ( 69 | _ StreamEndReason = iota 70 | STREAM_REASON_MISC 71 | STREAM_REASON_RESOLVEFAILED 72 | STREAM_REASON_CONNECTREFUSED 73 | STREAM_REASON_EXITPOLICY 74 | STREAM_REASON_DESTROY 75 | STREAM_REASON_DONE 76 | STREAM_REASON_TIMEOUT 77 | STREAM_REASON_NOROUTE 78 | STREAM_REASON_HIBERNATING 79 | STREAM_REASON_INTERNAL 80 | STREAM_REASON_RESOURCELIMIT 81 | STREAM_REASON_CONNRESET 82 | STREAM_REASON_TORPROTOCOL 83 | STREAM_REASON_NOTDIRECTORY 84 | ) 85 | 86 | func (c Command) String() string { 87 | switch c { 88 | case CMD_PADDING: 89 | return "CMD_PADDING" 90 | case CMD_CREATE: 91 | return "CMD_CREATE" 92 | case CMD_CREATED: 93 | return "CMD_CREATED" 94 | case CMD_RELAY: 95 | return "CMD_RELAY" 96 | case CMD_DESTROY: 97 | return "CMD_DESTROY" 98 | case CMD_CREATE_FAST: 99 | return "CMD_CREATE_FAST" 100 | case CMD_CREATED_FAST: 101 | return "CMD_CREATED_FAST" 102 | case CMD_VERSIONS: 103 | return "CMD_VERSIONS" 104 | case CMD_NETINFO: 105 | return "CMD_NETINFO" 106 | case CMD_RELAY_EARLY: 107 | return "CMD_RELAY_EARLY" 108 | case CMD_CREATE2: 109 | return "CMD_CREATE2" 110 | case CMD_CREATED2: 111 | return "CMD_CREATED2" 112 | case CMD_VPADDING: 113 | return "CMD_VPADDING" 114 | case CMD_CERTS: 115 | return "CMD_CERTS" 116 | case CMD_AUTH_CHALLENGE: 117 | return "CMD_AUTH_CHALLENGE" 118 | case CMD_AUTHENTICATE: 119 | return "CMD_AUTHENTICATE" 120 | case CMD_AUTHORIZE: 121 | return "CMD_AUTHORIZE" 122 | default: 123 | return fmt.Sprintf("CMD_UNKNOWN_%d", c) 124 | } 125 | } 126 | 127 | func (c RelayCommand) String() string { 128 | switch c { 129 | case RELAY_BEGIN: 130 | return "RELAY_BEGIN" 131 | case RELAY_DATA: 132 | return "RELAY_DATA" 133 | case RELAY_END: 134 | return "RELAY_END" 135 | case RELAY_CONNECTED: 136 | return "RELAY_CONNECTED" 137 | case RELAY_SENDME: 138 | return "RELAY_SENDME" 139 | case RELAY_EXTEND: 140 | return "RELAY_EXTEND" 141 | case RELAY_EXTENDED: 142 | return "RELAY_EXTENDED" 143 | case RELAY_TRUNCATE: 144 | return "RELAY_TRUNCATE" 145 | case RELAY_TRUNCATED: 146 | return "RELAY_TRUNCATED" 147 | case RELAY_DROP: 148 | return "RELAY_DROP" 149 | case RELAY_RESOLVE: 150 | return "RELAY_RESOLVE" 151 | case RELAY_RESOLVED: 152 | return "RELAY_RESOLVED" 153 | case RELAY_BEGIN_DIR: 154 | return "RELAY_BEGIN_DIR" 155 | case RELAY_EXTEND2: 156 | return "RELAY_EXTEND2" 157 | case RELAY_EXTENDED2: 158 | return "RELAY_EXTENDED2" 159 | default: 160 | return fmt.Sprintf("RELAY_UNKNOWN_%d", c) 161 | } 162 | } 163 | 164 | func (d DestroyReason) String() string { 165 | switch d { 166 | case DESTROY_REASON_NONE: 167 | return "DESTROY_REASON_NONE" 168 | case DESTROY_REASON_PROTOCOL: 169 | return "DESTROY_REASON_PROTOCOL" 170 | case DESTROY_REASON_INTERNAL: 171 | return "DESTROY_REASON_INTERNAL" 172 | case DESTROY_REASON_REQUESTED: 173 | return "DESTROY_REASON_REQUESTED" 174 | case DESTROY_REASON_HIBERNATING: 175 | return "DESTROY_REASON_HIBERNATING" 176 | case DESTROY_REASON_RESOURCELIMIT: 177 | return "DESTROY_REASON_RESOURCELIMIT" 178 | case DESTROY_REASON_CONNECTFAILED: 179 | return "DESTROY_REASON_CONNECTFAILED" 180 | case DESTROY_REASON_OR_IDENTITY: 181 | return "DESTROY_REASON_OR_IDENTITY" 182 | case DESTROY_REASON_OR_CONN_CLOSED: 183 | return "DESTROY_REASON_OR_CONN_CLOSED" 184 | case DESTROY_REASON_FINISHED: 185 | return "DESTROY_REASON_FINISHED" 186 | case DESTROY_REASON_TIMEOUT: 187 | return "DESTROY_REASON_TIMEOUT" 188 | case DESTROY_REASON_DESTROYED: 189 | return "DESTROY_REASON_DESTROYED" 190 | case DESTROY_REASON_NOSUCHSERVICE: 191 | return "DESTROY_REASON_NOSUCHSERVICE" 192 | default: 193 | return fmt.Sprintf("DESTROY_REASON_%d", d) 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /rand.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | crand "crypto/rand" 9 | brand "math/rand" 10 | ) 11 | 12 | func SetupRand() error { 13 | // Seed our pseudo-random RNG with crpyto-random data 14 | seed := make([]byte, 8) 15 | _, err := crand.Read(seed) 16 | if err != nil { 17 | return err 18 | } 19 | 20 | s := int64(0) 21 | for i := 0; i < 8; i++ { 22 | s = s << 8 23 | s += int64(seed[i]) 24 | } 25 | brand.Seed(s) 26 | 27 | return nil 28 | } 29 | 30 | func CRandBytes(target []byte) error { 31 | _, err := crand.Read(target) 32 | return err 33 | } 34 | -------------------------------------------------------------------------------- /relay.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "regexp" 11 | "strconv" 12 | ) 13 | 14 | const MAX_RELAY_LEN = 514 - 11 - 5 15 | 16 | var regex_ip = `(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])` 17 | var regex_v6 = `\[[0-9a-fA-F:]{3,45}\]` 18 | var regex_host = `(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*(?:[A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])` 19 | var regex_streamtargetstr = `^(` + regex_ip + `|` + regex_v6 + `|` + regex_host + `):([1-9][0-9]{0,4})$` 20 | var regex_streamtarget = regexp.MustCompile(regex_streamtargetstr) 21 | 22 | func (c *OnionConnection) handleRelayBackward(circ *RelayCircuit, cell Cell) ActionableError { 23 | origData := cell.Data() 24 | data := GetCellBuf(false) 25 | copy(data, origData) 26 | data = data[0:len(origData)] 27 | 28 | circ.previousHop <- &RelayData{ 29 | id: circ.theirID, 30 | data: data, 31 | forRelay: false, 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func (c *OnionConnection) handleRelayForward(circ *Circuit, cell Cell) ActionableError { 38 | cstate := circ.forward 39 | 40 | dec, err := cstate.cipher.Crypt(cell.Data(), GetCellBuf(false)) 41 | if err != nil { 42 | return CloseCircuit(err, DESTROY_REASON_INTERNAL) 43 | } 44 | 45 | rcell := RelayCell{dec} 46 | 47 | should_be_forwarded := false 48 | 49 | if !rcell.Recognized() { 50 | should_be_forwarded = true 51 | } 52 | 53 | if !should_be_forwarded { 54 | tmpCell := GetCellBuf(false) 55 | defer ReturnCellBuf(tmpCell) 56 | copy(tmpCell, rcell.bytes) 57 | tmpCell = tmpCell[:len(rcell.bytes)] 58 | tmpCell[5] = 0 59 | tmpCell[6] = 0 60 | tmpCell[7] = 0 61 | tmpCell[8] = 0 62 | 63 | old_dig := cstate.digest.Clone() // XXX rofl 64 | 65 | cstate.digest.Write(tmpCell) 66 | their_digest := rcell.Digest() 67 | our_digest := cstate.digest.Sum(nil) 68 | if their_digest[0] != our_digest[0] || their_digest[1] != our_digest[1] || their_digest[2] != our_digest[2] || their_digest[3] != our_digest[3] { 69 | cstate.digest = old_dig // XXX Find a better way to do this :-) 70 | should_be_forwarded = true 71 | } 72 | } 73 | 74 | if should_be_forwarded { 75 | if circ.nextHop == nil { 76 | ReturnCellBuf(dec) 77 | return CloseCircuit(errors.New("cannot forward that!"), DESTROY_REASON_PROTOCOL) 78 | } 79 | 80 | circ.nextHop <- &RelayData{ 81 | id: circ.nextHopID, 82 | data: dec, 83 | forRelay: true, 84 | rType: cell.Command(), 85 | } 86 | return nil 87 | } 88 | 89 | defer ReturnCellBuf(dec) 90 | 91 | if rcell.Length()+11 > len(dec) { 92 | return CloseCircuit(errors.New("Malformed relay cell"), DESTROY_REASON_PROTOCOL) 93 | } 94 | 95 | return c.handleRelayDecrypted(circ, cell, &rcell) 96 | } 97 | 98 | func (c *OnionConnection) handleRelayDecrypted(circ *Circuit, cell Cell, rcell *RelayCell) ActionableError { 99 | var err ActionableError 100 | 101 | // At this point we established that the rcell is intended for us 102 | switch rcell.Command() { 103 | case RELAY_DATA: 104 | err = c.handleRelayData(circ, rcell) 105 | case RELAY_END: 106 | err = c.handleRelayEnd(circ, rcell) 107 | case RELAY_SENDME: 108 | err = c.handleRelaySendme(circ, rcell) 109 | case RELAY_BEGIN_DIR, RELAY_BEGIN: 110 | err = c.handleRelayBegin(circ, rcell) 111 | case RELAY_EXTEND: 112 | if cell.Command() == CMD_RELAY { 113 | err = CloseCircuit(errors.New("RELAY may not have an EXTEND command"), DESTROY_REASON_PROTOCOL) 114 | break 115 | } 116 | err = c.handleRelayExtend(circ, rcell) 117 | case RELAY_EXTEND2: 118 | if cell.Command() == CMD_RELAY { 119 | err = CloseCircuit(errors.New("RELAY may not have an EXTEND command"), DESTROY_REASON_PROTOCOL) 120 | break 121 | } 122 | err = c.handleRelayExtend2(circ, rcell) 123 | case RELAY_RESOLVE: 124 | err = c.handleRelayResolve(circ, rcell) 125 | case RELAY_DROP: 126 | // Ignore 127 | default: 128 | err = CloseCircuit(fmt.Errorf("Don't know a command %s: %v", rcell.Command(), rcell), DESTROY_REASON_PROTOCOL) 129 | } 130 | 131 | if err != nil { 132 | switch err.Handle() { 133 | case ERROR_CLOSE_STREAM, ERROR_REFUSE_STREAM: 134 | streamID := rcell.StreamID() 135 | if streamID == 0 { 136 | err = CloseConnection(fmt.Errorf("Got a ERROR_REFUSE_STREAM for StreamID=0. Original error: %s", err)) 137 | break 138 | } 139 | 140 | if err.Handle() == ERROR_REFUSE_STREAM { 141 | Log(LOG_CIRC, "Refusing stream: %s", err) 142 | } else { 143 | Log(LOG_CIRC, "Closing stream: %s", err) 144 | 145 | stream, ok := circ.streams[streamID] 146 | if !ok { 147 | err = CloseCircuit(fmt.Errorf("Got ERROR_CLOSE_STREAM for unknown Stream. Original: %s", err), DESTROY_REASON_PROTOCOL) 148 | break 149 | } 150 | 151 | delete(circ.streams, streamID) 152 | stream.Destroy() 153 | } 154 | err = c.sendRelayCell(circ, streamID, BackwardDirection, RELAY_END, []byte{byte(err.StreamEndReason())}) 155 | } 156 | } 157 | 158 | return err 159 | } 160 | 161 | func (c *OnionConnection) handleRelayBegin(circ *Circuit, cell *RelayCell) ActionableError { 162 | streamID := cell.StreamID() 163 | isDir := cell.Command() == RELAY_BEGIN_DIR 164 | 165 | _, alreadyExists := circ.streams[streamID] 166 | if alreadyExists { 167 | return CloseCircuit(errors.New("We already have a stream with that ID"), DESTROY_REASON_PROTOCOL) 168 | } 169 | 170 | if isDir && c.parentOR.config.DirPort == 0 { 171 | return RefuseStream(errors.New("We're no directory."), STREAM_REASON_NOTDIRECTORY) 172 | } 173 | 174 | var addr string 175 | if isDir { 176 | addr = fmt.Sprintf("127.0.0.1:%d", c.parentOR.config.DirPort) 177 | } else { 178 | for i := 0; i < cell.Length(); i++ { 179 | if cell.Data()[i] == 0 { 180 | addr = string(cell.Data()[0:i]) 181 | break 182 | } 183 | } 184 | // XXX handle flags 185 | } 186 | 187 | if addr == "" { 188 | return RefuseStream(errors.New("No address found"), STREAM_REASON_TORPROTOCOL) 189 | } 190 | 191 | matches := regex_streamtarget.FindStringSubmatch(addr) 192 | if matches == nil { 193 | return RefuseStream(fmt.Errorf("Refusing to connect to %q as it does not look valid", addr), STREAM_REASON_TORPROTOCOL) 194 | } 195 | 196 | port, _ := strconv.ParseUint(matches[2], 10, 64) 197 | if port > 65535 { 198 | return CloseStream(errors.New("invalid port in RELAY_BEGIN"), STREAM_REASON_TORPROTOCOL) 199 | } 200 | 201 | Log(LOG_CIRC, "Opening stream to %s", addr) 202 | 203 | stream, err := NewStream(streamID) 204 | if err != nil { 205 | return RefuseStream(err, STREAM_REASON_INTERNAL) 206 | } 207 | 208 | circ.streams[streamID] = stream 209 | go stream.Run(circ.id, circ.backwardWindow, c.circuitReadQueue, matches[1], uint16(port), isDir, c.parentOR.config.ExitPolicy) 210 | 211 | return nil 212 | } 213 | 214 | func (c *OnionConnection) sendRelayCell(circ *Circuit, stream StreamID, direction DataDirection, command RelayCommand, data []byte) ActionableError { 215 | if len(data) > MAX_RELAY_LEN { 216 | panic("Somehow we're trying to send a massive cell") 217 | } 218 | 219 | var crypto DirectionalCircuitState // XXX When would forward be relevant here? 220 | if direction == ForwardDirection { 221 | crypto = circ.forward 222 | } else { 223 | crypto = circ.backward 224 | } 225 | 226 | cell := NewCell(c.negotiatedVersion, circ.id, CMD_RELAY, nil) 227 | buf := cell.Data() 228 | 229 | // The rest will be crypto'd 230 | buf[0] = byte(command) 231 | buf[1] = 0 // recognized 232 | buf[2] = 0 233 | BigEndian.PutUint16(buf[3:5], uint16(stream)) 234 | 235 | // placeholder for digest 236 | 237 | if data != nil && len(data) != 0 { 238 | BigEndian.PutUint16(buf[9:11], uint16(len(data))) 239 | copy(buf[11:], data) 240 | } 241 | 242 | crypto.digest.Write(buf) 243 | digest := crypto.digest.Sum(nil) 244 | buf[5] = digest[0] 245 | buf[6] = digest[1] 246 | buf[7] = digest[2] 247 | buf[8] = digest[3] 248 | 249 | // Now AES it 250 | crypto.cipher.Crypt(buf, buf) 251 | 252 | c.writeQueue <- cell.Bytes() // XXX this could deadlock 253 | 254 | return nil 255 | } 256 | 257 | func (c *OnionConnection) handleRelayEnd(circ *Circuit, cell *RelayCell) ActionableError { 258 | streamID := cell.StreamID() 259 | stream, ok := circ.streams[streamID] 260 | if !ok { 261 | Log(LOG_INFO, "Ignoring RELAY_END for non-existent stream") 262 | return nil 263 | } 264 | 265 | delete(circ.streams, streamID) 266 | stream.Destroy() 267 | 268 | return nil 269 | } 270 | 271 | func (c *OnionConnection) handleRelaySendme(circ *Circuit, cell *RelayCell) ActionableError { 272 | if cell.StreamID() == 0 { 273 | circ.backwardWindow.Refill(100) 274 | } else { 275 | stream, ok := circ.streams[cell.StreamID()] 276 | if !ok { 277 | Log(LOG_CIRC, "Ignoring SENDME for unknown stream") 278 | return nil // Sure, that's ok 279 | } 280 | 281 | stream.backwardWindow.Refill(50) 282 | } 283 | return nil 284 | } 285 | 286 | func (c *OnionConnection) handleRelayData(circ *Circuit, cell *RelayCell) ActionableError { 287 | circ.forwardWindow-- 288 | if circ.forwardWindow <= 900 { 289 | if err := c.sendRelayCell(circ, 0, BackwardDirection, RELAY_SENDME, nil); err != nil { 290 | return err 291 | } 292 | circ.forwardWindow += 100 293 | } 294 | 295 | streamID := cell.StreamID() 296 | stream, ok := circ.streams[streamID] 297 | if !ok { 298 | Log(LOG_INFO, "ignoring data for stream we don't know") 299 | return nil 300 | } 301 | 302 | ok = stream.forwardWindow.TryTake() 303 | if !ok { 304 | return CloseStream(errors.New("Refusing to overflow window"), STREAM_REASON_TORPROTOCOL) 305 | } 306 | 307 | data := cell.Data() 308 | // gotta copy that 309 | dataCopy := GetCellBuf(false) 310 | copy(dataCopy, data) 311 | 312 | stream.writeChan <- dataCopy[0:len(data)] 313 | 314 | return nil 315 | } 316 | 317 | func (c *OnionConnection) handleRelayResolve(circ *Circuit, cell *RelayCell) ActionableError { 318 | stream := cell.StreamID() 319 | if stream == 0 { 320 | return CloseCircuit(errors.New("No Circuit ID for RELAY_RESOLVE"), DESTROY_REASON_PROTOCOL) 321 | } 322 | 323 | data := cell.Data() 324 | var firstZero int 325 | for i, ch := range data { 326 | if ch == 0 { 327 | firstZero = i 328 | break 329 | } 330 | } 331 | if firstZero == 0 { 332 | return CloseCircuit(errors.New("No DNS name given in RELAY_RESOLVE"), DESTROY_REASON_PROTOCOL) 333 | } 334 | 335 | dnsName := string(data[:firstZero]) 336 | ResolveDNSAsync(dnsName, circ.id, stream, c.circuitReadQueue) 337 | 338 | return nil 339 | } 340 | -------------------------------------------------------------------------------- /relaycell.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type StreamID uint16 8 | 9 | type RelayCell struct { 10 | bytes []byte 11 | } 12 | 13 | func (c *RelayCell) Command() RelayCommand { 14 | return RelayCommand(c.bytes[0]) 15 | } 16 | 17 | func (c *RelayCell) Recognized() bool { 18 | if c.bytes[1] != 0 || c.bytes[2] != 0 { 19 | return false 20 | } else { 21 | return true 22 | } 23 | } 24 | 25 | func (c *RelayCell) StreamID() StreamID { 26 | return StreamID(BigEndian.Uint16(c.bytes[3:5])) 27 | } 28 | 29 | func (c *RelayCell) Digest() []byte { 30 | return c.bytes[5:9] 31 | } 32 | 33 | func (c *RelayCell) Length() int { 34 | return int(BigEndian.Uint16(c.bytes[9:11])) 35 | } 36 | 37 | func (c *RelayCell) Data() []byte { 38 | return c.bytes[11 : 11+c.Length()] 39 | } 40 | -------------------------------------------------------------------------------- /relaydata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type RelayData struct { 8 | id CircuitID 9 | data []byte 10 | forRelay bool 11 | rType Command 12 | } 13 | 14 | func (c *RelayData) CircID() CircuitID { 15 | return c.id 16 | } 17 | 18 | func (c *RelayData) ForRelay() bool { 19 | return c.forRelay 20 | } 21 | 22 | func (rdata *RelayData) Handle(c *OnionConnection, circ *Circuit) ActionableError { 23 | data := rdata.data 24 | 25 | cell := NewCell(c.negotiatedVersion, circ.id, CMD_RELAY, nil) 26 | 27 | cstate := circ.backward.cipher 28 | _, err := cstate.Crypt(data, cell.Data()) 29 | if err != nil { 30 | cell.ReleaseBuffers() 31 | return CloseCircuit(err, DESTROY_REASON_INTERNAL) 32 | } 33 | 34 | c.writeQueue <- cell.Bytes() 35 | return nil 36 | } 37 | 38 | func (data *RelayData) HandleRelay(c *OnionConnection, circ *RelayCircuit) ActionableError { 39 | c.writeQueue <- NewCell(c.negotiatedVersion, circ.id, data.rType, data.data).Bytes() 40 | 41 | return nil 42 | } 43 | 44 | func (data *RelayData) ReleaseBuffers() { 45 | ReturnCellBuf(data.data) 46 | } 47 | -------------------------------------------------------------------------------- /sha1/README: -------------------------------------------------------------------------------- 1 | This SHA1 module exists only so that we can add a .Clone() method to the object. 2 | -------------------------------------------------------------------------------- /sha1/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sha1_test 6 | 7 | import ( 8 | "crypto/sha1" 9 | "fmt" 10 | "io" 11 | ) 12 | 13 | func ExampleNew() { 14 | h := sha1.New() 15 | io.WriteString(h, "His money is twice tainted:") 16 | io.WriteString(h, " 'taint yours and 'taint mine.") 17 | fmt.Printf("% x", h.Sum(nil)) 18 | // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd 19 | } 20 | 21 | func ExampleSum() { 22 | data := []byte("This page intentionally left blank.") 23 | fmt.Printf("% x", sha1.Sum(data)) 24 | // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96 25 | } 26 | -------------------------------------------------------------------------------- /sha1/sha1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174. 6 | package sha1 7 | 8 | // The size of a SHA1 checksum in bytes. 9 | const Size = 20 10 | 11 | // The blocksize of SHA1 in bytes. 12 | const BlockSize = 64 13 | 14 | const ( 15 | chunk = 64 16 | init0 = 0x67452301 17 | init1 = 0xEFCDAB89 18 | init2 = 0x98BADCFE 19 | init3 = 0x10325476 20 | init4 = 0xC3D2E1F0 21 | ) 22 | 23 | // Digest represents the partial evaluation of a checksum. 24 | type Digest struct { 25 | h [5]uint32 26 | x [chunk]byte 27 | nx int 28 | len uint64 29 | } 30 | 31 | func (d *Digest) Reset() { 32 | d.h[0] = init0 33 | d.h[1] = init1 34 | d.h[2] = init2 35 | d.h[3] = init3 36 | d.h[4] = init4 37 | d.nx = 0 38 | d.len = 0 39 | } 40 | 41 | // New returns a new hash.Hash computing the SHA1 checksum. 42 | func New() *Digest { 43 | d := new(Digest) 44 | d.Reset() 45 | return d 46 | } 47 | 48 | func (d *Digest) Clone() *Digest { 49 | n := new(Digest) 50 | *n = *d 51 | return n 52 | } 53 | 54 | func (d *Digest) Size() int { return Size } 55 | 56 | func (d *Digest) BlockSize() int { return BlockSize } 57 | 58 | func (d *Digest) Write(p []byte) (nn int, err error) { 59 | nn = len(p) 60 | d.len += uint64(nn) 61 | if d.nx > 0 { 62 | n := copy(d.x[d.nx:], p) 63 | d.nx += n 64 | if d.nx == chunk { 65 | block(d, d.x[:]) 66 | d.nx = 0 67 | } 68 | p = p[n:] 69 | } 70 | if len(p) >= chunk { 71 | n := len(p) &^ (chunk - 1) 72 | block(d, p[:n]) 73 | p = p[n:] 74 | } 75 | if len(p) > 0 { 76 | d.nx = copy(d.x[:], p) 77 | } 78 | return 79 | } 80 | 81 | func (d0 *Digest) Sum(in []byte) []byte { 82 | // Make a copy of d0 so that caller can keep writing and summing. 83 | d := *d0 84 | hash := d.checkSum() 85 | return append(in, hash[:]...) 86 | } 87 | 88 | func (d *Digest) checkSum() [Size]byte { 89 | len := d.len 90 | // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. 91 | var tmp [64]byte 92 | tmp[0] = 0x80 93 | if len%64 < 56 { 94 | d.Write(tmp[0 : 56-len%64]) 95 | } else { 96 | d.Write(tmp[0 : 64+56-len%64]) 97 | } 98 | 99 | // Length in bits. 100 | len <<= 3 101 | for i := uint(0); i < 8; i++ { 102 | tmp[i] = byte(len >> (56 - 8*i)) 103 | } 104 | d.Write(tmp[0:8]) 105 | 106 | if d.nx != 0 { 107 | panic("d.nx != 0") 108 | } 109 | 110 | var digest [Size]byte 111 | for i, s := range d.h { 112 | digest[i*4] = byte(s >> 24) 113 | digest[i*4+1] = byte(s >> 16) 114 | digest[i*4+2] = byte(s >> 8) 115 | digest[i*4+3] = byte(s) 116 | } 117 | 118 | return digest 119 | } 120 | 121 | // Sum returns the SHA1 checksum of the data. 122 | func Sum(data []byte) [Size]byte { 123 | var d Digest 124 | d.Reset() 125 | d.Write(data) 126 | return d.checkSum() 127 | } 128 | -------------------------------------------------------------------------------- /sha1/sha1_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // SHA1 hash algorithm. See RFC 3174. 6 | 7 | package sha1 8 | 9 | import ( 10 | "crypto/rand" 11 | "fmt" 12 | "io" 13 | "testing" 14 | ) 15 | 16 | type sha1Test struct { 17 | out string 18 | in string 19 | } 20 | 21 | var golden = []sha1Test{ 22 | {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, 23 | {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, 24 | {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"}, 25 | {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, 26 | {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"}, 27 | {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"}, 28 | {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"}, 29 | {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"}, 30 | {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"}, 31 | {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"}, 32 | {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"}, 33 | {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."}, 34 | {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."}, 35 | {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."}, 36 | {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, 37 | {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"}, 38 | {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."}, 39 | {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."}, 40 | {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."}, 41 | {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, 42 | {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, 43 | {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"}, 44 | {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"}, 45 | {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, 46 | {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."}, 47 | {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."}, 48 | {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."}, 49 | {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"}, 50 | {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, 51 | {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, 52 | {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"}, 53 | } 54 | 55 | func TestGolden(t *testing.T) { 56 | for i := 0; i < len(golden); i++ { 57 | g := golden[i] 58 | s := fmt.Sprintf("%x", Sum([]byte(g.in))) 59 | if s != g.out { 60 | t.Fatalf("Sum function: sha1(%s) = %s want %s", g.in, s, g.out) 61 | } 62 | c := New() 63 | for j := 0; j < 3; j++ { 64 | if j < 2 { 65 | io.WriteString(c, g.in) 66 | } else { 67 | io.WriteString(c, g.in[0:len(g.in)/2]) 68 | c.Sum(nil) 69 | io.WriteString(c, g.in[len(g.in)/2:]) 70 | } 71 | s := fmt.Sprintf("%x", c.Sum(nil)) 72 | if s != g.out { 73 | t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out) 74 | } 75 | c.Reset() 76 | } 77 | } 78 | } 79 | 80 | func TestSize(t *testing.T) { 81 | c := New() 82 | if got := c.Size(); got != Size { 83 | t.Errorf("Size = %d; want %d", got, Size) 84 | } 85 | } 86 | 87 | func TestBlockSize(t *testing.T) { 88 | c := New() 89 | if got := c.BlockSize(); got != BlockSize { 90 | t.Errorf("BlockSize = %d; want %d", got, BlockSize) 91 | } 92 | } 93 | 94 | // Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match. 95 | func TestBlockGeneric(t *testing.T) { 96 | gen, asm := New(), New() 97 | buf := make([]byte, BlockSize*20) // arbitrary factor 98 | rand.Read(buf) 99 | blockGeneric(gen, buf) 100 | block(asm, buf) 101 | if *gen != *asm { 102 | t.Error("block and blockGeneric resulted in different states") 103 | } 104 | } 105 | 106 | var bench = New() 107 | var buf = make([]byte, 8192) 108 | 109 | func benchmarkSize(b *testing.B, size int) { 110 | b.SetBytes(int64(size)) 111 | sum := make([]byte, bench.Size()) 112 | for i := 0; i < b.N; i++ { 113 | bench.Reset() 114 | bench.Write(buf[:size]) 115 | bench.Sum(sum[:0]) 116 | } 117 | } 118 | 119 | func BenchmarkHash8Bytes(b *testing.B) { 120 | benchmarkSize(b, 8) 121 | } 122 | 123 | func BenchmarkHash1K(b *testing.B) { 124 | benchmarkSize(b, 1024) 125 | } 126 | 127 | func BenchmarkHash8K(b *testing.B) { 128 | benchmarkSize(b, 8192) 129 | } 130 | -------------------------------------------------------------------------------- /sha1/sha1block.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sha1 6 | 7 | const ( 8 | _K0 = 0x5A827999 9 | _K1 = 0x6ED9EBA1 10 | _K2 = 0x8F1BBCDC 11 | _K3 = 0xCA62C1D6 12 | ) 13 | 14 | // blockGeneric is a portable, pure Go version of the SHA1 block step. 15 | // It's used by sha1block_generic.go and tests. 16 | func blockGeneric(dig *Digest, p []byte) { 17 | var w [16]uint32 18 | 19 | h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] 20 | for len(p) >= chunk { 21 | // Can interlace the computation of w with the 22 | // rounds below if needed for speed. 23 | for i := 0; i < 16; i++ { 24 | j := i * 4 25 | w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3]) 26 | } 27 | 28 | a, b, c, d, e := h0, h1, h2, h3, h4 29 | 30 | // Each of the four 20-iteration rounds 31 | // differs only in the computation of f and 32 | // the choice of K (_K0, _K1, etc). 33 | i := 0 34 | for ; i < 16; i++ { 35 | f := b&c | (^b)&d 36 | a5 := a<<5 | a>>(32-5) 37 | b30 := b<<30 | b>>(32-30) 38 | t := a5 + f + e + w[i&0xf] + _K0 39 | a, b, c, d, e = t, a, b30, c, d 40 | } 41 | for ; i < 20; i++ { 42 | tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] 43 | w[i&0xf] = tmp<<1 | tmp>>(32-1) 44 | 45 | f := b&c | (^b)&d 46 | a5 := a<<5 | a>>(32-5) 47 | b30 := b<<30 | b>>(32-30) 48 | t := a5 + f + e + w[i&0xf] + _K0 49 | a, b, c, d, e = t, a, b30, c, d 50 | } 51 | for ; i < 40; i++ { 52 | tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] 53 | w[i&0xf] = tmp<<1 | tmp>>(32-1) 54 | f := b ^ c ^ d 55 | a5 := a<<5 | a>>(32-5) 56 | b30 := b<<30 | b>>(32-30) 57 | t := a5 + f + e + w[i&0xf] + _K1 58 | a, b, c, d, e = t, a, b30, c, d 59 | } 60 | for ; i < 60; i++ { 61 | tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] 62 | w[i&0xf] = tmp<<1 | tmp>>(32-1) 63 | f := ((b | c) & d) | (b & c) 64 | 65 | a5 := a<<5 | a>>(32-5) 66 | b30 := b<<30 | b>>(32-30) 67 | t := a5 + f + e + w[i&0xf] + _K2 68 | a, b, c, d, e = t, a, b30, c, d 69 | } 70 | for ; i < 80; i++ { 71 | tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] 72 | w[i&0xf] = tmp<<1 | tmp>>(32-1) 73 | f := b ^ c ^ d 74 | a5 := a<<5 | a>>(32-5) 75 | b30 := b<<30 | b>>(32-30) 76 | t := a5 + f + e + w[i&0xf] + _K3 77 | a, b, c, d, e = t, a, b30, c, d 78 | } 79 | 80 | h0 += a 81 | h1 += b 82 | h2 += c 83 | h3 += d 84 | h4 += e 85 | 86 | p = p[chunk:] 87 | } 88 | 89 | dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4 90 | } 91 | -------------------------------------------------------------------------------- /sha1/sha1block_386.s: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "textflag.h" 6 | 7 | // SHA1 block routine. See sha1block.go for Go equivalent. 8 | // 9 | // There are 80 rounds of 4 types: 10 | // - rounds 0-15 are type 1 and load data (ROUND1 macro). 11 | // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). 12 | // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). 13 | // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). 14 | // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). 15 | // 16 | // Each round loads or shuffles the data, then computes a per-round 17 | // function of b, c, d, and then mixes the result into and rotates the 18 | // five registers a, b, c, d, e holding the intermediate results. 19 | // 20 | // The register rotation is implemented by rotating the arguments to 21 | // the round macros instead of by explicit move instructions. 22 | 23 | // Like sha1block_amd64.s, but we keep the data and limit pointers on the stack. 24 | // To free up the word pointer (R10 on amd64, DI here), we add it to e during 25 | // LOAD/SHUFFLE instead of during MIX. 26 | // 27 | // The stack holds the intermediate word array - 16 uint32s - at 0(SP) up to 64(SP). 28 | // The saved a, b, c, d, e (R11 through R15 on amd64) are at 64(SP) up to 84(SP). 29 | // The saved limit pointer (DI on amd64) is at 84(SP). 30 | // The saved data pointer (SI on amd64) is at 88(SP). 31 | 32 | #define LOAD(index, e) \ 33 | MOVL 88(SP), SI; \ 34 | MOVL (index*4)(SI), DI; \ 35 | BSWAPL DI; \ 36 | MOVL DI, (index*4)(SP); \ 37 | ADDL DI, e 38 | 39 | #define SHUFFLE(index, e) \ 40 | MOVL (((index)&0xf)*4)(SP), DI; \ 41 | XORL (((index-3)&0xf)*4)(SP), DI; \ 42 | XORL (((index-8)&0xf)*4)(SP), DI; \ 43 | XORL (((index-14)&0xf)*4)(SP), DI; \ 44 | ROLL $1, DI; \ 45 | MOVL DI, (((index)&0xf)*4)(SP); \ 46 | ADDL DI, e 47 | 48 | #define FUNC1(a, b, c, d, e) \ 49 | MOVL d, DI; \ 50 | XORL c, DI; \ 51 | ANDL b, DI; \ 52 | XORL d, DI 53 | 54 | #define FUNC2(a, b, c, d, e) \ 55 | MOVL b, DI; \ 56 | XORL c, DI; \ 57 | XORL d, DI 58 | 59 | #define FUNC3(a, b, c, d, e) \ 60 | MOVL b, SI; \ 61 | ORL c, SI; \ 62 | ANDL d, SI; \ 63 | MOVL b, DI; \ 64 | ANDL c, DI; \ 65 | ORL SI, DI 66 | 67 | #define FUNC4 FUNC2 68 | 69 | #define MIX(a, b, c, d, e, const) \ 70 | ROLL $30, b; \ 71 | ADDL DI, e; \ 72 | MOVL a, SI; \ 73 | ROLL $5, SI; \ 74 | LEAL const(e)(SI*1), e 75 | 76 | #define ROUND1(a, b, c, d, e, index) \ 77 | LOAD(index, e); \ 78 | FUNC1(a, b, c, d, e); \ 79 | MIX(a, b, c, d, e, 0x5A827999) 80 | 81 | #define ROUND1x(a, b, c, d, e, index) \ 82 | SHUFFLE(index, e); \ 83 | FUNC1(a, b, c, d, e); \ 84 | MIX(a, b, c, d, e, 0x5A827999) 85 | 86 | #define ROUND2(a, b, c, d, e, index) \ 87 | SHUFFLE(index, e); \ 88 | FUNC2(a, b, c, d, e); \ 89 | MIX(a, b, c, d, e, 0x6ED9EBA1) 90 | 91 | #define ROUND3(a, b, c, d, e, index) \ 92 | SHUFFLE(index, e); \ 93 | FUNC3(a, b, c, d, e); \ 94 | MIX(a, b, c, d, e, 0x8F1BBCDC) 95 | 96 | #define ROUND4(a, b, c, d, e, index) \ 97 | SHUFFLE(index, e); \ 98 | FUNC4(a, b, c, d, e); \ 99 | MIX(a, b, c, d, e, 0xCA62C1D6) 100 | 101 | // func block(dig *Digest, p []byte) 102 | TEXT ·block(SB),NOSPLIT,$92-16 103 | MOVL dig+0(FP), BP 104 | MOVL p+4(FP), SI 105 | MOVL p_len+8(FP), DX 106 | SHRL $6, DX 107 | SHLL $6, DX 108 | 109 | LEAL (SI)(DX*1), DI 110 | MOVL (0*4)(BP), AX 111 | MOVL (1*4)(BP), BX 112 | MOVL (2*4)(BP), CX 113 | MOVL (3*4)(BP), DX 114 | MOVL (4*4)(BP), BP 115 | 116 | CMPL SI, DI 117 | JEQ end 118 | 119 | MOVL DI, 84(SP) 120 | 121 | loop: 122 | MOVL SI, 88(SP) 123 | 124 | MOVL AX, 64(SP) 125 | MOVL BX, 68(SP) 126 | MOVL CX, 72(SP) 127 | MOVL DX, 76(SP) 128 | MOVL BP, 80(SP) 129 | 130 | ROUND1(AX, BX, CX, DX, BP, 0) 131 | ROUND1(BP, AX, BX, CX, DX, 1) 132 | ROUND1(DX, BP, AX, BX, CX, 2) 133 | ROUND1(CX, DX, BP, AX, BX, 3) 134 | ROUND1(BX, CX, DX, BP, AX, 4) 135 | ROUND1(AX, BX, CX, DX, BP, 5) 136 | ROUND1(BP, AX, BX, CX, DX, 6) 137 | ROUND1(DX, BP, AX, BX, CX, 7) 138 | ROUND1(CX, DX, BP, AX, BX, 8) 139 | ROUND1(BX, CX, DX, BP, AX, 9) 140 | ROUND1(AX, BX, CX, DX, BP, 10) 141 | ROUND1(BP, AX, BX, CX, DX, 11) 142 | ROUND1(DX, BP, AX, BX, CX, 12) 143 | ROUND1(CX, DX, BP, AX, BX, 13) 144 | ROUND1(BX, CX, DX, BP, AX, 14) 145 | ROUND1(AX, BX, CX, DX, BP, 15) 146 | 147 | ROUND1x(BP, AX, BX, CX, DX, 16) 148 | ROUND1x(DX, BP, AX, BX, CX, 17) 149 | ROUND1x(CX, DX, BP, AX, BX, 18) 150 | ROUND1x(BX, CX, DX, BP, AX, 19) 151 | 152 | ROUND2(AX, BX, CX, DX, BP, 20) 153 | ROUND2(BP, AX, BX, CX, DX, 21) 154 | ROUND2(DX, BP, AX, BX, CX, 22) 155 | ROUND2(CX, DX, BP, AX, BX, 23) 156 | ROUND2(BX, CX, DX, BP, AX, 24) 157 | ROUND2(AX, BX, CX, DX, BP, 25) 158 | ROUND2(BP, AX, BX, CX, DX, 26) 159 | ROUND2(DX, BP, AX, BX, CX, 27) 160 | ROUND2(CX, DX, BP, AX, BX, 28) 161 | ROUND2(BX, CX, DX, BP, AX, 29) 162 | ROUND2(AX, BX, CX, DX, BP, 30) 163 | ROUND2(BP, AX, BX, CX, DX, 31) 164 | ROUND2(DX, BP, AX, BX, CX, 32) 165 | ROUND2(CX, DX, BP, AX, BX, 33) 166 | ROUND2(BX, CX, DX, BP, AX, 34) 167 | ROUND2(AX, BX, CX, DX, BP, 35) 168 | ROUND2(BP, AX, BX, CX, DX, 36) 169 | ROUND2(DX, BP, AX, BX, CX, 37) 170 | ROUND2(CX, DX, BP, AX, BX, 38) 171 | ROUND2(BX, CX, DX, BP, AX, 39) 172 | 173 | ROUND3(AX, BX, CX, DX, BP, 40) 174 | ROUND3(BP, AX, BX, CX, DX, 41) 175 | ROUND3(DX, BP, AX, BX, CX, 42) 176 | ROUND3(CX, DX, BP, AX, BX, 43) 177 | ROUND3(BX, CX, DX, BP, AX, 44) 178 | ROUND3(AX, BX, CX, DX, BP, 45) 179 | ROUND3(BP, AX, BX, CX, DX, 46) 180 | ROUND3(DX, BP, AX, BX, CX, 47) 181 | ROUND3(CX, DX, BP, AX, BX, 48) 182 | ROUND3(BX, CX, DX, BP, AX, 49) 183 | ROUND3(AX, BX, CX, DX, BP, 50) 184 | ROUND3(BP, AX, BX, CX, DX, 51) 185 | ROUND3(DX, BP, AX, BX, CX, 52) 186 | ROUND3(CX, DX, BP, AX, BX, 53) 187 | ROUND3(BX, CX, DX, BP, AX, 54) 188 | ROUND3(AX, BX, CX, DX, BP, 55) 189 | ROUND3(BP, AX, BX, CX, DX, 56) 190 | ROUND3(DX, BP, AX, BX, CX, 57) 191 | ROUND3(CX, DX, BP, AX, BX, 58) 192 | ROUND3(BX, CX, DX, BP, AX, 59) 193 | 194 | ROUND4(AX, BX, CX, DX, BP, 60) 195 | ROUND4(BP, AX, BX, CX, DX, 61) 196 | ROUND4(DX, BP, AX, BX, CX, 62) 197 | ROUND4(CX, DX, BP, AX, BX, 63) 198 | ROUND4(BX, CX, DX, BP, AX, 64) 199 | ROUND4(AX, BX, CX, DX, BP, 65) 200 | ROUND4(BP, AX, BX, CX, DX, 66) 201 | ROUND4(DX, BP, AX, BX, CX, 67) 202 | ROUND4(CX, DX, BP, AX, BX, 68) 203 | ROUND4(BX, CX, DX, BP, AX, 69) 204 | ROUND4(AX, BX, CX, DX, BP, 70) 205 | ROUND4(BP, AX, BX, CX, DX, 71) 206 | ROUND4(DX, BP, AX, BX, CX, 72) 207 | ROUND4(CX, DX, BP, AX, BX, 73) 208 | ROUND4(BX, CX, DX, BP, AX, 74) 209 | ROUND4(AX, BX, CX, DX, BP, 75) 210 | ROUND4(BP, AX, BX, CX, DX, 76) 211 | ROUND4(DX, BP, AX, BX, CX, 77) 212 | ROUND4(CX, DX, BP, AX, BX, 78) 213 | ROUND4(BX, CX, DX, BP, AX, 79) 214 | 215 | ADDL 64(SP), AX 216 | ADDL 68(SP), BX 217 | ADDL 72(SP), CX 218 | ADDL 76(SP), DX 219 | ADDL 80(SP), BP 220 | 221 | MOVL 88(SP), SI 222 | ADDL $64, SI 223 | CMPL SI, 84(SP) 224 | JB loop 225 | 226 | end: 227 | MOVL dig+0(FP), DI 228 | MOVL AX, (0*4)(DI) 229 | MOVL BX, (1*4)(DI) 230 | MOVL CX, (2*4)(DI) 231 | MOVL DX, (3*4)(DI) 232 | MOVL BP, (4*4)(DI) 233 | RET 234 | -------------------------------------------------------------------------------- /sha1/sha1block_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "textflag.h" 6 | 7 | // SHA1 block routine. See sha1block.go for Go equivalent. 8 | // 9 | // There are 80 rounds of 4 types: 10 | // - rounds 0-15 are type 1 and load data (ROUND1 macro). 11 | // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). 12 | // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). 13 | // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). 14 | // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). 15 | // 16 | // Each round loads or shuffles the data, then computes a per-round 17 | // function of b, c, d, and then mixes the result into and rotates the 18 | // five registers a, b, c, d, e holding the intermediate results. 19 | // 20 | // The register rotation is implemented by rotating the arguments to 21 | // the round macros instead of by explicit move instructions. 22 | 23 | #define LOAD(index) \ 24 | MOVL (index*4)(SI), R10; \ 25 | BSWAPL R10; \ 26 | MOVL R10, (index*4)(SP) 27 | 28 | #define SHUFFLE(index) \ 29 | MOVL (((index)&0xf)*4)(SP), R10; \ 30 | XORL (((index-3)&0xf)*4)(SP), R10; \ 31 | XORL (((index-8)&0xf)*4)(SP), R10; \ 32 | XORL (((index-14)&0xf)*4)(SP), R10; \ 33 | ROLL $1, R10; \ 34 | MOVL R10, (((index)&0xf)*4)(SP) 35 | 36 | #define FUNC1(a, b, c, d, e) \ 37 | MOVL d, R9; \ 38 | XORL c, R9; \ 39 | ANDL b, R9; \ 40 | XORL d, R9 41 | 42 | #define FUNC2(a, b, c, d, e) \ 43 | MOVL b, R9; \ 44 | XORL c, R9; \ 45 | XORL d, R9 46 | 47 | #define FUNC3(a, b, c, d, e) \ 48 | MOVL b, R8; \ 49 | ORL c, R8; \ 50 | ANDL d, R8; \ 51 | MOVL b, R9; \ 52 | ANDL c, R9; \ 53 | ORL R8, R9 54 | 55 | #define FUNC4 FUNC2 56 | 57 | #define MIX(a, b, c, d, e, const) \ 58 | ROLL $30, b; \ 59 | ADDL R9, e; \ 60 | MOVL a, R8; \ 61 | ROLL $5, R8; \ 62 | LEAL const(e)(R10*1), e; \ 63 | ADDL R8, e 64 | 65 | #define ROUND1(a, b, c, d, e, index) \ 66 | LOAD(index); \ 67 | FUNC1(a, b, c, d, e); \ 68 | MIX(a, b, c, d, e, 0x5A827999) 69 | 70 | #define ROUND1x(a, b, c, d, e, index) \ 71 | SHUFFLE(index); \ 72 | FUNC1(a, b, c, d, e); \ 73 | MIX(a, b, c, d, e, 0x5A827999) 74 | 75 | #define ROUND2(a, b, c, d, e, index) \ 76 | SHUFFLE(index); \ 77 | FUNC2(a, b, c, d, e); \ 78 | MIX(a, b, c, d, e, 0x6ED9EBA1) 79 | 80 | #define ROUND3(a, b, c, d, e, index) \ 81 | SHUFFLE(index); \ 82 | FUNC3(a, b, c, d, e); \ 83 | MIX(a, b, c, d, e, 0x8F1BBCDC) 84 | 85 | #define ROUND4(a, b, c, d, e, index) \ 86 | SHUFFLE(index); \ 87 | FUNC4(a, b, c, d, e); \ 88 | MIX(a, b, c, d, e, 0xCA62C1D6) 89 | 90 | TEXT ·block(SB),NOSPLIT,$64-32 91 | MOVQ dig+0(FP), BP 92 | MOVQ p_base+8(FP), SI 93 | MOVQ p_len+16(FP), DX 94 | SHRQ $6, DX 95 | SHLQ $6, DX 96 | 97 | LEAQ (SI)(DX*1), DI 98 | MOVL (0*4)(BP), AX 99 | MOVL (1*4)(BP), BX 100 | MOVL (2*4)(BP), CX 101 | MOVL (3*4)(BP), DX 102 | MOVL (4*4)(BP), BP 103 | 104 | CMPQ SI, DI 105 | JEQ end 106 | 107 | loop: 108 | MOVL AX, R11 109 | MOVL BX, R12 110 | MOVL CX, R13 111 | MOVL DX, R14 112 | MOVL BP, R15 113 | 114 | ROUND1(AX, BX, CX, DX, BP, 0) 115 | ROUND1(BP, AX, BX, CX, DX, 1) 116 | ROUND1(DX, BP, AX, BX, CX, 2) 117 | ROUND1(CX, DX, BP, AX, BX, 3) 118 | ROUND1(BX, CX, DX, BP, AX, 4) 119 | ROUND1(AX, BX, CX, DX, BP, 5) 120 | ROUND1(BP, AX, BX, CX, DX, 6) 121 | ROUND1(DX, BP, AX, BX, CX, 7) 122 | ROUND1(CX, DX, BP, AX, BX, 8) 123 | ROUND1(BX, CX, DX, BP, AX, 9) 124 | ROUND1(AX, BX, CX, DX, BP, 10) 125 | ROUND1(BP, AX, BX, CX, DX, 11) 126 | ROUND1(DX, BP, AX, BX, CX, 12) 127 | ROUND1(CX, DX, BP, AX, BX, 13) 128 | ROUND1(BX, CX, DX, BP, AX, 14) 129 | ROUND1(AX, BX, CX, DX, BP, 15) 130 | 131 | ROUND1x(BP, AX, BX, CX, DX, 16) 132 | ROUND1x(DX, BP, AX, BX, CX, 17) 133 | ROUND1x(CX, DX, BP, AX, BX, 18) 134 | ROUND1x(BX, CX, DX, BP, AX, 19) 135 | 136 | ROUND2(AX, BX, CX, DX, BP, 20) 137 | ROUND2(BP, AX, BX, CX, DX, 21) 138 | ROUND2(DX, BP, AX, BX, CX, 22) 139 | ROUND2(CX, DX, BP, AX, BX, 23) 140 | ROUND2(BX, CX, DX, BP, AX, 24) 141 | ROUND2(AX, BX, CX, DX, BP, 25) 142 | ROUND2(BP, AX, BX, CX, DX, 26) 143 | ROUND2(DX, BP, AX, BX, CX, 27) 144 | ROUND2(CX, DX, BP, AX, BX, 28) 145 | ROUND2(BX, CX, DX, BP, AX, 29) 146 | ROUND2(AX, BX, CX, DX, BP, 30) 147 | ROUND2(BP, AX, BX, CX, DX, 31) 148 | ROUND2(DX, BP, AX, BX, CX, 32) 149 | ROUND2(CX, DX, BP, AX, BX, 33) 150 | ROUND2(BX, CX, DX, BP, AX, 34) 151 | ROUND2(AX, BX, CX, DX, BP, 35) 152 | ROUND2(BP, AX, BX, CX, DX, 36) 153 | ROUND2(DX, BP, AX, BX, CX, 37) 154 | ROUND2(CX, DX, BP, AX, BX, 38) 155 | ROUND2(BX, CX, DX, BP, AX, 39) 156 | 157 | ROUND3(AX, BX, CX, DX, BP, 40) 158 | ROUND3(BP, AX, BX, CX, DX, 41) 159 | ROUND3(DX, BP, AX, BX, CX, 42) 160 | ROUND3(CX, DX, BP, AX, BX, 43) 161 | ROUND3(BX, CX, DX, BP, AX, 44) 162 | ROUND3(AX, BX, CX, DX, BP, 45) 163 | ROUND3(BP, AX, BX, CX, DX, 46) 164 | ROUND3(DX, BP, AX, BX, CX, 47) 165 | ROUND3(CX, DX, BP, AX, BX, 48) 166 | ROUND3(BX, CX, DX, BP, AX, 49) 167 | ROUND3(AX, BX, CX, DX, BP, 50) 168 | ROUND3(BP, AX, BX, CX, DX, 51) 169 | ROUND3(DX, BP, AX, BX, CX, 52) 170 | ROUND3(CX, DX, BP, AX, BX, 53) 171 | ROUND3(BX, CX, DX, BP, AX, 54) 172 | ROUND3(AX, BX, CX, DX, BP, 55) 173 | ROUND3(BP, AX, BX, CX, DX, 56) 174 | ROUND3(DX, BP, AX, BX, CX, 57) 175 | ROUND3(CX, DX, BP, AX, BX, 58) 176 | ROUND3(BX, CX, DX, BP, AX, 59) 177 | 178 | ROUND4(AX, BX, CX, DX, BP, 60) 179 | ROUND4(BP, AX, BX, CX, DX, 61) 180 | ROUND4(DX, BP, AX, BX, CX, 62) 181 | ROUND4(CX, DX, BP, AX, BX, 63) 182 | ROUND4(BX, CX, DX, BP, AX, 64) 183 | ROUND4(AX, BX, CX, DX, BP, 65) 184 | ROUND4(BP, AX, BX, CX, DX, 66) 185 | ROUND4(DX, BP, AX, BX, CX, 67) 186 | ROUND4(CX, DX, BP, AX, BX, 68) 187 | ROUND4(BX, CX, DX, BP, AX, 69) 188 | ROUND4(AX, BX, CX, DX, BP, 70) 189 | ROUND4(BP, AX, BX, CX, DX, 71) 190 | ROUND4(DX, BP, AX, BX, CX, 72) 191 | ROUND4(CX, DX, BP, AX, BX, 73) 192 | ROUND4(BX, CX, DX, BP, AX, 74) 193 | ROUND4(AX, BX, CX, DX, BP, 75) 194 | ROUND4(BP, AX, BX, CX, DX, 76) 195 | ROUND4(DX, BP, AX, BX, CX, 77) 196 | ROUND4(CX, DX, BP, AX, BX, 78) 197 | ROUND4(BX, CX, DX, BP, AX, 79) 198 | 199 | ADDL R11, AX 200 | ADDL R12, BX 201 | ADDL R13, CX 202 | ADDL R14, DX 203 | ADDL R15, BP 204 | 205 | ADDQ $64, SI 206 | CMPQ SI, DI 207 | JB loop 208 | 209 | end: 210 | MOVQ dig+0(FP), DI 211 | MOVL AX, (0*4)(DI) 212 | MOVL BX, (1*4)(DI) 213 | MOVL CX, (2*4)(DI) 214 | MOVL DX, (3*4)(DI) 215 | MOVL BP, (4*4)(DI) 216 | RET 217 | -------------------------------------------------------------------------------- /sha1/sha1block_amd64p32.s: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "textflag.h" 6 | 7 | // SHA1 block routine. See sha1block.go for Go equivalent. 8 | // 9 | // There are 80 rounds of 4 types: 10 | // - rounds 0-15 are type 1 and load data (ROUND1 macro). 11 | // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). 12 | // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). 13 | // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). 14 | // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). 15 | // 16 | // Each round loads or shuffles the data, then computes a per-round 17 | // function of b, c, d, and then mixes the result into and rotates the 18 | // five registers a, b, c, d, e holding the intermediate results. 19 | // 20 | // The register rotation is implemented by rotating the arguments to 21 | // the round macros instead of by explicit move instructions. 22 | // 23 | // amd64p32 version. 24 | // To ensure safety for Native Client, avoids use of BP and R15 25 | // as well as two-register addressing modes. 26 | 27 | #define LOAD(index) \ 28 | MOVL (index*4)(SI), R10; \ 29 | BSWAPL R10; \ 30 | MOVL R10, (index*4)(SP) 31 | 32 | #define SHUFFLE(index) \ 33 | MOVL (((index)&0xf)*4)(SP), R10; \ 34 | XORL (((index-3)&0xf)*4)(SP), R10; \ 35 | XORL (((index-8)&0xf)*4)(SP), R10; \ 36 | XORL (((index-14)&0xf)*4)(SP), R10; \ 37 | ROLL $1, R10; \ 38 | MOVL R10, (((index)&0xf)*4)(SP) 39 | 40 | #define FUNC1(a, b, c, d, e) \ 41 | MOVL d, R9; \ 42 | XORL c, R9; \ 43 | ANDL b, R9; \ 44 | XORL d, R9 45 | 46 | #define FUNC2(a, b, c, d, e) \ 47 | MOVL b, R9; \ 48 | XORL c, R9; \ 49 | XORL d, R9 50 | 51 | #define FUNC3(a, b, c, d, e) \ 52 | MOVL b, R8; \ 53 | ORL c, R8; \ 54 | ANDL d, R8; \ 55 | MOVL b, R9; \ 56 | ANDL c, R9; \ 57 | ORL R8, R9 58 | 59 | #define FUNC4 FUNC2 60 | 61 | #define MIX(a, b, c, d, e, const) \ 62 | ROLL $30, b; \ 63 | ADDL R9, e; \ 64 | MOVL a, R8; \ 65 | ROLL $5, R8; \ 66 | LEAL const(e)(R10*1), e; \ 67 | ADDL R8, e 68 | 69 | #define ROUND1(a, b, c, d, e, index) \ 70 | LOAD(index); \ 71 | FUNC1(a, b, c, d, e); \ 72 | MIX(a, b, c, d, e, 0x5A827999) 73 | 74 | #define ROUND1x(a, b, c, d, e, index) \ 75 | SHUFFLE(index); \ 76 | FUNC1(a, b, c, d, e); \ 77 | MIX(a, b, c, d, e, 0x5A827999) 78 | 79 | #define ROUND2(a, b, c, d, e, index) \ 80 | SHUFFLE(index); \ 81 | FUNC2(a, b, c, d, e); \ 82 | MIX(a, b, c, d, e, 0x6ED9EBA1) 83 | 84 | #define ROUND3(a, b, c, d, e, index) \ 85 | SHUFFLE(index); \ 86 | FUNC3(a, b, c, d, e); \ 87 | MIX(a, b, c, d, e, 0x8F1BBCDC) 88 | 89 | #define ROUND4(a, b, c, d, e, index) \ 90 | SHUFFLE(index); \ 91 | FUNC4(a, b, c, d, e); \ 92 | MIX(a, b, c, d, e, 0xCA62C1D6) 93 | 94 | TEXT ·block(SB),NOSPLIT,$64-32 95 | MOVL dig+0(FP), R14 96 | MOVL p_base+4(FP), SI 97 | MOVL p_len+8(FP), DX 98 | SHRQ $6, DX 99 | SHLQ $6, DX 100 | 101 | LEAQ (SI)(DX*1), DI 102 | MOVL (0*4)(R14), AX 103 | MOVL (1*4)(R14), BX 104 | MOVL (2*4)(R14), CX 105 | MOVL (3*4)(R14), DX 106 | MOVL (4*4)(R14), R13 107 | 108 | CMPQ SI, DI 109 | JEQ end 110 | 111 | loop: 112 | #define BP R13 /* keep diff from sha1block_amd64.s small */ 113 | ROUND1(AX, BX, CX, DX, BP, 0) 114 | ROUND1(BP, AX, BX, CX, DX, 1) 115 | ROUND1(DX, BP, AX, BX, CX, 2) 116 | ROUND1(CX, DX, BP, AX, BX, 3) 117 | ROUND1(BX, CX, DX, BP, AX, 4) 118 | ROUND1(AX, BX, CX, DX, BP, 5) 119 | ROUND1(BP, AX, BX, CX, DX, 6) 120 | ROUND1(DX, BP, AX, BX, CX, 7) 121 | ROUND1(CX, DX, BP, AX, BX, 8) 122 | ROUND1(BX, CX, DX, BP, AX, 9) 123 | ROUND1(AX, BX, CX, DX, BP, 10) 124 | ROUND1(BP, AX, BX, CX, DX, 11) 125 | ROUND1(DX, BP, AX, BX, CX, 12) 126 | ROUND1(CX, DX, BP, AX, BX, 13) 127 | ROUND1(BX, CX, DX, BP, AX, 14) 128 | ROUND1(AX, BX, CX, DX, BP, 15) 129 | 130 | ROUND1x(BP, AX, BX, CX, DX, 16) 131 | ROUND1x(DX, BP, AX, BX, CX, 17) 132 | ROUND1x(CX, DX, BP, AX, BX, 18) 133 | ROUND1x(BX, CX, DX, BP, AX, 19) 134 | 135 | ROUND2(AX, BX, CX, DX, BP, 20) 136 | ROUND2(BP, AX, BX, CX, DX, 21) 137 | ROUND2(DX, BP, AX, BX, CX, 22) 138 | ROUND2(CX, DX, BP, AX, BX, 23) 139 | ROUND2(BX, CX, DX, BP, AX, 24) 140 | ROUND2(AX, BX, CX, DX, BP, 25) 141 | ROUND2(BP, AX, BX, CX, DX, 26) 142 | ROUND2(DX, BP, AX, BX, CX, 27) 143 | ROUND2(CX, DX, BP, AX, BX, 28) 144 | ROUND2(BX, CX, DX, BP, AX, 29) 145 | ROUND2(AX, BX, CX, DX, BP, 30) 146 | ROUND2(BP, AX, BX, CX, DX, 31) 147 | ROUND2(DX, BP, AX, BX, CX, 32) 148 | ROUND2(CX, DX, BP, AX, BX, 33) 149 | ROUND2(BX, CX, DX, BP, AX, 34) 150 | ROUND2(AX, BX, CX, DX, BP, 35) 151 | ROUND2(BP, AX, BX, CX, DX, 36) 152 | ROUND2(DX, BP, AX, BX, CX, 37) 153 | ROUND2(CX, DX, BP, AX, BX, 38) 154 | ROUND2(BX, CX, DX, BP, AX, 39) 155 | 156 | ROUND3(AX, BX, CX, DX, BP, 40) 157 | ROUND3(BP, AX, BX, CX, DX, 41) 158 | ROUND3(DX, BP, AX, BX, CX, 42) 159 | ROUND3(CX, DX, BP, AX, BX, 43) 160 | ROUND3(BX, CX, DX, BP, AX, 44) 161 | ROUND3(AX, BX, CX, DX, BP, 45) 162 | ROUND3(BP, AX, BX, CX, DX, 46) 163 | ROUND3(DX, BP, AX, BX, CX, 47) 164 | ROUND3(CX, DX, BP, AX, BX, 48) 165 | ROUND3(BX, CX, DX, BP, AX, 49) 166 | ROUND3(AX, BX, CX, DX, BP, 50) 167 | ROUND3(BP, AX, BX, CX, DX, 51) 168 | ROUND3(DX, BP, AX, BX, CX, 52) 169 | ROUND3(CX, DX, BP, AX, BX, 53) 170 | ROUND3(BX, CX, DX, BP, AX, 54) 171 | ROUND3(AX, BX, CX, DX, BP, 55) 172 | ROUND3(BP, AX, BX, CX, DX, 56) 173 | ROUND3(DX, BP, AX, BX, CX, 57) 174 | ROUND3(CX, DX, BP, AX, BX, 58) 175 | ROUND3(BX, CX, DX, BP, AX, 59) 176 | 177 | ROUND4(AX, BX, CX, DX, BP, 60) 178 | ROUND4(BP, AX, BX, CX, DX, 61) 179 | ROUND4(DX, BP, AX, BX, CX, 62) 180 | ROUND4(CX, DX, BP, AX, BX, 63) 181 | ROUND4(BX, CX, DX, BP, AX, 64) 182 | ROUND4(AX, BX, CX, DX, BP, 65) 183 | ROUND4(BP, AX, BX, CX, DX, 66) 184 | ROUND4(DX, BP, AX, BX, CX, 67) 185 | ROUND4(CX, DX, BP, AX, BX, 68) 186 | ROUND4(BX, CX, DX, BP, AX, 69) 187 | ROUND4(AX, BX, CX, DX, BP, 70) 188 | ROUND4(BP, AX, BX, CX, DX, 71) 189 | ROUND4(DX, BP, AX, BX, CX, 72) 190 | ROUND4(CX, DX, BP, AX, BX, 73) 191 | ROUND4(BX, CX, DX, BP, AX, 74) 192 | ROUND4(AX, BX, CX, DX, BP, 75) 193 | ROUND4(BP, AX, BX, CX, DX, 76) 194 | ROUND4(DX, BP, AX, BX, CX, 77) 195 | ROUND4(CX, DX, BP, AX, BX, 78) 196 | ROUND4(BX, CX, DX, BP, AX, 79) 197 | #undef BP 198 | 199 | ADDL (0*4)(R14), AX 200 | ADDL (1*4)(R14), BX 201 | ADDL (2*4)(R14), CX 202 | ADDL (3*4)(R14), DX 203 | ADDL (4*4)(R14), R13 204 | 205 | MOVL AX, (0*4)(R14) 206 | MOVL BX, (1*4)(R14) 207 | MOVL CX, (2*4)(R14) 208 | MOVL DX, (3*4)(R14) 209 | MOVL R13, (4*4)(R14) 210 | 211 | ADDQ $64, SI 212 | CMPQ SI, DI 213 | JB loop 214 | 215 | end: 216 | RET 217 | -------------------------------------------------------------------------------- /sha1/sha1block_arm.s: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // 5 | // ARM version of md5block.go 6 | 7 | #include "textflag.h" 8 | 9 | // SHA1 block routine. See sha1block.go for Go equivalent. 10 | // 11 | // There are 80 rounds of 4 types: 12 | // - rounds 0-15 are type 1 and load data (ROUND1 macro). 13 | // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). 14 | // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). 15 | // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). 16 | // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). 17 | // 18 | // Each round loads or shuffles the data, then computes a per-round 19 | // function of b, c, d, and then mixes the result into and rotates the 20 | // five registers a, b, c, d, e holding the intermediate results. 21 | // 22 | // The register rotation is implemented by rotating the arguments to 23 | // the round macros instead of by explicit move instructions. 24 | 25 | // Register definitions 26 | data = 0 // Pointer to incoming data 27 | const = 1 // Current constant for SHA round 28 | a = 2 // SHA1 accumulator 29 | b = 3 // SHA1 accumulator 30 | c = 4 // SHA1 accumulator 31 | d = 5 // SHA1 accumulator 32 | e = 6 // SHA1 accumulator 33 | t0 = 7 // Temporary 34 | t1 = 8 // Temporary 35 | // r9, r10 are forbidden 36 | // r11 is OK provided you check the assembler that no synthetic instructions use it 37 | t2 = 11 // Temporary 38 | ctr = 12 // loop counter 39 | w = 14 // point to w buffer 40 | 41 | // func block(dig *Digest, p []byte) 42 | // 0(FP) is *Digest 43 | // 4(FP) is p.array (struct Slice) 44 | // 8(FP) is p.len 45 | //12(FP) is p.cap 46 | // 47 | // Stack frame 48 | p_end = -4 // -4(SP) pointer to the end of data 49 | p_data = p_end - 4 // -8(SP) current data pointer 50 | w_buf = p_data - 4*80 // -328(SP) 80 words temporary buffer w uint32[80] 51 | saved = w_buf - 4*5 // -348(SP) saved sha1 registers a,b,c,d,e - these must be last 52 | // Total size +4 for saved LR is 352 53 | 54 | // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3] 55 | // e += w[i] 56 | #define LOAD(e) \ 57 | MOVBU 2(R(data)), R(t0) ; \ 58 | MOVBU 3(R(data)), R(t1) ; \ 59 | MOVBU 1(R(data)), R(t2) ; \ 60 | ORR R(t0)<<8, R(t1), R(t0) ; \ 61 | MOVBU.P 4(R(data)), R(t1) ; \ 62 | ORR R(t2)<<16, R(t0), R(t0) ; \ 63 | ORR R(t1)<<24, R(t0), R(t0) ; \ 64 | MOVW.P R(t0), 4(R(w)) ; \ 65 | ADD R(t0), R(e), R(e) 66 | 67 | // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] 68 | // w[i&0xf] = tmp<<1 | tmp>>(32-1) 69 | // e += w[i&0xf] 70 | #define SHUFFLE(e) \ 71 | MOVW (-16*4)(R(w)), R(t0) ; \ 72 | MOVW (-14*4)(R(w)), R(t1) ; \ 73 | MOVW (-8*4)(R(w)), R(t2) ; \ 74 | EOR R(t0), R(t1), R(t0) ; \ 75 | MOVW (-3*4)(R(w)), R(t1) ; \ 76 | EOR R(t2), R(t0), R(t0) ; \ 77 | EOR R(t0), R(t1), R(t0) ; \ 78 | MOVW R(t0)@>(32-1), R(t0) ; \ 79 | MOVW.P R(t0), 4(R(w)) ; \ 80 | ADD R(t0), R(e), R(e) 81 | 82 | // t1 = (b & c) | ((~b) & d) 83 | #define FUNC1(a, b, c, d, e) \ 84 | MVN R(b), R(t1) ; \ 85 | AND R(b), R(c), R(t0) ; \ 86 | AND R(d), R(t1), R(t1) ; \ 87 | ORR R(t0), R(t1), R(t1) 88 | 89 | // t1 = b ^ c ^ d 90 | #define FUNC2(a, b, c, d, e) \ 91 | EOR R(b), R(c), R(t1) ; \ 92 | EOR R(d), R(t1), R(t1) 93 | 94 | // t1 = (b & c) | (b & d) | (c & d) = 95 | // t1 = (b & c) | ((b | c) & d) 96 | #define FUNC3(a, b, c, d, e) \ 97 | ORR R(b), R(c), R(t0) ; \ 98 | AND R(b), R(c), R(t1) ; \ 99 | AND R(d), R(t0), R(t0) ; \ 100 | ORR R(t0), R(t1), R(t1) 101 | 102 | #define FUNC4 FUNC2 103 | 104 | // a5 := a<<5 | a>>(32-5) 105 | // b = b<<30 | b>>(32-30) 106 | // e = a5 + t1 + e + const 107 | #define MIX(a, b, c, d, e) \ 108 | ADD R(t1), R(e), R(e) ; \ 109 | MOVW R(b)@>(32-30), R(b) ; \ 110 | ADD R(a)@>(32-5), R(e), R(e) ; \ 111 | ADD R(const), R(e), R(e) 112 | 113 | #define ROUND1(a, b, c, d, e) \ 114 | LOAD(e) ; \ 115 | FUNC1(a, b, c, d, e) ; \ 116 | MIX(a, b, c, d, e) 117 | 118 | #define ROUND1x(a, b, c, d, e) \ 119 | SHUFFLE(e) ; \ 120 | FUNC1(a, b, c, d, e) ; \ 121 | MIX(a, b, c, d, e) 122 | 123 | #define ROUND2(a, b, c, d, e) \ 124 | SHUFFLE(e) ; \ 125 | FUNC2(a, b, c, d, e) ; \ 126 | MIX(a, b, c, d, e) 127 | 128 | #define ROUND3(a, b, c, d, e) \ 129 | SHUFFLE(e) ; \ 130 | FUNC3(a, b, c, d, e) ; \ 131 | MIX(a, b, c, d, e) 132 | 133 | #define ROUND4(a, b, c, d, e) \ 134 | SHUFFLE(e) ; \ 135 | FUNC4(a, b, c, d, e) ; \ 136 | MIX(a, b, c, d, e) 137 | 138 | 139 | // func block(dig *Digest, p []byte) 140 | TEXT ·block(SB), 0, $352-16 141 | MOVW p+4(FP), R(data) // pointer to the data 142 | MOVW p_len+8(FP), R(t0) // number of bytes 143 | ADD R(data), R(t0) 144 | MOVW R(t0), p_end(SP) // pointer to end of data 145 | 146 | // Load up initial SHA1 accumulator 147 | MOVW dig+0(FP), R(t0) 148 | MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)] 149 | 150 | loop: 151 | // Save registers at SP+4 onwards 152 | MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13) 153 | 154 | MOVW $w_buf(SP), R(w) 155 | MOVW $0x5A827999, R(const) 156 | MOVW $3, R(ctr) 157 | loop1: ROUND1(a, b, c, d, e) 158 | ROUND1(e, a, b, c, d) 159 | ROUND1(d, e, a, b, c) 160 | ROUND1(c, d, e, a, b) 161 | ROUND1(b, c, d, e, a) 162 | SUB.S $1, R(ctr) 163 | BNE loop1 164 | 165 | ROUND1(a, b, c, d, e) 166 | ROUND1x(e, a, b, c, d) 167 | ROUND1x(d, e, a, b, c) 168 | ROUND1x(c, d, e, a, b) 169 | ROUND1x(b, c, d, e, a) 170 | 171 | MOVW $0x6ED9EBA1, R(const) 172 | MOVW $4, R(ctr) 173 | loop2: ROUND2(a, b, c, d, e) 174 | ROUND2(e, a, b, c, d) 175 | ROUND2(d, e, a, b, c) 176 | ROUND2(c, d, e, a, b) 177 | ROUND2(b, c, d, e, a) 178 | SUB.S $1, R(ctr) 179 | BNE loop2 180 | 181 | MOVW $0x8F1BBCDC, R(const) 182 | MOVW $4, R(ctr) 183 | loop3: ROUND3(a, b, c, d, e) 184 | ROUND3(e, a, b, c, d) 185 | ROUND3(d, e, a, b, c) 186 | ROUND3(c, d, e, a, b) 187 | ROUND3(b, c, d, e, a) 188 | SUB.S $1, R(ctr) 189 | BNE loop3 190 | 191 | MOVW $0xCA62C1D6, R(const) 192 | MOVW $4, R(ctr) 193 | loop4: ROUND4(a, b, c, d, e) 194 | ROUND4(e, a, b, c, d) 195 | ROUND4(d, e, a, b, c) 196 | ROUND4(c, d, e, a, b) 197 | ROUND4(b, c, d, e, a) 198 | SUB.S $1, R(ctr) 199 | BNE loop4 200 | 201 | // Accumulate - restoring registers from SP+4 202 | MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)] 203 | ADD R(t0), R(a) 204 | ADD R(t1), R(b) 205 | ADD R(t2), R(c) 206 | ADD R(ctr), R(d) 207 | ADD R(w), R(e) 208 | 209 | MOVW p_end(SP), R(t0) 210 | CMP R(t0), R(data) 211 | BLO loop 212 | 213 | // Save final SHA1 accumulator 214 | MOVW dig+0(FP), R(t0) 215 | MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0)) 216 | 217 | RET 218 | -------------------------------------------------------------------------------- /sha1/sha1block_decl.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build amd64 amd64p32 arm 386 6 | 7 | package sha1 8 | 9 | //go:noescape 10 | 11 | func block(dig *Digest, p []byte) 12 | -------------------------------------------------------------------------------- /sha1/sha1block_generic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !amd64,!amd64p32,!386,!arm 6 | 7 | package sha1 8 | 9 | var block = blockGeneric 10 | -------------------------------------------------------------------------------- /sha1/textflag.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file defines flags attached to various functions 6 | // and data objects. The compilers, assemblers, and linker must 7 | // all agree on these values. 8 | 9 | // Don't profile the marked routine. This flag is deprecated. 10 | #define NOPROF 1 11 | // It is ok for the linker to get multiple of these symbols. It will 12 | // pick one of the duplicates to use. 13 | #define DUPOK 2 14 | // Don't insert stack check preamble. 15 | #define NOSPLIT 4 16 | // Put this data in a read-only section. 17 | #define RODATA 8 18 | // This data contains no pointers. 19 | #define NOPTR 16 20 | // This is a wrapper function and should not count as disabling 'recover'. 21 | #define WRAPPER 32 22 | // This function uses its incoming context register. 23 | #define NEEDCTXT 64 24 | 25 | /*c2go 26 | enum 27 | { 28 | NOPROF = 1, 29 | DUPOK = 2, 30 | NOSPLIT = 4, 31 | RODATA = 8, 32 | NOPTR = 16, 33 | WRAPPER = 32, 34 | NEEDCTXT = 64, 35 | }; 36 | */ 37 | 38 | -------------------------------------------------------------------------------- /stats.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "sync/atomic" 9 | ) 10 | 11 | const ( 12 | _ = iota 13 | STATCTR_CONNECTIONS 14 | STATCTR_CIRC_CREATE 15 | STATCTR_CIRC_DESTROY 16 | STATCTR_CIRC_CURRENT 17 | 18 | STATCTR_COUNT // must be last 19 | ) 20 | 21 | var counts [STATCTR_COUNT]int32 22 | 23 | func StatsUpd(t, val int32) int32 { 24 | n := atomic.AddInt32(&(counts[t]), val) 25 | return n 26 | } 27 | 28 | func StatsNewCircuit() { 29 | a := StatsUpd(STATCTR_CIRC_CREATE, 1) 30 | b := StatsUpd(STATCTR_CIRC_CURRENT, 1) 31 | Log(LOG_INFO, "Now have %d circuits (a total of %d were created)", b, a) 32 | } 33 | 34 | func StatsDestroyCircuit() { 35 | a := StatsUpd(STATCTR_CIRC_DESTROY, 1) 36 | b := StatsUpd(STATCTR_CIRC_CURRENT, -1) 37 | Log(LOG_INFO, "Now have %d circuits (a total of %d were destroyed)", b, a) 38 | } 39 | 40 | func StatsAddConnection() { 41 | a := StatsUpd(STATCTR_CONNECTIONS, 1) 42 | Log(LOG_INFO, "Now have %d connections", a) 43 | } 44 | 45 | func StatsRemoveConnection() { 46 | a := StatsUpd(STATCTR_CONNECTIONS, -1) 47 | Log(LOG_INFO, "Now have %d connections", a) 48 | } 49 | 50 | func StatsAddInput(bytes uint32) { 51 | //atomic.AddUint32(&counterInput, bytes) 52 | } 53 | 54 | func StatsAddOutput(bytes uint32) { 55 | //atomic.AddUint32(&counterOutput, bytes) 56 | } 57 | 58 | func RecordStats() (input, output uint32) { 59 | //input = atomic.SwapUint32(&counterInput, 0) 60 | //output = atomic.SwapUint32(&counterOutput, 0) 61 | return 62 | } 63 | -------------------------------------------------------------------------------- /stream.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "net" 10 | "sync/atomic" 11 | "time" 12 | ) 13 | 14 | type StreamMessageType byte 15 | 16 | const ( 17 | STREAM_CONNECTED StreamMessageType = iota 18 | STREAM_DISCONNECTED 19 | STREAM_SENDME 20 | ) 21 | 22 | type Stream struct { 23 | id StreamID 24 | writeChan chan []byte 25 | forwardWindow, backwardWindow *Window 26 | finished int32 27 | } 28 | 29 | /* Stream cleanups 30 | * 31 | * When the writer fails to write we close the socket, triggering the reader to fail. 32 | * When the reader fails to read we close the channel. Closing the channel will cause the goroutine to finish. 33 | * When the circuit tells us to close by closing our channel, we just finish the goroutine, causing the other cleanup to happen. 34 | * 35 | * Finishing the goroutine means closing the socket and informing the channel that we're done (which should then dealloc us) 36 | */ 37 | 38 | func NewStream(id StreamID) (*Stream, error) { 39 | s := &Stream{ 40 | id: id, 41 | writeChan: make(chan []byte, 505), 42 | forwardWindow: NewWindow(500), 43 | backwardWindow: NewWindow(500), 44 | } 45 | return s, nil 46 | } 47 | 48 | func (s *Stream) Destroy() { 49 | close(s.writeChan) 50 | } 51 | 52 | var dialer = net.Dialer{ 53 | KeepAlive: 0, 54 | DualStack: true, 55 | Timeout: 5 * time.Second, 56 | } 57 | 58 | func (s *Stream) Run(circID CircuitID, circWindow *Window, queue CircReadQueue, address string, port uint16, isDir bool, ep ExitPolicy) { 59 | addr := ResolveDNS(address)[0] 60 | 61 | if !(addr.Type == 4 || addr.Type == 6) { 62 | queue <- &StreamControl{ 63 | circuitID: circID, 64 | streamID: s.id, 65 | data: STREAM_DISCONNECTED, 66 | reason: STREAM_REASON_RESOLVEFAILED, 67 | } 68 | } 69 | 70 | if !isDir && !ep.AllowsConnect(addr.Value, port) { 71 | queue <- &StreamControl{ 72 | circuitID: circID, 73 | streamID: s.id, 74 | data: STREAM_DISCONNECTED, 75 | reason: STREAM_REASON_EXITPOLICY, 76 | remoteAddr: addr.Value, 77 | } 78 | return 79 | } 80 | 81 | conn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", addr.String(), port)) 82 | if err != nil { 83 | queue <- &StreamControl{ 84 | circuitID: circID, 85 | streamID: s.id, 86 | data: STREAM_DISCONNECTED, 87 | reason: STREAM_REASON_CONNECTREFUSED, 88 | } 89 | return 90 | } 91 | 92 | queue <- &StreamControl{ 93 | circuitID: circID, 94 | streamID: s.id, 95 | data: STREAM_CONNECTED, 96 | remoteAddr: addr.Value, 97 | } 98 | 99 | defer func() { 100 | conn.Close() 101 | 102 | atomic.StoreInt32(&s.finished, 1) 103 | s.backwardWindow.Abort() 104 | s.forwardWindow.Abort() 105 | circWindow.Abort() 106 | 107 | queue <- &StreamControl{ 108 | circuitID: circID, 109 | streamID: s.id, 110 | data: STREAM_DISCONNECTED, 111 | reason: STREAM_REASON_DONE, 112 | } // XXX this could deadlock 113 | Log(LOG_CIRC, "Disconnected stream %d to %s", s.id, address) 114 | }() 115 | 116 | readQueue := make(chan []byte, 5) 117 | 118 | go s.reader(conn, circWindow, readQueue) 119 | 120 | for { 121 | select { 122 | case data, ok := <-s.writeChan: 123 | if !ok { 124 | return 125 | } 126 | _, err := conn.Write(data) 127 | if err != nil { 128 | return 129 | } 130 | ReturnCellBuf(data) 131 | 132 | for len(s.writeChan) < 10 && s.forwardWindow.GetLevel() <= 450 { 133 | s.forwardWindow.Refill(50) 134 | queue <- &StreamControl{ 135 | data: STREAM_SENDME, 136 | circuitID: circID, 137 | streamID: s.id, 138 | } 139 | } 140 | case data, ok := <-readQueue: 141 | if !ok { 142 | return 143 | } 144 | queue <- &StreamData{ 145 | circuitID: circID, 146 | streamID: s.id, 147 | data: data, 148 | } // XXX this could deadlock 149 | } 150 | } 151 | } 152 | 153 | func (s *Stream) reader(conn net.Conn, circWindow *Window, queue chan []byte) { 154 | var readBuf [4096]byte 155 | 156 | for { 157 | hasWnd1 := false 158 | hasWnd2 := false 159 | 160 | // Try to obtain permission to send the data. 161 | for !(hasWnd1 && hasWnd2) { 162 | done := atomic.LoadInt32(&s.finished) 163 | if done != 0 { 164 | close(queue) 165 | return 166 | } 167 | 168 | if !hasWnd1 { 169 | hasWnd1 = s.backwardWindow.Take() 170 | continue 171 | } 172 | if !hasWnd2 { 173 | hasWnd2 = circWindow.Take() 174 | continue 175 | } 176 | } 177 | 178 | bytes, err := conn.Read(readBuf[:]) 179 | if err != nil && bytes <= 0 { 180 | close(queue) 181 | return 182 | } 183 | for i := 0; i < bytes; { 184 | s := MAX_RELAY_LEN 185 | if s > bytes-i { 186 | s = bytes-i 187 | } 188 | cell := GetCellBuf(false) 189 | copy(cell, readBuf[i:]) 190 | queue <- cell[0:s] // XXX would it make sense to add a timeout here? This has proven to deadlock 191 | i += s 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /streamcontrol.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type StreamControl struct { 8 | NeverForRelay 9 | NoBuffers 10 | circuitID CircuitID 11 | streamID StreamID 12 | data StreamMessageType 13 | reason StreamEndReason 14 | remoteAddr []byte 15 | } 16 | 17 | func (sd *StreamControl) CircID() CircuitID { 18 | return sd.circuitID 19 | } 20 | 21 | func (sc *StreamControl) Handle(c *OnionConnection, circ *Circuit) ActionableError { 22 | switch sc.data { 23 | case STREAM_CONNECTED: 24 | var data []byte 25 | if sc.remoteAddr != nil { 26 | if len(sc.remoteAddr) == 4 { 27 | data = make([]byte, 8) //XXX 28 | copy(data, sc.remoteAddr) 29 | data[6] = 1 30 | data[7] = 44 31 | } else if len(sc.remoteAddr) == 16 { 32 | data = make([]byte, 25) //XXX 33 | data[4] = 6 34 | copy(data[5:], sc.remoteAddr) 35 | data[23] = 1 36 | data[24] = 44 37 | } 38 | } 39 | 40 | return c.sendRelayCell(circ, sc.streamID, BackwardDirection, RELAY_CONNECTED, data) 41 | 42 | case STREAM_DISCONNECTED: 43 | stream, ok := circ.streams[sc.streamID] 44 | if !ok { 45 | return nil 46 | } 47 | delete(circ.streams, sc.streamID) 48 | stream.Destroy() 49 | 50 | // We need to inform the OP that the connection died 51 | var data []byte 52 | if sc.remoteAddr != nil { 53 | if len(sc.remoteAddr) == 4 { 54 | data = make([]byte, 9) //XXX 55 | data[0] = byte(sc.reason) 56 | copy(data[1:], sc.remoteAddr) 57 | data[7] = 1 58 | data[8] = 44 59 | } else if len(sc.remoteAddr) == 16 { 60 | data = make([]byte, 26) //XXX 61 | data[0] = byte(sc.reason) 62 | data[5] = 6 63 | copy(data[6:], sc.remoteAddr) 64 | data[24] = 1 65 | data[25] = 44 66 | } else { 67 | data = []byte{byte(sc.reason)} 68 | } 69 | } 70 | return c.sendRelayCell(circ, sc.streamID, BackwardDirection, RELAY_END, data) 71 | 72 | case STREAM_SENDME: 73 | _, ok := circ.streams[sc.streamID] 74 | if !ok { 75 | return nil 76 | } 77 | 78 | return c.sendRelayCell(circ, sc.streamID, BackwardDirection, RELAY_SENDME, nil) 79 | 80 | default: 81 | panic("Did not understand our StreamControl message!") 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /streamdata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | type StreamData struct { 8 | NeverForRelay 9 | circuitID CircuitID 10 | streamID StreamID 11 | data []byte 12 | } 13 | 14 | func (sd *StreamData) CircID() CircuitID { 15 | return sd.circuitID 16 | } 17 | 18 | func (sd *StreamData) Handle(c *OnionConnection, circ *Circuit) ActionableError { 19 | data := sd.data 20 | 21 | for pos := 0; pos < len(data); pos += MAX_RELAY_LEN { 22 | thisLen := len(data) - pos 23 | if thisLen > MAX_RELAY_LEN { 24 | thisLen = MAX_RELAY_LEN 25 | } 26 | 27 | data := data[pos : pos+thisLen] 28 | if err := c.sendRelayCell(circ, sd.streamID, BackwardDirection, RELAY_DATA, data); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | 36 | func (sd *StreamData) ReleaseBuffers() { 37 | ReturnCellBuf(sd.data) 38 | } 39 | -------------------------------------------------------------------------------- /tls.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "crypto/sha1" 9 | "crypto/sha256" 10 | "encoding/base32" 11 | "github.com/tvdw/openssl" 12 | "log" 13 | "math/rand" 14 | "net" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | const SSLRecordSize = openssl.SSLRecordSize 20 | 21 | type TorTLS struct { 22 | ctx *openssl.Ctx 23 | 24 | LinkKey, IdKey, AuthKey openssl.PrivateKey 25 | LinkCert, IdCert, AuthCert *openssl.Certificate 26 | LinkCertDER, IdCertDER, AuthCertDER []byte 27 | Fingerprint Fingerprint 28 | Fingerprint256 []byte 29 | } 30 | 31 | func NewTLSCtx(isClient bool, or *ORCtx) (*TorTLS, error) { 32 | log.Printf("Creating TLS context with isClient=%v\n", isClient) 33 | 34 | sslCtx, err := openssl.NewCtxWithVersion(openssl.AnyVersion) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | tls := &TorTLS{ 40 | ctx: sslCtx, 41 | } 42 | 43 | // Considering how important this piece of code is for resisting fingerprints, we just follow whatever Tor itself does 44 | 45 | if !isClient { // XXX simplify 46 | nickname1 := RandomHostname(8, 20, "www.", ".net") 47 | nickname2 := RandomHostname(8, 20, "www.", ".com") 48 | 49 | issued, _ := time.ParseDuration("-24h") // XXX check what tor does (some time ago, then a long-time cert) 50 | expires, _ := time.ParseDuration("24h") // XXX also, don't re-use for all certs 51 | 52 | tmpPk, err := openssl.GenerateRSAKeyWithExponent(1024, 65537) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | authPk, err := openssl.GenerateRSAKeyWithExponent(1024, 65537) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | cert, err := openssl.NewCertificate(&openssl.CertificateInfo{ 63 | CommonName: nickname1, 64 | Serial: rand.Int63(), 65 | Issued: issued, 66 | Expires: expires, 67 | }, tmpPk) 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | identityPk := or.identityKey 73 | 74 | idcert, err := openssl.NewCertificate(&openssl.CertificateInfo{ 75 | CommonName: nickname2, 76 | Serial: rand.Int63(), 77 | Issued: issued, 78 | Expires: expires, 79 | }, identityPk) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | authcert, err := openssl.NewCertificate(&openssl.CertificateInfo{ 85 | CommonName: nickname1, 86 | Serial: rand.Int63(), 87 | Issued: issued, 88 | Expires: expires, 89 | }, authPk) 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | if err := cert.SetIssuer(idcert); err != nil { 95 | return nil, err 96 | } 97 | if err := cert.Sign(identityPk, openssl.EVP_SHA1); err != nil { 98 | return nil, err 99 | } 100 | 101 | if err := idcert.SetIssuer(idcert); err != nil { 102 | return nil, err 103 | } 104 | if err := idcert.Sign(identityPk, openssl.EVP_SHA1); err != nil { 105 | return nil, err 106 | } 107 | 108 | if err := authcert.SetIssuer(idcert); err != nil { 109 | return nil, err 110 | } 111 | if err := authcert.Sign(identityPk, openssl.EVP_SHA1); err != nil { 112 | return nil, err 113 | } 114 | 115 | sslCtx.UseCertificate(cert) 116 | sslCtx.UsePrivateKey(tmpPk) 117 | 118 | sslCtx.SetEllipticCurve(openssl.Prime256v1) 119 | 120 | tls.LinkCert = cert 121 | tls.LinkKey = tmpPk 122 | tls.LinkCertDER, err = cert.MarshalDER() 123 | if err != nil { 124 | return nil, err 125 | } 126 | 127 | tls.IdCert = idcert 128 | tls.IdKey = identityPk 129 | tls.IdCertDER, err = idcert.MarshalDER() 130 | if err != nil { 131 | return nil, err 132 | } 133 | 134 | keyDer, _ := identityPk.MarshalPKCS1PublicKeyDER() 135 | fingerprint := sha1.Sum(keyDer) 136 | log.Printf("Our fingerprint is %X\n", fingerprint) 137 | copy(tls.Fingerprint[:], fingerprint[:]) 138 | 139 | { 140 | sha := sha256.New() 141 | sha.Write(keyDer) 142 | tls.Fingerprint256 = sha.Sum(nil) 143 | } 144 | 145 | tls.AuthCert = authcert 146 | tls.AuthKey = authPk 147 | tls.AuthCertDER, err = authcert.MarshalDER() 148 | if err != nil { 149 | return nil, err 150 | } 151 | } 152 | 153 | // We don't want SSLv2 or SSLv3 154 | sslCtx.SetOptions(openssl.NoSSLv2 | openssl.NoSSLv3) 155 | 156 | // Prefer the server's ordering of ciphers: the client's ordering has 157 | // historically been chosen for fingerprinting resistance. 158 | sslCtx.SetOptions(openssl.CipherServerPreference) 159 | 160 | //XXX: panic() if we don't have openssl of 1.0.1e or later 161 | //XXX: please remember me why... 162 | 163 | // Tickets hurt perfect forward secrecy, but we still have non-server clients announce them, to reduce fingerprinting impact 164 | if !isClient { 165 | sslCtx.SetOptions(openssl.NoTicket) 166 | } 167 | 168 | // This saves us quite some memory 169 | //sslCtx.SetMode(openssl.ReleaseBuffers) 170 | 171 | // Avoid reusing DH keys if we don't have to 172 | sslCtx.SetOptions(openssl.SingleDHUse | openssl.SingleECDHUse) 173 | 174 | // Never renegotiate. 175 | sslCtx.SetOptions(openssl.NoSessionResumptionOrRenegotiation) 176 | 177 | // All compression does with encrypted data is waste CPU cycles. Disable it 178 | sslCtx.SetOptions(openssl.NoCompression) 179 | 180 | // Disable session caching 181 | sslCtx.SetSessionCacheMode(openssl.SessionCacheOff) 182 | 183 | // Allow all peer certificates 184 | sslCtx.SetVerify(openssl.VerifyNone, nil) 185 | 186 | return tls, nil 187 | } 188 | 189 | func (or *ORCtx) GetTLSCtx(isClient bool) *TorTLS { 190 | or.tlsLock.Lock() 191 | defer or.tlsLock.Unlock() 192 | 193 | //assert(xxxxxxTlsCtx) 194 | if isClient { 195 | return or.clientTlsCtx 196 | } else { 197 | return or.serverTlsCtx 198 | } 199 | } 200 | 201 | func SetupTLS(or *ORCtx) error { 202 | var serverCtx, clientCtx *TorTLS 203 | 204 | serverCtx, err := NewTLSCtx(false, or) 205 | if err != nil { 206 | return err 207 | } 208 | 209 | if or.config.IsPublicServer { 210 | clientCtx = serverCtx 211 | } else { 212 | cCtx, err := NewTLSCtx(true, or) 213 | if err != nil { 214 | return err 215 | } 216 | clientCtx = cCtx 217 | } 218 | 219 | or.tlsLock.Lock() 220 | defer or.tlsLock.Unlock() 221 | 222 | or.clientTlsCtx = clientCtx 223 | or.serverTlsCtx = serverCtx 224 | 225 | return nil 226 | } 227 | 228 | func (or *ORCtx) WrapTLS(conn net.Conn, isClient bool) (*openssl.Conn, *TorTLS, error) { 229 | tls := or.GetTLSCtx(isClient) 230 | 231 | var tlsConn *openssl.Conn 232 | var err error 233 | if isClient { 234 | tlsConn, err = openssl.Client(conn, tls.ctx) 235 | } else { 236 | tlsConn, err = openssl.Server(conn, tls.ctx) 237 | } 238 | 239 | if err != nil { 240 | return nil, nil, err 241 | } 242 | 243 | return tlsConn, tls, nil 244 | } 245 | 246 | func RandomHostname(minLen, maxLen int, prefix, suffix string) string { 247 | chars := (rand.Int() % (maxLen - minLen)) + minLen 248 | 249 | enc := base32.StdEncoding 250 | rndChars := chars 251 | host := make([]byte, rndChars) 252 | CRandBytes(host) 253 | 254 | return prefix + strings.ToLower(enc.EncodeToString(host)[:chars]) + suffix 255 | } 256 | -------------------------------------------------------------------------------- /tordir/descriptor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tordir 6 | 7 | import ( 8 | "bytes" 9 | "crypto/sha1" 10 | "encoding/base64" 11 | "encoding/pem" 12 | "errors" 13 | "fmt" 14 | "github.com/tvdw/openssl" 15 | "log" 16 | "net" 17 | "net/http" 18 | "strings" 19 | "time" 20 | ) 21 | 22 | type Descriptor struct { 23 | // Router definition 24 | Nickname string 25 | Address net.IP 26 | ORPort uint16 27 | DirPort uint16 28 | 29 | BandwidthAvg, BandwidthBurst, BandwidthObserved int 30 | Platform string 31 | LastPublished time.Time 32 | Fingerprint string 33 | Hibernating bool 34 | UptimeStart time.Time 35 | NTORKey []byte 36 | SigningKey, OnionKey openssl.PrivateKey 37 | Accept, Reject, IPv6Policy string 38 | Contact string 39 | Family []string 40 | ReadHistory, WriteHistory []string 41 | EventDNS bool 42 | CachesExtraInfo bool 43 | ExtraInfoDigest string 44 | HiddenServiceDir int 45 | AllowSingleHopExits bool 46 | ORAddress []string 47 | GeoIPDBDigest string 48 | GeoIP6DBDigest string 49 | ExitPolicy string 50 | } 51 | 52 | func (d *Descriptor) Validate() error { 53 | if d.Nickname == "" { 54 | return errors.New("Nickname is required") 55 | } 56 | if d.Address == nil { 57 | return errors.New("Address is required") 58 | } 59 | if d.ORPort == 0 && d.DirPort == 0 { 60 | return errors.New("A descriptor without ORPort or DirPort cannot be published") 61 | } 62 | if d.Platform == "" { 63 | return errors.New("platform is required") 64 | } 65 | if d.SigningKey == nil { 66 | return errors.New("A signing key is required") 67 | } 68 | if d.UptimeStart.IsZero() { 69 | return errors.New("no UptimeStart given") 70 | } 71 | if d.OnionKey == nil { 72 | return errors.New("No OnionKey given") 73 | } 74 | if d.NTORKey == nil { 75 | return errors.New("no NTORKey given") 76 | } 77 | return nil 78 | } 79 | 80 | func (d *Descriptor) SignedDescriptor() (string, error) { 81 | var buf, extra bytes.Buffer 82 | if err := d.Validate(); err != nil { 83 | return "", err 84 | } 85 | 86 | published := time.Now() 87 | 88 | keyDer, _ := d.SigningKey.MarshalPKCS1PublicKeyDER() 89 | fingerprint := sha1.Sum(keyDer) 90 | fp := fmt.Sprintf("%X %X %X %X %X %X %X %X %X %X", 91 | fingerprint[0:2], fingerprint[2:4], fingerprint[4:6], fingerprint[6:8], fingerprint[8:10], 92 | fingerprint[10:12], fingerprint[12:14], fingerprint[14:16], fingerprint[16:18], fingerprint[18:20], 93 | ) 94 | 95 | buf.WriteString(fmt.Sprintf("router %s %s %d 0 %d\n", d.Nickname, d.Address, d.ORPort, d.DirPort)) 96 | extra.WriteString(fmt.Sprintf("extra-info %s %X\n", d.Nickname, fingerprint)) 97 | extra.WriteString(fmt.Sprintf("published %s\n", published.Format("2006-01-02 15:04:05"))) 98 | 99 | for _, addr := range d.ORAddress { 100 | buf.WriteString(addr) 101 | } 102 | buf.WriteString(fmt.Sprintf("platform %s\n", d.Platform)) 103 | buf.WriteString(fmt.Sprintf("protocols Link 1 2 Circuit 1\n")) // Is this really needed? 104 | buf.WriteString(fmt.Sprintf("published %s\n", published.Format("2006-01-02 15:04:05"))) 105 | buf.WriteString(fmt.Sprintf("fingerprint %s\n", fp)) 106 | buf.WriteString(fmt.Sprintf("uptime %d\n", published.Unix()-d.UptimeStart.Unix()+1)) 107 | buf.WriteString(fmt.Sprintf("bandwidth %d %d %d\n", d.BandwidthAvg, d.BandwidthBurst, d.BandwidthObserved)) 108 | extraDigest := sha1.Sum(extra.Bytes()) 109 | buf.WriteString(fmt.Sprintf("extra-info-digest %X\n", extraDigest[:])) 110 | buf.WriteString(fmt.Sprintf("onion-key\n")) 111 | onion, err := d.OnionKey.MarshalPKCS1PublicKeyPEM() 112 | if err != nil { 113 | return "", err 114 | } 115 | buf.Write(onion) 116 | 117 | buf.WriteString(fmt.Sprintf("signing-key\n")) 118 | 119 | pub, err := d.SigningKey.MarshalPKCS1PublicKeyPEM() 120 | if err != nil { 121 | return "", err 122 | } 123 | buf.Write(pub) 124 | 125 | if len(d.Family) != 0 { 126 | buf.WriteString(fmt.Sprintf("family %s\n", strings.Join(d.Family, " "))) 127 | } 128 | if d.Hibernating { 129 | buf.WriteString(fmt.Sprintf("hibernating 1\n")) 130 | } 131 | if d.HiddenServiceDir != 0 { 132 | buf.WriteString(fmt.Sprintf("hidden-service-dir\n")) 133 | } 134 | if d.AllowSingleHopExits { 135 | buf.WriteString(fmt.Sprintf("allow-single-hop-exits\n")) 136 | } 137 | if d.Contact != "" { 138 | buf.WriteString(fmt.Sprintf("contact %s\n", d.Contact)) 139 | } 140 | buf.WriteString(fmt.Sprintf("ntor-onion-key %s\n", base64.StdEncoding.EncodeToString(d.NTORKey))) 141 | buf.WriteString(d.ExitPolicy) 142 | buf.WriteString(fmt.Sprintf("router-signature\n")) 143 | 144 | digest := sha1.Sum(buf.Bytes()) 145 | 146 | // Sign descriptor 147 | signature, err := d.SigningKey.PrivateEncrypt(digest[:]) 148 | if err != nil { 149 | return "", err 150 | } 151 | pem.Encode(&buf, &pem.Block{ 152 | Type: "SIGNATURE", 153 | Bytes: signature, 154 | }) 155 | 156 | // Sign extrainfo 157 | signature, err = d.SigningKey.PrivateEncrypt(digest[:]) 158 | if err != nil { 159 | return "", err 160 | } 161 | pem.Encode(&extra, &pem.Block{ 162 | Type: "SIGNATURE", 163 | Bytes: signature, 164 | }) 165 | 166 | return buf.String() + extra.String(), nil 167 | } 168 | 169 | func (d *Descriptor) Publish(address string) error { 170 | where := fmt.Sprintf("http://%s/tor/", address) 171 | 172 | desc, err := d.SignedDescriptor() 173 | if err != nil { 174 | return err 175 | } 176 | resp, err := http.Post(where, "tor/descriptor", strings.NewReader(desc)) 177 | if err != nil { 178 | return err 179 | } 180 | defer resp.Body.Close() 181 | 182 | //body, err := ioutil.ReadAll(resp.Body) 183 | //if err != nil { 184 | // return err 185 | //} 186 | log.Println(resp) 187 | 188 | return nil 189 | } 190 | -------------------------------------------------------------------------------- /tordir/descriptor_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tordir 6 | 7 | import ( 8 | "crypto/rand" 9 | "github.com/tvdw/openssl" 10 | "golang.org/x/crypto/curve25519" 11 | "log" 12 | "net" 13 | "testing" 14 | "time" 15 | ) 16 | 17 | func TestBasic(t *testing.T) { 18 | var priv, pub [32]byte 19 | rand.Read(priv[:]) 20 | curve25519.ScalarBaseMult(&pub, &priv) 21 | 22 | var d Descriptor 23 | d.Nickname = "mylittletorry18" 24 | d.Contact = "TvdW" 25 | d.Platform = "Tor 0.2.6.2-alpha on MS-DOS" 26 | d.Address = net.ParseIP("80.57.124.58") 27 | d.ORPort = 1234 28 | d.UptimeStart = time.Now() 29 | d.NTORKey = pub[:] 30 | d.BandwidthAvg = 1000000 31 | d.BandwidthBurst = 1200000 32 | d.BandwidthObserved = 30107 33 | k, err := openssl.GenerateRSAKeyWithExponent(1024, 65537) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | d.OnionKey, err = openssl.GenerateRSAKeyWithExponent(1024, 65537) 38 | d.SigningKey = k 39 | desc, err := d.SignedDescriptor() 40 | if err != nil { 41 | t.Error(err) 42 | } 43 | 44 | log.Println(desc) 45 | } 46 | -------------------------------------------------------------------------------- /window.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The GoTor Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "sync" 9 | ) 10 | 11 | type Window struct { 12 | cond *sync.Cond 13 | window int 14 | } 15 | 16 | func NewWindow(window int) *Window { 17 | return &Window{ 18 | cond: sync.NewCond(&sync.Mutex{}), 19 | window: window, 20 | } 21 | } 22 | 23 | func (w *Window) Abort() { 24 | w.cond.Broadcast() 25 | } 26 | 27 | func (w *Window) Refill(count int) { 28 | w.cond.L.Lock() 29 | w.window += count 30 | w.cond.Broadcast() 31 | w.cond.L.Unlock() 32 | } 33 | 34 | func (w *Window) Take() bool { 35 | w.cond.L.Lock() 36 | if w.window <= 0 { 37 | w.cond.Wait() 38 | } 39 | st := false 40 | if w.window > 0 { 41 | st = true 42 | w.window-- 43 | } 44 | w.cond.L.Unlock() 45 | return st 46 | } 47 | 48 | func (w *Window) TryTake() bool { 49 | w.cond.L.Lock() 50 | if w.window > 0 { 51 | w.window-- 52 | w.cond.L.Unlock() 53 | return true 54 | } 55 | w.cond.L.Unlock() 56 | return false 57 | } 58 | 59 | func (w *Window) GetLevel() int { 60 | w.cond.L.Lock() 61 | l := w.window 62 | w.cond.L.Unlock() 63 | return l 64 | } 65 | --------------------------------------------------------------------------------