]> Cypherpunks.ru repositories - govpn.git/blob - handshake.go
[DOC] Point to git-repository URL directly, instead of github project's page
[govpn.git] / handshake.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package govpn
20
21 import (
22         "crypto/rand"
23         "crypto/subtle"
24         "encoding/binary"
25         "log"
26         "net"
27         "path"
28         "time"
29
30         "golang.org/x/crypto/curve25519"
31         "golang.org/x/crypto/poly1305"
32         "golang.org/x/crypto/salsa20"
33         "golang.org/x/crypto/salsa20/salsa"
34         "golang.org/x/crypto/xtea"
35 )
36
37 type Handshake struct {
38         addr     *net.UDPAddr
39         LastPing time.Time
40         Id       PeerId
41         rNonce   *[8]byte
42         dhPriv   *[32]byte      // own private DH key
43         key      *[KeySize]byte // handshake encryption key
44         rServer  *[8]byte       // random string for authentication
45         rClient  *[8]byte
46         sServer  *[32]byte // secret string for main key calculation
47         sClient  *[32]byte
48 }
49
50 func keyFromSecrets(server, client []byte) *[KeySize]byte {
51         k := new([32]byte)
52         for i := 0; i < 32; i++ {
53                 k[i] = server[i] ^ client[i]
54         }
55         return k
56 }
57
58 // Check if it is valid handshake-related message.
59 // Minimal size and last 16 zero bytes.
60 func IsValidHandshakePkt(pkt []byte) bool {
61         if len(pkt) < 24 {
62                 return false
63         }
64         for i := len(pkt) - poly1305.TagSize; i < len(pkt); i++ {
65                 if pkt[i] != '\x00' {
66                         return false
67                 }
68         }
69         return true
70 }
71
72 // Zero handshake's memory state
73 func (h *Handshake) Zero() {
74         sliceZero(h.rNonce[:])
75         sliceZero(h.dhPriv[:])
76         sliceZero(h.key[:])
77         if h.rServer != nil {
78                 sliceZero(h.rServer[:])
79         }
80         if h.rClient != nil {
81                 sliceZero(h.rClient[:])
82         }
83         if h.sServer != nil {
84                 sliceZero(h.sServer[:])
85         }
86         if h.sClient != nil {
87                 sliceZero(h.sClient[:])
88         }
89 }
90
91 func (h *Handshake) rNonceNext() []byte {
92         nonce := make([]byte, 8)
93         nonceCurrent, _ := binary.Uvarint(h.rNonce[:])
94         binary.PutUvarint(nonce, nonceCurrent+1)
95         return nonce
96 }
97
98 func dhPrivGen() *[32]byte {
99         dh := new([32]byte)
100         if _, err := rand.Read(dh[:]); err != nil {
101                 panic("Can not read random for DH private key")
102         }
103         return dh
104 }
105
106 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
107         key := new([32]byte)
108         curve25519.ScalarMult(key, priv, pub)
109         salsa.HSalsa20(key, new([16]byte), key, &salsa.Sigma)
110         return key
111 }
112
113 // Create new handshake state.
114 func HandshakeNew(addr *net.UDPAddr) *Handshake {
115         state := Handshake{
116                 addr:     addr,
117                 LastPing: time.Now(),
118         }
119         return &state
120 }
121
122 // Start handshake's procedure from the client.
123 // It is the entry point for starting the handshake procedure.
124 // You have to specify outgoing conn address, remote's addr address,
125 // our own identification and an encryption key. First handshake packet
126 // will be sent immediately.
127 func HandshakeStart(conn *net.UDPConn, addr *net.UDPAddr, id *PeerId, key *[32]byte) *Handshake {
128         state := HandshakeNew(addr)
129
130         state.dhPriv = dhPrivGen()
131         dhPub := new([32]byte)
132         curve25519.ScalarBaseMult(dhPub, state.dhPriv)
133
134         state.rNonce = new([8]byte)
135         if _, err := rand.Read(state.rNonce[:]); err != nil {
136                 panic("Can not read random for handshake nonce")
137         }
138         enc := make([]byte, 32)
139         salsa20.XORKeyStream(enc, dhPub[:], state.rNonce[:], key)
140
141         ciph, err := xtea.NewCipher(id[:])
142         if err != nil {
143                 panic(err)
144         }
145         rEnc := make([]byte, xtea.BlockSize)
146         ciph.Encrypt(rEnc, state.rNonce[:])
147
148         data := append(state.rNonce[:], enc...)
149         data = append(data, rEnc...)
150         data = append(data, '\x00')
151         data = append(data, make([]byte, poly1305.TagSize)...)
152
153         if _, err := conn.WriteTo(data, addr); err != nil {
154                 panic(err)
155         }
156         return state
157 }
158
159 // Process handshake message on the server side.
160 // This function is intended to be called on server's side.
161 // Our outgoing conn connection and received data are required.
162 // If this is the final handshake message, then new Peer object
163 // will be created and used as a transport. If no mutually
164 // authenticated Peer is ready, then return nil.
165 func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
166         switch len(data) {
167         case 65: // R + ENC(PSK, dh_client_pub) + xtea(ID, R) + NULL + NULLs
168                 if h.rNonce != nil {
169                         log.Println("Invalid handshake stage from", h.addr)
170                         return nil
171                 }
172
173                 // Try to determine client's ID
174                 id := IDsCache.Find(data[:8], data[8+32:8+32+8])
175                 if id == nil {
176                         log.Println("Unknown identity from", h.addr)
177                         return nil
178                 }
179                 key := KeyRead(path.Join(PeersPath, id.String(), "key"))
180                 h.Id = *id
181
182                 // Generate private DH key
183                 h.dhPriv = dhPrivGen()
184                 dhPub := new([32]byte)
185                 curve25519.ScalarBaseMult(dhPub, h.dhPriv)
186
187                 // Decrypt remote public key and compute shared key
188                 dec := new([32]byte)
189                 salsa20.XORKeyStream(dec[:], data[8:8+32], data[:8], key)
190                 h.key = dhKeyGen(h.dhPriv, dec)
191
192                 // Compute nonce and encrypt our public key
193                 h.rNonce = new([8]byte)
194                 copy(h.rNonce[:], data[:8])
195
196                 encPub := make([]byte, 32)
197                 salsa20.XORKeyStream(encPub, dhPub[:], h.rNonceNext(), key)
198
199                 // Generate R* and encrypt them
200                 h.rServer = new([8]byte)
201                 if _, err := rand.Read(h.rServer[:]); err != nil {
202                         panic("Can not read random for handshake random key")
203                 }
204                 h.sServer = new([32]byte)
205                 if _, err := rand.Read(h.sServer[:]); err != nil {
206                         panic("Can not read random for handshake shared key")
207                 }
208                 encRs := make([]byte, 8+32)
209                 salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
210
211                 // Send that to client
212                 if _, err := conn.WriteTo(
213                         append(encPub,
214                                 append(encRs, make([]byte, poly1305.TagSize)...)...), h.addr); err != nil {
215                         panic(err)
216                 }
217                 h.LastPing = time.Now()
218         case 64: // ENC(K, RS + RC + SC) + NULLs
219                 if (h.rNonce == nil) || (h.rClient != nil) {
220                         log.Println("Invalid handshake stage from", h.addr)
221                         return nil
222                 }
223
224                 // Decrypted Rs compare rServer
225                 decRs := make([]byte, 8+8+32)
226                 salsa20.XORKeyStream(decRs, data[:8+8+32], h.rNonceNext(), h.key)
227                 if subtle.ConstantTimeCompare(decRs[:8], h.rServer[:]) != 1 {
228                         log.Println("Invalid server's random number with", h.addr)
229                         return nil
230                 }
231
232                 // Send final answer to client
233                 enc := make([]byte, 8)
234                 salsa20.XORKeyStream(enc, decRs[8:8+8], make([]byte, 8), h.key)
235                 if _, err := conn.WriteTo(append(enc, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
236                         panic(err)
237                 }
238
239                 // Switch peer
240                 peer := newPeer(h.addr, h.Id, 0, keyFromSecrets(h.sServer[:], decRs[8+8:]))
241                 h.LastPing = time.Now()
242                 return peer
243         default:
244                 log.Println("Invalid handshake message from", h.addr)
245         }
246         return nil
247 }
248
249 // Process handshake message on the client side.
250 // This function is intended to be called on client's side.
251 // Our outgoing conn connection, authentication key and received data
252 // are required. Client does not work with identities, as he is the
253 // only one, so key is a requirement.
254 // If this is the final handshake message, then new Peer object
255 // will be created and used as a transport. If no mutually
256 // authenticated Peer is ready, then return nil.
257 func (h *Handshake) Client(conn *net.UDPConn, key *[KeySize]byte, data []byte) *Peer {
258         switch len(data) {
259         case 88: // ENC(PSK, dh_server_pub) + ENC(K, RS + SS) + NULLs
260                 if h.key != nil {
261                         log.Println("Invalid handshake stage from", h.addr)
262                         return nil
263                 }
264
265                 // Decrypt remote public key and compute shared key
266                 dec := new([32]byte)
267                 salsa20.XORKeyStream(dec[:], data[:32], h.rNonceNext(), key)
268                 h.key = dhKeyGen(h.dhPriv, dec)
269
270                 // Decrypt Rs
271                 decRs := make([]byte, 8+32)
272                 salsa20.XORKeyStream(decRs, data[32:32+8+32], h.rNonce[:], h.key)
273                 h.rServer = new([8]byte)
274                 copy(h.rServer[:], decRs[:8])
275                 h.sServer = new([32]byte)
276                 copy(h.sServer[:], decRs[8:])
277
278                 // Generate R* and encrypt them
279                 h.rClient = new([8]byte)
280                 if _, err := rand.Read(h.rClient[:]); err != nil {
281                         panic("Can not read random for handshake random key")
282                 }
283                 h.sClient = new([32]byte)
284                 if _, err := rand.Read(h.sClient[:]); err != nil {
285                         panic("Can not read random for handshake shared key")
286                 }
287                 encRs := make([]byte, 8+8+32)
288                 salsa20.XORKeyStream(encRs,
289                         append(h.rServer[:],
290                                 append(h.rClient[:], h.sClient[:]...)...), h.rNonceNext(), h.key)
291
292                 // Send that to server
293                 if _, err := conn.WriteTo(append(encRs, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
294                         panic(err)
295                 }
296                 h.LastPing = time.Now()
297         case 24: // ENC(K, RC) + NULLs
298                 if h.key == nil {
299                         log.Println("Invalid handshake stage from", h.addr)
300                         return nil
301                 }
302
303                 // Decrypt rClient
304                 dec := make([]byte, 8)
305                 salsa20.XORKeyStream(dec, data[:8], make([]byte, 8), h.key)
306                 if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 {
307                         log.Println("Invalid client's random number with", h.addr)
308                         return nil
309                 }
310
311                 // Switch peer
312                 peer := newPeer(h.addr, h.Id, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
313                 h.LastPing = time.Now()
314                 return peer
315         default:
316                 log.Println("Invalid handshake message from", h.addr)
317         }
318         return nil
319 }