]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/handshake.go
GnuPG without the
[govpn.git] / src / cypherpunks.ru / govpn / handshake.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2019 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, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package govpn
19
20 import (
21         "crypto/subtle"
22         "encoding/binary"
23         "io"
24         "log"
25         "time"
26
27         "chacha20"
28         "github.com/agl/ed25519"
29         "github.com/agl/ed25519/extra25519"
30         "golang.org/x/crypto/blake2b"
31         "golang.org/x/crypto/curve25519"
32 )
33
34 const (
35         RSize = 8
36         SSize = 32
37 )
38
39 type Handshake struct {
40         addr     string
41         conn     io.Writer
42         LastPing time.Time
43         Conf     *PeerConf
44         dsaPubH  *[ed25519.PublicKeySize]byte
45         key      *[32]byte
46         rNonce   *[16]byte
47         dhPriv   *[32]byte    // own private DH key
48         rServer  *[RSize]byte // random string for authentication
49         rClient  *[RSize]byte
50         sServer  *[SSize]byte // secret string for main key calculation
51         sClient  *[SSize]byte
52 }
53
54 func keyFromSecrets(server, client []byte) *[SSize]byte {
55         k := new([SSize]byte)
56         for i := 0; i < SSize; i++ {
57                 k[i] = server[i] ^ client[i]
58         }
59         return k
60 }
61
62 // Zero handshake's memory state
63 func (h *Handshake) Zero() {
64         if h.rNonce != nil {
65                 SliceZero(h.rNonce[:])
66         }
67         if h.dhPriv != nil {
68                 SliceZero(h.dhPriv[:])
69         }
70         if h.key != nil {
71                 SliceZero(h.key[:])
72         }
73         if h.dsaPubH != nil {
74                 SliceZero(h.dsaPubH[:])
75         }
76         if h.rServer != nil {
77                 SliceZero(h.rServer[:])
78         }
79         if h.rClient != nil {
80                 SliceZero(h.rClient[:])
81         }
82         if h.sServer != nil {
83                 SliceZero(h.sServer[:])
84         }
85         if h.sClient != nil {
86                 SliceZero(h.sClient[:])
87         }
88 }
89
90 func (h *Handshake) rNonceNext(count uint64) *[16]byte {
91         nonce := new([16]byte)
92         nonceCurrent, _ := binary.Uvarint(h.rNonce[8:])
93         binary.PutUvarint(nonce[8:], nonceCurrent+count)
94         return nonce
95 }
96
97 func dhKeypairGen() (*[32]byte, *[32]byte) {
98         priv := new([32]byte)
99         pub := new([32]byte)
100         repr := new([32]byte)
101         reprFound := false
102         for !reprFound {
103                 if _, err := io.ReadFull(Rand, priv[:]); err != nil {
104                         log.Fatalln("Error reading random for DH private key:", err)
105                 }
106                 reprFound = extra25519.ScalarBaseMult(pub, repr, priv)
107         }
108         return priv, repr
109 }
110
111 func dhKeyGen(priv, pub *[32]byte) *[32]byte {
112         key := new([32]byte)
113         curve25519.ScalarMult(key, priv, pub)
114         hashed := blake2b.Sum256(key[:])
115         return &hashed
116 }
117
118 // Create new handshake state.
119 func NewHandshake(addr string, conn io.Writer, conf *PeerConf) *Handshake {
120         state := Handshake{
121                 addr:     addr,
122                 conn:     conn,
123                 LastPing: time.Now(),
124                 Conf:     conf,
125         }
126         state.dsaPubH = new([ed25519.PublicKeySize]byte)
127         copy(state.dsaPubH[:], state.Conf.Verifier.Pub[:])
128         hashed := blake2b.Sum256(state.dsaPubH[:])
129         state.dsaPubH = &hashed
130         return &state
131 }
132
133 // Generate ID tag from client identification and data.
134 func idTag(id *PeerID, timeSync int, data []byte) []byte {
135         enc := make([]byte, 8)
136         copy(enc, data)
137         AddTimeSync(timeSync, enc)
138         mac, err := blake2b.New256(id[:])
139         if err != nil {
140                 panic(err)
141         }
142         mac.Write(enc)
143         sum := mac.Sum(nil)
144         return sum[len(sum)-8:]
145 }
146
147 // Start handshake's procedure from the client. It is the entry point
148 // for starting the handshake procedure.
149 // First handshake packet will be sent immediately.
150 func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake {
151         state := NewHandshake(addr, conn, conf)
152         var dhPubRepr *[32]byte
153         state.dhPriv, dhPubRepr = dhKeypairGen()
154
155         state.rNonce = new([16]byte)
156         if _, err := io.ReadFull(Rand, state.rNonce[8:]); err != nil {
157                 log.Fatalln("Error reading random for nonce:", err)
158         }
159         var enc []byte
160         if conf.Noise {
161                 enc = make([]byte, conf.MTU-8-RSize)
162         } else {
163                 enc = make([]byte, 32)
164         }
165         copy(enc, dhPubRepr[:])
166         if conf.Encless {
167                 var err error
168                 enc, err = EnclessEncode(state.dsaPubH, state.rNonce, enc)
169                 if err != err {
170                         panic(err)
171                 }
172         } else {
173                 chacha20.XORKeyStream(enc, enc, state.rNonce, state.dsaPubH)
174         }
175         data := append(state.rNonce[8:], enc...)
176         data = append(data, idTag(state.Conf.ID, state.Conf.TimeSync, state.rNonce[8:])...)
177         state.conn.Write(data)
178         return state
179 }
180
181 // Process handshake message on the server side.
182 // This function is intended to be called on server's side.
183 // If this is the final handshake message, then new Peer object
184 // will be created and used as a transport. If no mutually
185 // authenticated Peer is ready, then return nil.
186 func (h *Handshake) Server(data []byte) *Peer {
187         // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag
188         if h.rNonce == nil && ((!h.Conf.Encless && len(data) >= 48) ||
189                 (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) {
190                 h.rNonce = new([16]byte)
191                 copy(h.rNonce[8:], data[:RSize])
192
193                 // Decrypt remote public key
194                 cDHRepr := new([32]byte)
195                 if h.Conf.Encless {
196                         out, err := EnclessDecode(
197                                 h.dsaPubH,
198                                 h.rNonce,
199                                 data[RSize:len(data)-8],
200                         )
201                         if err != nil {
202                                 log.Println("Unable to decode packet from", h.addr, err)
203                                 return nil
204                         }
205                         copy(cDHRepr[:], out)
206                 } else {
207                         chacha20.XORKeyStream(cDHRepr[:], data[RSize:RSize+32], h.rNonce, h.dsaPubH)
208                 }
209
210                 // Generate DH keypair
211                 var dhPubRepr *[32]byte
212                 h.dhPriv, dhPubRepr = dhKeypairGen()
213
214                 // Compute shared key
215                 cDH := new([32]byte)
216                 extra25519.RepresentativeToPublicKey(cDH, cDHRepr)
217                 h.key = dhKeyGen(h.dhPriv, cDH)
218
219                 var encPub []byte
220                 var err error
221                 if h.Conf.Encless {
222                         encPub = make([]byte, h.Conf.MTU)
223                         copy(encPub, dhPubRepr[:])
224                         encPub, err = EnclessEncode(h.dsaPubH, h.rNonceNext(1), encPub)
225                         if err != nil {
226                                 panic(err)
227                         }
228                 } else {
229                         encPub = make([]byte, 32)
230                         chacha20.XORKeyStream(encPub, dhPubRepr[:], h.rNonceNext(1), h.dsaPubH)
231                 }
232
233                 // Generate R* and encrypt them
234                 h.rServer = new([RSize]byte)
235                 if _, err = io.ReadFull(Rand, h.rServer[:]); err != nil {
236                         log.Fatalln("Error reading random for R:", err)
237                 }
238                 h.sServer = new([SSize]byte)
239                 if _, err = io.ReadFull(Rand, h.sServer[:]); err != nil {
240                         log.Fatalln("Error reading random for S:", err)
241                 }
242                 var encRs []byte
243                 if h.Conf.Noise && !h.Conf.Encless {
244                         encRs = make([]byte, h.Conf.MTU-len(encPub)-8)
245                 } else if h.Conf.Encless {
246                         encRs = make([]byte, h.Conf.MTU-8)
247                 } else {
248                         encRs = make([]byte, RSize+SSize)
249                 }
250                 copy(encRs, append(h.rServer[:], h.sServer[:]...))
251                 if h.Conf.Encless {
252                         encRs, err = EnclessEncode(h.key, h.rNonce, encRs)
253                         if err != nil {
254                                 panic(err)
255                         }
256                 } else {
257                         chacha20.XORKeyStream(encRs, encRs, h.rNonce, h.key)
258                 }
259
260                 // Send that to client
261                 h.conn.Write(append(encPub, append(
262                         encRs, idTag(h.Conf.ID, h.Conf.TimeSync, encPub)...,
263                 )...))
264                 h.LastPing = time.Now()
265         } else
266         // ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag
267         if h.rClient == nil && ((!h.Conf.Encless && len(data) >= 120) ||
268                 (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) {
269                 var dec []byte
270                 var err error
271                 if h.Conf.Encless {
272                         dec, err = EnclessDecode(
273                                 h.key,
274                                 h.rNonceNext(1),
275                                 data[:len(data)-8],
276                         )
277                         if err != nil {
278                                 log.Println("Unable to decode packet from", h.addr, err)
279                                 return nil
280                         }
281                         dec = dec[:RSize+RSize+SSize+ed25519.SignatureSize]
282                 } else {
283                         dec = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize)
284                         chacha20.XORKeyStream(
285                                 dec,
286                                 data[:RSize+RSize+SSize+ed25519.SignatureSize],
287                                 h.rNonceNext(1),
288                                 h.key,
289                         )
290                 }
291                 if subtle.ConstantTimeCompare(dec[:RSize], h.rServer[:]) != 1 {
292                         log.Println("Invalid server's random number with", h.addr)
293                         return nil
294                 }
295                 sign := new([ed25519.SignatureSize]byte)
296                 copy(sign[:], dec[RSize+RSize+SSize:])
297                 if !ed25519.Verify(h.Conf.Verifier.Pub, h.key[:], sign) {
298                         log.Println("Invalid signature from", h.addr)
299                         return nil
300                 }
301
302                 // Send final answer to client
303                 var enc []byte
304                 if h.Conf.Noise {
305                         enc = make([]byte, h.Conf.MTU-8)
306                 } else {
307                         enc = make([]byte, RSize)
308                 }
309                 copy(enc, dec[RSize:RSize+RSize])
310                 if h.Conf.Encless {
311                         enc, err = EnclessEncode(h.key, h.rNonceNext(2), enc)
312                         if err != nil {
313                                 panic(err)
314                         }
315                 } else {
316                         chacha20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key)
317                 }
318                 h.conn.Write(append(enc, idTag(h.Conf.ID, h.Conf.TimeSync, enc)...))
319
320                 // Switch peer
321                 peer := newPeer(
322                         false,
323                         h.addr,
324                         h.conn,
325                         h.Conf,
326                         keyFromSecrets(h.sServer[:], dec[RSize+RSize:RSize+RSize+SSize]))
327                 h.LastPing = time.Now()
328                 return peer
329         } else {
330                 log.Println("Invalid handshake message from", h.addr)
331         }
332         return nil
333 }
334
335 // Process handshake message on the client side.
336 // This function is intended to be called on client's side.
337 // If this is the final handshake message, then new Peer object
338 // will be created and used as a transport. If no mutually
339 // authenticated Peer is ready, then return nil.
340 func (h *Handshake) Client(data []byte) *Peer {
341         // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag
342         if h.rServer == nil && h.key == nil &&
343                 ((!h.Conf.Encless && len(data) >= 80) ||
344                         (h.Conf.Encless && len(data) == 2*(EnclessEnlargeSize+h.Conf.MTU))) {
345                 // Decrypt remote public key
346                 sDHRepr := new([32]byte)
347                 var tmp []byte
348                 var err error
349                 if h.Conf.Encless {
350                         tmp, err = EnclessDecode(
351                                 h.dsaPubH,
352                                 h.rNonceNext(1),
353                                 data[:len(data)/2],
354                         )
355                         if err != nil {
356                                 log.Println("Unable to decode packet from", h.addr, err)
357                                 return nil
358                         }
359                         copy(sDHRepr[:], tmp[:32])
360                 } else {
361                         chacha20.XORKeyStream(sDHRepr[:], data[:32], h.rNonceNext(1), h.dsaPubH)
362                 }
363
364                 // Compute shared key
365                 sDH := new([32]byte)
366                 extra25519.RepresentativeToPublicKey(sDH, sDHRepr)
367                 h.key = dhKeyGen(h.dhPriv, sDH)
368
369                 // Decrypt Rs
370                 h.rServer = new([RSize]byte)
371                 h.sServer = new([SSize]byte)
372                 if h.Conf.Encless {
373                         tmp, err = EnclessDecode(h.key, h.rNonce, data[len(data)/2:len(data)-8])
374                         if err != nil {
375                                 log.Println("Unable to decode packet from", h.addr, err)
376                                 return nil
377                         }
378                         copy(h.rServer[:], tmp[:RSize])
379                         copy(h.sServer[:], tmp[RSize:RSize+SSize])
380                 } else {
381                         decRs := make([]byte, RSize+SSize)
382                         chacha20.XORKeyStream(decRs, data[SSize:SSize+RSize+SSize], h.rNonce, h.key)
383                         copy(h.rServer[:], decRs[:RSize])
384                         copy(h.sServer[:], decRs[RSize:])
385                 }
386
387                 // Generate R* and signature and encrypt them
388                 h.rClient = new([RSize]byte)
389                 if _, err = io.ReadFull(Rand, h.rClient[:]); err != nil {
390                         log.Fatalln("Error reading random for R:", err)
391                 }
392                 h.sClient = new([SSize]byte)
393                 if _, err = io.ReadFull(Rand, h.sClient[:]); err != nil {
394                         log.Fatalln("Error reading random for S:", err)
395                 }
396                 sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:])
397
398                 var enc []byte
399                 if h.Conf.Noise {
400                         enc = make([]byte, h.Conf.MTU-8)
401                 } else {
402                         enc = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize)
403                 }
404                 copy(enc, h.rServer[:])
405                 copy(enc[RSize:], h.rClient[:])
406                 copy(enc[RSize+RSize:], h.sClient[:])
407                 copy(enc[RSize+RSize+SSize:], sign[:])
408                 if h.Conf.Encless {
409                         enc, err = EnclessEncode(h.key, h.rNonceNext(1), enc)
410                         if err != nil {
411                                 panic(err)
412                         }
413                 } else {
414                         chacha20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key)
415                 }
416
417                 // Send that to server
418                 h.conn.Write(append(enc, idTag(h.Conf.ID, h.Conf.TimeSync, enc)...))
419                 h.LastPing = time.Now()
420         } else
421         // ENC(K, R+2, RC) + IDtag
422         if h.key != nil && ((!h.Conf.Encless && len(data) >= 16) ||
423                 (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) {
424                 var err error
425                 // Decrypt rClient
426                 var dec []byte
427                 if h.Conf.Encless {
428                         dec, err = EnclessDecode(h.key, h.rNonceNext(2), data[:len(data)-8])
429                         if err != nil {
430                                 log.Println("Unable to decode packet from", h.addr, err)
431                                 return nil
432                         }
433                         dec = dec[:RSize]
434                 } else {
435                         dec = make([]byte, RSize)
436                         chacha20.XORKeyStream(dec, data[:RSize], h.rNonceNext(2), h.key)
437                 }
438                 if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 {
439                         log.Println("Invalid client's random number with", h.addr)
440                         return nil
441                 }
442
443                 // Switch peer
444                 peer := newPeer(
445                         true,
446                         h.addr,
447                         h.conn,
448                         h.Conf,
449                         keyFromSecrets(h.sServer[:], h.sClient[:]),
450                 )
451                 h.LastPing = time.Now()
452                 return peer
453         } else {
454                 log.Println("Invalid handshake stage from", h.addr)
455         }
456         return nil
457 }