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