]> Cypherpunks.ru repositories - govpn.git/blob - handshake.go
Merge branch 'develop'
[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/salsa20"
32         "golang.org/x/crypto/salsa20/salsa"
33         "golang.org/x/crypto/xtea"
34 )
35
36 type Handshake struct {
37         addr     *net.UDPAddr
38         LastPing time.Time
39         Id       PeerId
40         rNonce   *[8]byte
41         dhPriv   *[32]byte      // own private DH key
42         key      *[KeySize]byte // handshake encryption key
43         rServer  *[8]byte       // random string for authentication
44         rClient  *[8]byte
45         sServer  *[32]byte // secret string for main key calculation
46         sClient  *[32]byte
47 }
48
49 func keyFromSecrets(server, client []byte) *[KeySize]byte {
50         k := new([32]byte)
51         for i := 0; i < 32; i++ {
52                 k[i] = server[i] ^ client[i]
53         }
54         return k
55 }
56
57 // Zero handshake's memory state
58 func (h *Handshake) Zero() {
59         if h.rNonce != nil {
60                 sliceZero(h.rNonce[:])
61         }
62         if h.dhPriv != nil {
63                 sliceZero(h.dhPriv[:])
64         }
65         if h.key != nil {
66                 sliceZero(h.key[:])
67         }
68         if h.rServer != nil {
69                 sliceZero(h.rServer[:])
70         }
71         if h.rClient != nil {
72                 sliceZero(h.rClient[:])
73         }
74         if h.sServer != nil {
75                 sliceZero(h.sServer[:])
76         }
77         if h.sClient != nil {
78                 sliceZero(h.sClient[:])
79         }
80 }
81
82 func (h *Handshake) rNonceNext() []byte {
83         nonce := make([]byte, 8)
84         nonceCurrent, _ := binary.Uvarint(h.rNonce[:])
85         binary.PutUvarint(nonce, nonceCurrent+1)
86         return nonce
87 }
88
89 func dhPrivGen() *[32]byte {
90         dh := new([32]byte)
91         if _, err := rand.Read(dh[:]); err != nil {
92                 panic("Can not read random for DH private key")
93         }
94         return dh
95 }
96
97 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
98         key := new([32]byte)
99         curve25519.ScalarMult(key, priv, pub)
100         salsa.HSalsa20(key, new([16]byte), key, &salsa.Sigma)
101         return key
102 }
103
104 // Create new handshake state.
105 func HandshakeNew(addr *net.UDPAddr) *Handshake {
106         state := Handshake{
107                 addr:     addr,
108                 LastPing: time.Now(),
109         }
110         return &state
111 }
112
113 // Generate ID tag from client identification and data.
114 func idTag(id *PeerId, data []byte) []byte {
115         ciph, err := xtea.NewCipher(id[:])
116         if err != nil {
117                 panic(err)
118         }
119         enc := make([]byte, xtea.BlockSize)
120         ciph.Encrypt(enc, data[:xtea.BlockSize])
121         return enc
122 }
123
124 // Start handshake's procedure from the client.
125 // It is the entry point for starting the handshake procedure.
126 // You have to specify outgoing conn address, remote's addr address,
127 // our own identification and an encryption key. First handshake packet
128 // will be sent immediately.
129 func HandshakeStart(conn *net.UDPConn, addr *net.UDPAddr, id *PeerId, key *[32]byte) *Handshake {
130         state := HandshakeNew(addr)
131
132         state.dhPriv = dhPrivGen()
133         dhPub := new([32]byte)
134         curve25519.ScalarBaseMult(dhPub, state.dhPriv)
135
136         state.rNonce = new([8]byte)
137         if _, err := rand.Read(state.rNonce[:]); err != nil {
138                 panic("Can not read random for handshake nonce")
139         }
140         enc := make([]byte, 32)
141         salsa20.XORKeyStream(enc, dhPub[:], state.rNonce[:], key)
142         data := append(state.rNonce[:], enc...)
143         data = append(data, idTag(id, state.rNonce[:])...)
144         if _, err := conn.WriteTo(data, addr); err != nil {
145                 panic(err)
146         }
147         return state
148 }
149
150 // Process handshake message on the server side.
151 // This function is intended to be called on server's side.
152 // Client identity, our outgoing conn connection and
153 // received data are required.
154 // If this is the final handshake message, then new Peer object
155 // will be created and used as a transport. If no mutually
156 // authenticated Peer is ready, then return nil.
157 func (h *Handshake) Server(id *PeerId, conn *net.UDPConn, data []byte) *Peer {
158         // R + ENC(PSK, dh_client_pub) + IDtag
159         if len(data) == 48 && h.rNonce == nil {
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, append(encRs, idTag(id, encPub)...)...), h.addr); err != nil {
195                         panic(err)
196                 }
197                 h.LastPing = time.Now()
198         } else
199         // ENC(K, RS + RC + SC) + IDtag
200         if len(data) == 56 && h.rClient == nil {
201                 // Decrypted Rs compare rServer
202                 decRs := make([]byte, 8+8+32)
203                 salsa20.XORKeyStream(decRs, data[:8+8+32], h.rNonceNext(), h.key)
204                 if subtle.ConstantTimeCompare(decRs[:8], h.rServer[:]) != 1 {
205                         log.Println("Invalid server's random number with", h.addr)
206                         return nil
207                 }
208
209                 // Send final answer to client
210                 enc := make([]byte, 8)
211                 salsa20.XORKeyStream(enc, decRs[8:8+8], make([]byte, 8), h.key)
212                 if _, err := conn.WriteTo(append(enc, idTag(id, enc)...), h.addr); err != nil {
213                         panic(err)
214                 }
215
216                 // Switch peer
217                 peer := newPeer(h.addr, h.Id, 0, keyFromSecrets(h.sServer[:], decRs[8+8:]))
218                 h.LastPing = time.Now()
219                 return peer
220         } else {
221                 log.Println("Invalid handshake message from", h.addr)
222         }
223         return nil
224 }
225
226 // Process handshake message on the client side.
227 // This function is intended to be called on client's side.
228 // Our outgoing conn connection, authentication
229 // key and received data are required.
230 // If this is the final handshake message, then new Peer object
231 // will be created and used as a transport. If no mutually
232 // authenticated Peer is ready, then return nil.
233 func (h *Handshake) Client(id *PeerId, conn *net.UDPConn, key *[KeySize]byte, data []byte) *Peer {
234         switch len(data) {
235         case 80: // ENC(PSK, dh_server_pub) + ENC(K, RS + SS) + IDtag
236                 if h.key != nil {
237                         log.Println("Invalid handshake stage from", h.addr)
238                         return nil
239                 }
240
241                 // Decrypt remote public key and compute shared key
242                 dec := new([32]byte)
243                 salsa20.XORKeyStream(dec[:], data[:32], h.rNonceNext(), key)
244                 h.key = dhKeyGen(h.dhPriv, dec)
245
246                 // Decrypt Rs
247                 decRs := make([]byte, 8+32)
248                 salsa20.XORKeyStream(decRs, data[32:32+8+32], h.rNonce[:], h.key)
249                 h.rServer = new([8]byte)
250                 copy(h.rServer[:], decRs[:8])
251                 h.sServer = new([32]byte)
252                 copy(h.sServer[:], decRs[8:])
253
254                 // Generate R* and encrypt them
255                 h.rClient = new([8]byte)
256                 if _, err := rand.Read(h.rClient[:]); err != nil {
257                         panic("Can not read random for handshake random key")
258                 }
259                 h.sClient = new([32]byte)
260                 if _, err := rand.Read(h.sClient[:]); err != nil {
261                         panic("Can not read random for handshake shared key")
262                 }
263                 encRs := make([]byte, 8+8+32)
264                 salsa20.XORKeyStream(encRs,
265                         append(h.rServer[:],
266                                 append(h.rClient[:], h.sClient[:]...)...), h.rNonceNext(), h.key)
267
268                 // Send that to server
269                 if _, err := conn.WriteTo(append(encRs, idTag(id, encRs)...), h.addr); err != nil {
270                         panic(err)
271                 }
272                 h.LastPing = time.Now()
273         case 16: // ENC(K, RC) + IDtag
274                 if h.key == nil {
275                         log.Println("Invalid handshake stage from", h.addr)
276                         return nil
277                 }
278
279                 // Decrypt rClient
280                 dec := make([]byte, 8)
281                 salsa20.XORKeyStream(dec, data[:8], make([]byte, 8), h.key)
282                 if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 {
283                         log.Println("Invalid client's random number with", h.addr)
284                         return nil
285                 }
286
287                 // Switch peer
288                 peer := newPeer(h.addr, h.Id, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
289                 h.LastPing = time.Now()
290                 return peer
291         default:
292                 log.Println("Invalid handshake message from", h.addr)
293         }
294         return nil
295 }