]> Cypherpunks.ru repositories - govpn.git/blob - handshake.go
Texinfo documentation, client ID, simultaneous clients
[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 func (h *Handshake) rNonceNext() []byte {
73         nonce := make([]byte, 8)
74         nonceCurrent, _ := binary.Uvarint(h.rNonce[:])
75         binary.PutUvarint(nonce, nonceCurrent+1)
76         return nonce
77 }
78
79 func dhPrivGen() *[32]byte {
80         dh := new([32]byte)
81         if _, err := rand.Read(dh[:]); err != nil {
82                 panic("Can not read random for DH private key")
83         }
84         return dh
85 }
86
87 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
88         key := new([32]byte)
89         curve25519.ScalarMult(key, priv, pub)
90         salsa.HSalsa20(key, new([16]byte), key, &salsa.Sigma)
91         return key
92 }
93
94 // Create new handshake state.
95 func HandshakeNew(addr *net.UDPAddr) *Handshake {
96         state := Handshake{
97                 addr:     addr,
98                 LastPing: time.Now(),
99         }
100         return &state
101 }
102
103 // Start handshake's procedure from the client.
104 // It is the entry point for starting the handshake procedure.
105 // You have to specify outgoing conn address, remote's addr address,
106 // our own identification and an encryption key. First handshake packet
107 // will be sent immediately.
108 func HandshakeStart(conn *net.UDPConn, addr *net.UDPAddr, id *PeerId, key *[32]byte) *Handshake {
109         state := HandshakeNew(addr)
110
111         state.dhPriv = dhPrivGen()
112         dhPub := new([32]byte)
113         curve25519.ScalarBaseMult(dhPub, state.dhPriv)
114
115         state.rNonce = new([8]byte)
116         if _, err := rand.Read(state.rNonce[:]); err != nil {
117                 panic("Can not read random for handshake nonce")
118         }
119         enc := make([]byte, 32)
120         salsa20.XORKeyStream(enc, dhPub[:], state.rNonce[:], key)
121
122         ciph, err := xtea.NewCipher(id[:])
123         if err != nil {
124                 panic(err)
125         }
126         rEnc := make([]byte, xtea.BlockSize)
127         ciph.Encrypt(rEnc, state.rNonce[:])
128
129         data := append(state.rNonce[:], enc...)
130         data = append(data, rEnc...)
131         data = append(data, '\x00')
132         data = append(data, make([]byte, poly1305.TagSize)...)
133
134         if _, err := conn.WriteTo(data, addr); err != nil {
135                 panic(err)
136         }
137         return state
138 }
139
140 // Process handshake message on the server side.
141 // This function is intended to be called on server's side.
142 // Our outgoing conn connection and received data are required.
143 // If this is the final handshake message, then new Peer object
144 // will be created and used as a transport. If no mutually
145 // authenticated Peer is ready, then return nil.
146 func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
147         switch len(data) {
148         case 65: // R + ENC(PSK, dh_client_pub) + xtea(ID, R) + NULL + NULLs
149                 if h.rNonce != nil {
150                         log.Println("Invalid handshake stage from", h.addr)
151                         return nil
152                 }
153
154                 // Try to determine client's ID
155                 id := IDsCache.Find(data[:8], data[8+32:8+32+8])
156                 if id == nil {
157                         log.Println("Unknown identity from", h.addr)
158                         return nil
159                 }
160                 key := KeyRead(path.Join(PeersPath, id.String(), "key"))
161                 h.Id = *id
162
163                 // Generate private DH key
164                 h.dhPriv = dhPrivGen()
165                 dhPub := new([32]byte)
166                 curve25519.ScalarBaseMult(dhPub, h.dhPriv)
167
168                 // Decrypt remote public key and compute shared key
169                 dec := new([32]byte)
170                 salsa20.XORKeyStream(dec[:], data[8:8+32], data[:8], key)
171                 h.key = dhKeyGen(h.dhPriv, dec)
172
173                 // Compute nonce and encrypt our public key
174                 h.rNonce = new([8]byte)
175                 copy(h.rNonce[:], data[:8])
176
177                 encPub := make([]byte, 32)
178                 salsa20.XORKeyStream(encPub, dhPub[:], h.rNonceNext(), key)
179
180                 // Generate R* and encrypt them
181                 h.rServer = new([8]byte)
182                 if _, err := rand.Read(h.rServer[:]); err != nil {
183                         panic("Can not read random for handshake random key")
184                 }
185                 h.sServer = new([32]byte)
186                 if _, err := rand.Read(h.sServer[:]); err != nil {
187                         panic("Can not read random for handshake shared key")
188                 }
189                 encRs := make([]byte, 8+32)
190                 salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
191
192                 // Send that to client
193                 if _, err := conn.WriteTo(
194                         append(encPub,
195                                 append(encRs, make([]byte, poly1305.TagSize)...)...), h.addr); err != nil {
196                         panic(err)
197                 }
198                 h.LastPing = time.Now()
199         case 64: // ENC(K, RS + RC + SC) + NULLs
200                 if (h.rNonce == nil) || (h.rClient != nil) {
201                         log.Println("Invalid handshake stage from", h.addr)
202                         return nil
203                 }
204
205                 // Decrypted Rs compare rServer
206                 decRs := make([]byte, 8+8+32)
207                 salsa20.XORKeyStream(decRs, data[:8+8+32], h.rNonceNext(), h.key)
208                 if subtle.ConstantTimeCompare(decRs[:8], h.rServer[:]) != 1 {
209                         log.Println("Invalid server's random number with", h.addr)
210                         return nil
211                 }
212
213                 // Send final answer to client
214                 enc := make([]byte, 8)
215                 salsa20.XORKeyStream(enc, decRs[8:8+8], make([]byte, 8), h.key)
216                 if _, err := conn.WriteTo(append(enc, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
217                         panic(err)
218                 }
219
220                 // Switch peer
221                 peer := newPeer(h.addr, h.Id, 0, keyFromSecrets(h.sServer[:], decRs[8+8:]))
222                 h.LastPing = time.Now()
223                 return peer
224         default:
225                 log.Println("Invalid handshake message from", h.addr)
226         }
227         return nil
228 }
229
230 // Process handshake message on the client side.
231 // This function is intended to be called on client's side.
232 // Our outgoing conn connection, authentication key and received data
233 // are required. Client does not work with identities, as he is the
234 // only one, so key is a requirement.
235 // If this is the final handshake message, then new Peer object
236 // will be created and used as a transport. If no mutually
237 // authenticated Peer is ready, then return nil.
238 func (h *Handshake) Client(conn *net.UDPConn, key *[KeySize]byte, data []byte) *Peer {
239         switch len(data) {
240         case 88: // ENC(PSK, dh_server_pub) + ENC(K, RS + SS) + NULLs
241                 if h.key != nil {
242                         log.Println("Invalid handshake stage from", h.addr)
243                         return nil
244                 }
245
246                 // Decrypt remote public key and compute shared key
247                 dec := new([32]byte)
248                 salsa20.XORKeyStream(dec[:], data[:32], h.rNonceNext(), key)
249                 h.key = dhKeyGen(h.dhPriv, dec)
250
251                 // Decrypt Rs
252                 decRs := make([]byte, 8+32)
253                 salsa20.XORKeyStream(decRs, data[32:32+8+32], h.rNonce[:], h.key)
254                 h.rServer = new([8]byte)
255                 copy(h.rServer[:], decRs[:8])
256                 h.sServer = new([32]byte)
257                 copy(h.sServer[:], decRs[8:])
258
259                 // Generate R* and encrypt them
260                 h.rClient = new([8]byte)
261                 if _, err := rand.Read(h.rClient[:]); err != nil {
262                         panic("Can not read random for handshake random key")
263                 }
264                 h.sClient = new([32]byte)
265                 if _, err := rand.Read(h.sClient[:]); err != nil {
266                         panic("Can not read random for handshake shared key")
267                 }
268                 encRs := make([]byte, 8+8+32)
269                 salsa20.XORKeyStream(encRs,
270                         append(h.rServer[:],
271                                 append(h.rClient[:], h.sClient[:]...)...), h.rNonceNext(), h.key)
272
273                 // Send that to server
274                 if _, err := conn.WriteTo(append(encRs, make([]byte, poly1305.TagSize)...), h.addr); err != nil {
275                         panic(err)
276                 }
277                 h.LastPing = time.Now()
278         case 24: // ENC(K, RC) + NULLs
279                 if h.key == nil {
280                         log.Println("Invalid handshake stage from", h.addr)
281                         return nil
282                 }
283
284                 // Decrypt rClient
285                 dec := make([]byte, 8)
286                 salsa20.XORKeyStream(dec, data[:8], make([]byte, 8), h.key)
287                 if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 {
288                         log.Println("Invalid client's random number with", h.addr)
289                         return nil
290                 }
291
292                 // Switch peer
293                 peer := newPeer(h.addr, h.Id, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
294                 h.LastPing = time.Now()
295                 return peer
296         default:
297                 log.Println("Invalid handshake message from", h.addr)
298         }
299         return nil
300 }