github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/pss/handshake.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // +build !nopsshandshake 18 19 package pss 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "sync" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/hexutil" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/p2p" 32 "github.com/ethereum/go-ethereum/rlp" 33 "github.com/ethereum/go-ethereum/rpc" 34 "github.com/ethereum/go-ethereum/swarm/log" 35 ) 36 37 const ( 38 IsActiveHandshake = true 39 ) 40 41 var ( 42 ctrlSingleton *HandshakeController 43 ) 44 45 const ( 46 defaultSymKeyRequestTimeout = 1000 * 8 // max wait ms to receive a response to a handshake symkey request 47 defaultSymKeyExpiryTimeout = 1000 * 10 // ms to wait before allowing garbage collection of an expired symkey 48 defaultSymKeySendLimit = 256 // amount of messages a symkey is valid for 49 defaultSymKeyCapacity = 4 // max number of symkeys to store/send simultaneously 50 ) 51 52 // symmetric key exchange message payload 53 type handshakeMsg struct { 54 From []byte 55 Limit uint16 56 Keys [][]byte 57 Request uint8 58 Topic Topic 59 } 60 61 // internal representation of an individual symmetric key 62 type handshakeKey struct { 63 symKeyID *string 64 pubKeyID *string 65 limit uint16 66 count uint16 67 expiredAt time.Time 68 } 69 70 // container for all in- and outgoing keys 71 // for one particular peer (public key) and topic 72 type handshake struct { 73 outKeys []handshakeKey 74 inKeys []handshakeKey 75 } 76 77 // Initialization parameters for the HandshakeController 78 // 79 // SymKeyRequestExpiry: Timeout for waiting for a handshake reply 80 // (default 8000 ms) 81 // 82 // SymKeySendLimit: Amount of messages symmetric keys issues by 83 // this node is valid for (default 256) 84 // 85 // SymKeyCapacity: Ideal (and maximum) amount of symmetric keys 86 // held per direction per peer (default 4) 87 type HandshakeParams struct { 88 SymKeyRequestTimeout time.Duration 89 SymKeyExpiryTimeout time.Duration 90 SymKeySendLimit uint16 91 SymKeyCapacity uint8 92 } 93 94 // Sane defaults for HandshakeController initialization 95 func NewHandshakeParams() *HandshakeParams { 96 return &HandshakeParams{ 97 SymKeyRequestTimeout: defaultSymKeyRequestTimeout * time.Millisecond, 98 SymKeyExpiryTimeout: defaultSymKeyExpiryTimeout * time.Millisecond, 99 SymKeySendLimit: defaultSymKeySendLimit, 100 SymKeyCapacity: defaultSymKeyCapacity, 101 } 102 } 103 104 // Singleton object enabling semi-automatic Diffie-Hellman 105 // exchange of ephemeral symmetric keys 106 type HandshakeController struct { 107 pss *Pss 108 keyC map[string]chan []string // adds a channel to report when a handshake succeeds 109 keyCMu sync.Mutex // protects keyC map 110 lock sync.Mutex 111 symKeyRequestTimeout time.Duration 112 symKeyExpiryTimeout time.Duration 113 symKeySendLimit uint16 114 symKeyCapacity uint8 115 symKeyIndex map[string]*handshakeKey 116 handshakes map[string]map[Topic]*handshake 117 deregisterFuncs map[Topic]func() 118 } 119 120 // Attach HandshakeController to pss node 121 // 122 // Must be called before starting the pss node service 123 func SetHandshakeController(pss *Pss, params *HandshakeParams) error { 124 ctrl := &HandshakeController{ 125 pss: pss, 126 keyC: make(map[string]chan []string), 127 symKeyRequestTimeout: params.SymKeyRequestTimeout, 128 symKeyExpiryTimeout: params.SymKeyExpiryTimeout, 129 symKeySendLimit: params.SymKeySendLimit, 130 symKeyCapacity: params.SymKeyCapacity, 131 symKeyIndex: make(map[string]*handshakeKey), 132 handshakes: make(map[string]map[Topic]*handshake), 133 deregisterFuncs: make(map[Topic]func()), 134 } 135 api := &HandshakeAPI{ 136 namespace: "pss", 137 ctrl: ctrl, 138 } 139 pss.addAPI(rpc.API{ 140 Namespace: api.namespace, 141 Version: "0.2", 142 Service: api, 143 Public: true, 144 }) 145 ctrlSingleton = ctrl 146 return nil 147 } 148 149 // Return all unexpired symmetric keys from store by 150 // peer (public key), topic and specified direction 151 func (ctl *HandshakeController) validKeys(pubkeyid string, topic *Topic, in bool) (validkeys []*string) { 152 ctl.lock.Lock() 153 defer ctl.lock.Unlock() 154 now := time.Now() 155 if _, ok := ctl.handshakes[pubkeyid]; !ok { 156 return []*string{} 157 } else if _, ok := ctl.handshakes[pubkeyid][*topic]; !ok { 158 return []*string{} 159 } 160 var keystore *[]handshakeKey 161 if in { 162 keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) 163 } else { 164 keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) 165 } 166 167 for _, key := range *keystore { 168 if key.limit <= key.count { 169 ctl.releaseKeyNoLock(*key.symKeyID, topic) 170 } else if !key.expiredAt.IsZero() && key.expiredAt.Before(now) { 171 ctl.releaseKeyNoLock(*key.symKeyID, topic) 172 } else { 173 validkeys = append(validkeys, key.symKeyID) 174 } 175 } 176 return 177 } 178 179 // Add all given symmetric keys with validity limits to store by 180 // peer (public key), topic and specified direction 181 func (ctl *HandshakeController) updateKeys(pubkeyid string, topic *Topic, in bool, symkeyids []string, limit uint16) { 182 ctl.lock.Lock() 183 defer ctl.lock.Unlock() 184 if _, ok := ctl.handshakes[pubkeyid]; !ok { 185 ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) 186 187 } 188 if ctl.handshakes[pubkeyid][*topic] == nil { 189 ctl.handshakes[pubkeyid][*topic] = &handshake{} 190 } 191 var keystore *[]handshakeKey 192 expire := time.Now() 193 if in { 194 keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) 195 } else { 196 keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) 197 expire = expire.Add(time.Millisecond * ctl.symKeyExpiryTimeout) 198 } 199 for _, storekey := range *keystore { 200 storekey.expiredAt = expire 201 } 202 for i := 0; i < len(symkeyids); i++ { 203 storekey := handshakeKey{ 204 symKeyID: &symkeyids[i], 205 pubKeyID: &pubkeyid, 206 limit: limit, 207 } 208 *keystore = append(*keystore, storekey) 209 ctl.pss.mx.Lock() 210 ctl.pss.symKeyPool[*storekey.symKeyID][*topic].protected = true 211 ctl.pss.mx.Unlock() 212 } 213 for i := 0; i < len(*keystore); i++ { 214 ctl.symKeyIndex[*(*keystore)[i].symKeyID] = &((*keystore)[i]) 215 } 216 } 217 218 func (ctl *HandshakeController) releaseKey(symkeyid string, topic *Topic) bool { 219 ctl.lock.Lock() 220 defer ctl.lock.Unlock() 221 return ctl.releaseKeyNoLock(symkeyid, topic) 222 } 223 224 // Expire a symmetric key, making it eligible for garbage collection 225 func (ctl *HandshakeController) releaseKeyNoLock(symkeyid string, topic *Topic) bool { 226 if ctl.symKeyIndex[symkeyid] == nil { 227 log.Debug("no symkey", "symkeyid", symkeyid) 228 return false 229 } 230 ctl.symKeyIndex[symkeyid].expiredAt = time.Now() 231 log.Debug("handshake release", "symkeyid", symkeyid) 232 return true 233 } 234 235 // Checks all symmetric keys in given direction(s) by 236 // specified peer (public key) and topic for expiry. 237 // Expired means: 238 // - expiry timestamp is set, and grace period is exceeded 239 // - message validity limit is reached 240 func (ctl *HandshakeController) cleanHandshake(pubkeyid string, topic *Topic, in bool, out bool) int { 241 ctl.lock.Lock() 242 defer ctl.lock.Unlock() 243 var deletecount int 244 var deletes []string 245 now := time.Now() 246 handshake := ctl.handshakes[pubkeyid][*topic] 247 log.Debug("handshake clean", "pubkey", pubkeyid, "topic", topic) 248 if in { 249 for i, key := range handshake.inKeys { 250 if key.expiredAt.Before(now) || (key.expiredAt.IsZero() && key.limit <= key.count) { 251 log.Trace("handshake in clean remove", "symkeyid", *key.symKeyID) 252 deletes = append(deletes, *key.symKeyID) 253 handshake.inKeys[deletecount] = handshake.inKeys[i] 254 deletecount++ 255 } 256 } 257 handshake.inKeys = handshake.inKeys[:len(handshake.inKeys)-deletecount] 258 } 259 if out { 260 deletecount = 0 261 for i, key := range handshake.outKeys { 262 if key.expiredAt.Before(now) && (key.expiredAt.IsZero() && key.limit <= key.count) { 263 log.Trace("handshake out clean remove", "symkeyid", *key.symKeyID) 264 deletes = append(deletes, *key.symKeyID) 265 handshake.outKeys[deletecount] = handshake.outKeys[i] 266 deletecount++ 267 } 268 } 269 handshake.outKeys = handshake.outKeys[:len(handshake.outKeys)-deletecount] 270 } 271 for _, keyid := range deletes { 272 delete(ctl.symKeyIndex, keyid) 273 ctl.pss.symKeyPool[keyid][*topic].protected = false 274 } 275 return len(deletes) 276 } 277 278 // Runs cleanHandshake() on all peers and topics 279 func (ctl *HandshakeController) clean() { 280 peerpubkeys := ctl.handshakes 281 for pubkeyid, peertopics := range peerpubkeys { 282 for topic := range peertopics { 283 ctl.cleanHandshake(pubkeyid, &topic, true, true) 284 } 285 } 286 } 287 288 func (ctl *HandshakeController) getSymKey(symkeyid string) *handshakeKey { 289 ctl.lock.Lock() 290 defer ctl.lock.Unlock() 291 return ctl.symKeyIndex[symkeyid] 292 } 293 294 // Passed as a PssMsg handler for the topic handshake is activated on 295 // Handles incoming key exchange messages and 296 // counts message usage by symmetric key (expiry limit control) 297 // Only returns error if key handler fails 298 func (ctl *HandshakeController) handler(msg []byte, p *p2p.Peer, asymmetric bool, symkeyid string) error { 299 if asymmetric { 300 keymsg := &handshakeMsg{} 301 err := rlp.DecodeBytes(msg, keymsg) 302 if err == nil { 303 err := ctl.handleKeys(symkeyid, keymsg) 304 if err != nil { 305 log.Error("handlekeys fail", "error", err) 306 } 307 return err 308 } 309 return nil 310 } 311 return ctl.registerSymKeyUse(symkeyid) 312 } 313 314 func (ctl *HandshakeController) registerSymKeyUse(symkeyid string) error { 315 ctl.lock.Lock() 316 defer ctl.lock.Unlock() 317 318 symKey, ok := ctl.symKeyIndex[symkeyid] 319 if !ok { 320 return nil 321 } 322 323 if symKey.count >= symKey.limit { 324 return fmt.Errorf("symetric key expired (id: %s)", symkeyid) 325 } 326 symKey.count++ 327 328 receiver := common.ToHex(crypto.FromECDSAPub(ctl.pss.PublicKey())) 329 log.Trace("increment symkey recv use", "symsymkeyid", symkeyid, "count", symKey.count, "limit", symKey.limit, "receiver", receiver) 330 331 return nil 332 } 333 334 // Handle incoming key exchange message 335 // Add keys received from peer to store 336 // and enerate and send the amount of keys requested by peer 337 // 338 // TODO: 339 // - flood guard 340 // - keylength check 341 // - update address hint if: 342 // 1) leftmost bytes in new address do not match stored 343 // 2) else, if new address is longer 344 func (ctl *HandshakeController) handleKeys(pubkeyid string, keymsg *handshakeMsg) error { 345 // new keys from peer 346 if len(keymsg.Keys) > 0 { 347 log.Debug("received handshake keys", "pubkeyid", pubkeyid, "from", keymsg.From, "count", len(keymsg.Keys)) 348 var sendsymkeyids []string 349 for _, key := range keymsg.Keys { 350 sendsymkey := make([]byte, len(key)) 351 copy(sendsymkey, key) 352 sendsymkeyid, err := ctl.pss.setSymmetricKey(sendsymkey, keymsg.Topic, PssAddress(keymsg.From), false, false) 353 if err != nil { 354 return err 355 } 356 sendsymkeyids = append(sendsymkeyids, sendsymkeyid) 357 } 358 if len(sendsymkeyids) > 0 { 359 ctl.updateKeys(pubkeyid, &keymsg.Topic, false, sendsymkeyids, keymsg.Limit) 360 361 ctl.alertHandshake(pubkeyid, sendsymkeyids) 362 } 363 } 364 365 // peer request for keys 366 if keymsg.Request > 0 { 367 _, err := ctl.sendKey(pubkeyid, &keymsg.Topic, keymsg.Request) 368 if err != nil { 369 return err 370 } 371 } 372 373 return nil 374 } 375 376 // Send key exchange to peer (public key) valid for `topic` 377 // Will send number of keys specified by `keycount` with 378 // validity limits specified in `msglimit` 379 // If number of valid outgoing keys is less than the ideal/max 380 // amount, a request is sent for the amount of keys to make up 381 // the difference 382 func (ctl *HandshakeController) sendKey(pubkeyid string, topic *Topic, keycount uint8) ([]string, error) { 383 384 var requestcount uint8 385 to := PssAddress{} 386 if _, ok := ctl.pss.pubKeyPool[pubkeyid]; !ok { 387 return []string{}, errors.New("Invalid public key") 388 } else if psp, ok := ctl.pss.pubKeyPool[pubkeyid][*topic]; ok { 389 to = psp.address 390 } 391 392 recvkeys := make([][]byte, keycount) 393 recvkeyids := make([]string, keycount) 394 ctl.lock.Lock() 395 if _, ok := ctl.handshakes[pubkeyid]; !ok { 396 ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) 397 } 398 ctl.lock.Unlock() 399 400 // check if buffer is not full 401 outkeys := ctl.validKeys(pubkeyid, topic, false) 402 if len(outkeys) < int(ctl.symKeyCapacity) { 403 //requestcount = uint8(self.symKeyCapacity - uint8(len(outkeys))) 404 requestcount = ctl.symKeyCapacity 405 } 406 // return if there's nothing to be accomplished 407 if requestcount == 0 && keycount == 0 { 408 return []string{}, nil 409 } 410 411 // generate new keys to send 412 for i := 0; i < len(recvkeyids); i++ { 413 var err error 414 recvkeyids[i], err = ctl.pss.GenerateSymmetricKey(*topic, to, true) 415 if err != nil { 416 return []string{}, fmt.Errorf("set receive symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) 417 } 418 recvkeys[i], err = ctl.pss.GetSymmetricKey(recvkeyids[i]) 419 if err != nil { 420 return []string{}, fmt.Errorf("GET Generated outgoing symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) 421 } 422 } 423 ctl.updateKeys(pubkeyid, topic, true, recvkeyids, ctl.symKeySendLimit) 424 425 // encode and send the message 426 recvkeymsg := &handshakeMsg{ 427 From: ctl.pss.BaseAddr(), 428 Keys: recvkeys, 429 Request: requestcount, 430 Limit: ctl.symKeySendLimit, 431 Topic: *topic, 432 } 433 log.Debug("sending our symkeys", "pubkey", pubkeyid, "symkeys", recvkeyids, "limit", ctl.symKeySendLimit, "requestcount", requestcount, "keycount", len(recvkeys)) 434 recvkeybytes, err := rlp.EncodeToBytes(recvkeymsg) 435 if err != nil { 436 return []string{}, fmt.Errorf("rlp keymsg encode fail: %v", err) 437 } 438 // if the send fails it means this public key is not registered for this particular address AND topic 439 err = ctl.pss.SendAsym(pubkeyid, *topic, recvkeybytes) 440 if err != nil { 441 return []string{}, fmt.Errorf("Send symkey failed: %v", err) 442 } 443 return recvkeyids, nil 444 } 445 446 // Enables callback for keys received from a key exchange request 447 func (ctl *HandshakeController) alertHandshake(pubkeyid string, symkeys []string) chan []string { 448 ctl.keyCMu.Lock() 449 defer ctl.keyCMu.Unlock() 450 if len(symkeys) > 0 { 451 if _, ok := ctl.keyC[pubkeyid]; ok { 452 ctl.keyC[pubkeyid] <- symkeys 453 close(ctl.keyC[pubkeyid]) 454 delete(ctl.keyC, pubkeyid) 455 } 456 return nil 457 } 458 if _, ok := ctl.keyC[pubkeyid]; !ok { 459 ctl.keyC[pubkeyid] = make(chan []string) 460 } 461 return ctl.keyC[pubkeyid] 462 } 463 464 type HandshakeAPI struct { 465 namespace string 466 ctrl *HandshakeController 467 } 468 469 // Initiate a handshake session for a peer (public key) and topic 470 // combination. 471 // 472 // If `sync` is set, the call will block until keys are received from peer, 473 // or if the handshake request times out 474 // 475 // If `flush` is set, the max amount of keys will be sent to the peer 476 // regardless of how many valid keys that currently exist in the store. 477 // 478 // Returns list of symmetric key ids that can be passed to pss.GetSymmetricKey() 479 // for retrieval of the symmetric key bytes themselves. 480 // 481 // Fails if the incoming symmetric key store is already full (and `flush` is false), 482 // or if the underlying key dispatcher fails 483 func (api *HandshakeAPI) Handshake(pubkeyid string, topic Topic, sync bool, flush bool) (keys []string, err error) { 484 var hsc chan []string 485 var keycount uint8 486 if flush { 487 keycount = api.ctrl.symKeyCapacity 488 } else { 489 validkeys := api.ctrl.validKeys(pubkeyid, &topic, false) 490 keycount = api.ctrl.symKeyCapacity - uint8(len(validkeys)) 491 } 492 if keycount == 0 { 493 return keys, errors.New("Incoming symmetric key store is already full") 494 } 495 if sync { 496 hsc = api.ctrl.alertHandshake(pubkeyid, []string{}) 497 } 498 _, err = api.ctrl.sendKey(pubkeyid, &topic, keycount) 499 if err != nil { 500 return keys, err 501 } 502 if sync { 503 ctx, cancel := context.WithTimeout(context.Background(), api.ctrl.symKeyRequestTimeout) 504 defer cancel() 505 select { 506 case keys = <-hsc: 507 log.Trace("sync handshake response receive", "key", keys) 508 case <-ctx.Done(): 509 return []string{}, errors.New("timeout") 510 } 511 } 512 return keys, nil 513 } 514 515 // Activate handshake functionality on a topic 516 func (api *HandshakeAPI) AddHandshake(topic Topic) error { 517 api.ctrl.deregisterFuncs[topic] = api.ctrl.pss.Register(&topic, NewHandler(api.ctrl.handler)) 518 return nil 519 } 520 521 // Deactivate handshake functionality on a topic 522 func (api *HandshakeAPI) RemoveHandshake(topic *Topic) error { 523 if _, ok := api.ctrl.deregisterFuncs[*topic]; ok { 524 api.ctrl.deregisterFuncs[*topic]() 525 } 526 return nil 527 } 528 529 // Returns all valid symmetric keys in store per peer (public key) 530 // and topic. 531 // 532 // The `in` and `out` parameters indicate for which direction(s) 533 // symmetric keys will be returned. 534 // If both are false, no keys (and no error) will be returned. 535 func (api *HandshakeAPI) GetHandshakeKeys(pubkeyid string, topic Topic, in bool, out bool) (keys []string, err error) { 536 if in { 537 for _, inkey := range api.ctrl.validKeys(pubkeyid, &topic, true) { 538 keys = append(keys, *inkey) 539 } 540 } 541 if out { 542 for _, outkey := range api.ctrl.validKeys(pubkeyid, &topic, false) { 543 keys = append(keys, *outkey) 544 } 545 } 546 return keys, nil 547 } 548 549 // Returns the amount of messages the specified symmetric key 550 // is still valid for under the handshake scheme 551 func (api *HandshakeAPI) GetHandshakeKeyCapacity(symkeyid string) (uint16, error) { 552 storekey := api.ctrl.getSymKey(symkeyid) 553 if storekey == nil { 554 return 0, fmt.Errorf("invalid symkey id %s", symkeyid) 555 } 556 return storekey.limit - storekey.count, nil 557 } 558 559 // Returns the byte representation of the public key in ascii hex 560 // associated with the given symmetric key 561 func (api *HandshakeAPI) GetHandshakePublicKey(symkeyid string) (string, error) { 562 storekey := api.ctrl.getSymKey(symkeyid) 563 if storekey == nil { 564 return "", fmt.Errorf("invalid symkey id %s", symkeyid) 565 } 566 return *storekey.pubKeyID, nil 567 } 568 569 // Manually expire the given symkey 570 // 571 // If `flush` is set, garbage collection will be performed before returning. 572 // 573 // Returns true on successful removal, false otherwise 574 func (api *HandshakeAPI) ReleaseHandshakeKey(pubkeyid string, topic Topic, symkeyid string, flush bool) (removed bool, err error) { 575 removed = api.ctrl.releaseKey(symkeyid, &topic) 576 if removed && flush { 577 api.ctrl.cleanHandshake(pubkeyid, &topic, true, true) 578 } 579 return 580 } 581 582 // Send symmetric message under the handshake scheme 583 // 584 // Overloads the pss.SendSym() API call, adding symmetric key usage count 585 // for message expiry control 586 func (api *HandshakeAPI) SendSym(symkeyid string, topic Topic, msg hexutil.Bytes) (err error) { 587 err = api.ctrl.pss.SendSym(symkeyid, topic, msg[:]) 588 if otherErr := api.ctrl.registerSymKeyUse(symkeyid); otherErr != nil { 589 return otherErr 590 } 591 return err 592 }