github.com/Ethersocial/go-esn@v0.3.7/swarm/pss/pss.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 package pss 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "crypto/rand" 24 "errors" 25 "fmt" 26 "sync" 27 "time" 28 29 "github.com/ethersocial/go-esn/common" 30 "github.com/ethersocial/go-esn/crypto" 31 "github.com/ethersocial/go-esn/metrics" 32 "github.com/ethersocial/go-esn/p2p" 33 "github.com/ethersocial/go-esn/p2p/enode" 34 "github.com/ethersocial/go-esn/p2p/protocols" 35 "github.com/ethersocial/go-esn/rpc" 36 "github.com/ethersocial/go-esn/swarm/log" 37 "github.com/ethersocial/go-esn/swarm/network" 38 "github.com/ethersocial/go-esn/swarm/pot" 39 "github.com/ethersocial/go-esn/swarm/storage" 40 whisper "github.com/ethersocial/go-esn/whisper/whisperv5" 41 ) 42 43 const ( 44 defaultPaddingByteSize = 16 45 DefaultMsgTTL = time.Second * 120 46 defaultDigestCacheTTL = time.Second * 10 47 defaultSymKeyCacheCapacity = 512 48 digestLength = 32 // byte length of digest used for pss cache (currently same as swarm chunk hash) 49 defaultWhisperWorkTime = 3 50 defaultWhisperPoW = 0.0000000001 51 defaultMaxMsgSize = 1024 * 1024 52 defaultCleanInterval = time.Second * 60 * 10 53 defaultOutboxCapacity = 100000 54 pssProtocolName = "pss" 55 pssVersion = 2 56 hasherCount = 8 57 ) 58 59 var ( 60 addressLength = len(pot.Address{}) 61 ) 62 63 // cache is used for preventing backwards routing 64 // will also be instrumental in flood guard mechanism 65 // and mailbox implementation 66 type pssCacheEntry struct { 67 expiresAt time.Time 68 } 69 70 // abstraction to enable access to p2p.protocols.Peer.Send 71 type senderPeer interface { 72 Info() *p2p.PeerInfo 73 ID() enode.ID 74 Address() []byte 75 Send(context.Context, interface{}) error 76 } 77 78 // per-key peer related information 79 // member `protected` prevents garbage collection of the instance 80 type pssPeer struct { 81 lastSeen time.Time 82 address *PssAddress 83 protected bool 84 } 85 86 // Pss configuration parameters 87 type PssParams struct { 88 MsgTTL time.Duration 89 CacheTTL time.Duration 90 privateKey *ecdsa.PrivateKey 91 SymKeyCacheCapacity int 92 AllowRaw bool // If true, enables sending and receiving messages without builtin pss encryption 93 } 94 95 // Sane defaults for Pss 96 func NewPssParams() *PssParams { 97 return &PssParams{ 98 MsgTTL: DefaultMsgTTL, 99 CacheTTL: defaultDigestCacheTTL, 100 SymKeyCacheCapacity: defaultSymKeyCacheCapacity, 101 } 102 } 103 104 func (params *PssParams) WithPrivateKey(privatekey *ecdsa.PrivateKey) *PssParams { 105 params.privateKey = privatekey 106 return params 107 } 108 109 // Toplevel pss object, takes care of message sending, receiving, decryption and encryption, message handler dispatchers and message forwarding. 110 // 111 // Implements node.Service 112 type Pss struct { 113 *network.Kademlia // we can get the Kademlia address from this 114 privateKey *ecdsa.PrivateKey // pss can have it's own independent key 115 w *whisper.Whisper // key and encryption backend 116 auxAPIs []rpc.API // builtins (handshake, test) can add APIs 117 118 // sending and forwarding 119 fwdPool map[string]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer 120 fwdPoolMu sync.RWMutex 121 fwdCache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg 122 fwdCacheMu sync.RWMutex 123 cacheTTL time.Duration // how long to keep messages in fwdCache (not implemented) 124 msgTTL time.Duration 125 paddingByteSize int 126 capstring string 127 outbox chan *PssMsg 128 129 // keys and peers 130 pubKeyPool map[string]map[Topic]*pssPeer // mapping of hex public keys to peer address by topic. 131 pubKeyPoolMu sync.RWMutex 132 symKeyPool map[string]map[Topic]*pssPeer // mapping of symkeyids to peer address by topic. 133 symKeyPoolMu sync.RWMutex 134 symKeyDecryptCache []*string // fast lookup of symkeys recently used for decryption; last used is on top of stack 135 symKeyDecryptCacheCursor int // modular cursor pointing to last used, wraps on symKeyDecryptCache array 136 symKeyDecryptCacheCapacity int // max amount of symkeys to keep. 137 138 // message handling 139 handlers map[Topic]map[*Handler]bool // topic and version based pss payload handlers. See pss.Handle() 140 handlersMu sync.RWMutex 141 allowRaw bool 142 hashPool sync.Pool 143 144 // process 145 quitC chan struct{} 146 } 147 148 func (p *Pss) String() string { 149 return fmt.Sprintf("pss: addr %x, pubkey %v", p.BaseAddr(), common.ToHex(crypto.FromECDSAPub(&p.privateKey.PublicKey))) 150 } 151 152 // Creates a new Pss instance. 153 // 154 // In addition to params, it takes a swarm network Kademlia 155 // and a FileStore storage for message cache storage. 156 func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) { 157 if params.privateKey == nil { 158 return nil, errors.New("missing private key for pss") 159 } 160 cap := p2p.Cap{ 161 Name: pssProtocolName, 162 Version: pssVersion, 163 } 164 ps := &Pss{ 165 Kademlia: k, 166 privateKey: params.privateKey, 167 w: whisper.New(&whisper.DefaultConfig), 168 quitC: make(chan struct{}), 169 170 fwdPool: make(map[string]*protocols.Peer), 171 fwdCache: make(map[pssDigest]pssCacheEntry), 172 cacheTTL: params.CacheTTL, 173 msgTTL: params.MsgTTL, 174 paddingByteSize: defaultPaddingByteSize, 175 capstring: cap.String(), 176 outbox: make(chan *PssMsg, defaultOutboxCapacity), 177 178 pubKeyPool: make(map[string]map[Topic]*pssPeer), 179 symKeyPool: make(map[string]map[Topic]*pssPeer), 180 symKeyDecryptCache: make([]*string, params.SymKeyCacheCapacity), 181 symKeyDecryptCacheCapacity: params.SymKeyCacheCapacity, 182 183 handlers: make(map[Topic]map[*Handler]bool), 184 allowRaw: params.AllowRaw, 185 hashPool: sync.Pool{ 186 New: func() interface{} { 187 return storage.MakeHashFunc(storage.DefaultHash)() 188 }, 189 }, 190 } 191 192 for i := 0; i < hasherCount; i++ { 193 hashfunc := storage.MakeHashFunc(storage.DefaultHash)() 194 ps.hashPool.Put(hashfunc) 195 } 196 197 return ps, nil 198 } 199 200 ///////////////////////////////////////////////////////////////////// 201 // SECTION: node.Service interface 202 ///////////////////////////////////////////////////////////////////// 203 204 func (p *Pss) Start(srv *p2p.Server) error { 205 go func() { 206 ticker := time.NewTicker(defaultCleanInterval) 207 cacheTicker := time.NewTicker(p.cacheTTL) 208 defer ticker.Stop() 209 defer cacheTicker.Stop() 210 for { 211 select { 212 case <-cacheTicker.C: 213 p.cleanFwdCache() 214 case <-ticker.C: 215 p.cleanKeys() 216 case <-p.quitC: 217 return 218 } 219 } 220 }() 221 go func() { 222 for { 223 select { 224 case msg := <-p.outbox: 225 err := p.forward(msg) 226 if err != nil { 227 log.Error(err.Error()) 228 metrics.GetOrRegisterCounter("pss.forward.err", nil).Inc(1) 229 } 230 case <-p.quitC: 231 return 232 } 233 } 234 }() 235 log.Info("Started Pss") 236 log.Info("Loaded EC keys", "pubkey", common.ToHex(crypto.FromECDSAPub(p.PublicKey())), "secp256", common.ToHex(crypto.CompressPubkey(p.PublicKey()))) 237 return nil 238 } 239 240 func (p *Pss) Stop() error { 241 log.Info("Pss shutting down") 242 close(p.quitC) 243 return nil 244 } 245 246 var pssSpec = &protocols.Spec{ 247 Name: pssProtocolName, 248 Version: pssVersion, 249 MaxMsgSize: defaultMaxMsgSize, 250 Messages: []interface{}{ 251 PssMsg{}, 252 }, 253 } 254 255 func (p *Pss) Protocols() []p2p.Protocol { 256 return []p2p.Protocol{ 257 { 258 Name: pssSpec.Name, 259 Version: pssSpec.Version, 260 Length: pssSpec.Length(), 261 Run: p.Run, 262 }, 263 } 264 } 265 266 func (p *Pss) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 267 pp := protocols.NewPeer(peer, rw, pssSpec) 268 p.fwdPoolMu.Lock() 269 p.fwdPool[peer.Info().ID] = pp 270 p.fwdPoolMu.Unlock() 271 return pp.Run(p.handlePssMsg) 272 } 273 274 func (p *Pss) APIs() []rpc.API { 275 apis := []rpc.API{ 276 { 277 Namespace: "pss", 278 Version: "1.0", 279 Service: NewAPI(p), 280 Public: true, 281 }, 282 } 283 apis = append(apis, p.auxAPIs...) 284 return apis 285 } 286 287 // add API methods to the pss API 288 // must be run before node is started 289 func (p *Pss) addAPI(api rpc.API) { 290 p.auxAPIs = append(p.auxAPIs, api) 291 } 292 293 // Returns the swarm Kademlia address of the pss node 294 func (p *Pss) BaseAddr() []byte { 295 return p.Kademlia.BaseAddr() 296 } 297 298 // Returns the pss node's public key 299 func (p *Pss) PublicKey() *ecdsa.PublicKey { 300 return &p.privateKey.PublicKey 301 } 302 303 ///////////////////////////////////////////////////////////////////// 304 // SECTION: Message handling 305 ///////////////////////////////////////////////////////////////////// 306 307 // Links a handler function to a Topic 308 // 309 // All incoming messages with an envelope Topic matching the 310 // topic specified will be passed to the given Handler function. 311 // 312 // There may be an arbitrary number of handler functions per topic. 313 // 314 // Returns a deregister function which needs to be called to 315 // deregister the handler, 316 func (p *Pss) Register(topic *Topic, handler Handler) func() { 317 p.handlersMu.Lock() 318 defer p.handlersMu.Unlock() 319 handlers := p.handlers[*topic] 320 if handlers == nil { 321 handlers = make(map[*Handler]bool) 322 p.handlers[*topic] = handlers 323 } 324 handlers[&handler] = true 325 return func() { p.deregister(topic, &handler) } 326 } 327 func (p *Pss) deregister(topic *Topic, h *Handler) { 328 p.handlersMu.Lock() 329 defer p.handlersMu.Unlock() 330 handlers := p.handlers[*topic] 331 if len(handlers) == 1 { 332 delete(p.handlers, *topic) 333 return 334 } 335 delete(handlers, h) 336 } 337 338 // get all registered handlers for respective topics 339 func (p *Pss) getHandlers(topic Topic) map[*Handler]bool { 340 p.handlersMu.RLock() 341 defer p.handlersMu.RUnlock() 342 return p.handlers[topic] 343 } 344 345 // Filters incoming messages for processing or forwarding. 346 // Check if address partially matches 347 // If yes, it CAN be for us, and we process it 348 // Only passes error to pss protocol handler if payload is not valid pssmsg 349 func (p *Pss) handlePssMsg(ctx context.Context, msg interface{}) error { 350 metrics.GetOrRegisterCounter("pss.handlepssmsg", nil).Inc(1) 351 352 pssmsg, ok := msg.(*PssMsg) 353 354 if !ok { 355 return fmt.Errorf("invalid message type. Expected *PssMsg, got %T ", msg) 356 } 357 if int64(pssmsg.Expire) < time.Now().Unix() { 358 metrics.GetOrRegisterCounter("pss.expire", nil).Inc(1) 359 log.Warn("pss filtered expired message", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", common.ToHex(pssmsg.To)) 360 return nil 361 } 362 if p.checkFwdCache(pssmsg) { 363 log.Trace("pss relay block-cache match (process)", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", (common.ToHex(pssmsg.To))) 364 return nil 365 } 366 p.addFwdCache(pssmsg) 367 368 if !p.isSelfPossibleRecipient(pssmsg) { 369 log.Trace("pss was for someone else :'( ... forwarding", "pss", common.ToHex(p.BaseAddr())) 370 return p.enqueue(pssmsg) 371 } 372 373 log.Trace("pss for us, yay! ... let's process!", "pss", common.ToHex(p.BaseAddr())) 374 if err := p.process(pssmsg); err != nil { 375 qerr := p.enqueue(pssmsg) 376 if qerr != nil { 377 return fmt.Errorf("process fail: processerr %v, queueerr: %v", err, qerr) 378 } 379 } 380 return nil 381 382 } 383 384 // Entry point to processing a message for which the current node can be the intended recipient. 385 // Attempts symmetric and asymmetric decryption with stored keys. 386 // Dispatches message to all handlers matching the message topic 387 func (p *Pss) process(pssmsg *PssMsg) error { 388 metrics.GetOrRegisterCounter("pss.process", nil).Inc(1) 389 390 var err error 391 var recvmsg *whisper.ReceivedMessage 392 var payload []byte 393 var from *PssAddress 394 var asymmetric bool 395 var keyid string 396 var keyFunc func(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) 397 398 envelope := pssmsg.Payload 399 psstopic := Topic(envelope.Topic) 400 if pssmsg.isRaw() { 401 if !p.allowRaw { 402 return errors.New("raw message support disabled") 403 } 404 payload = pssmsg.Payload.Data 405 } else { 406 if pssmsg.isSym() { 407 keyFunc = p.processSym 408 } else { 409 asymmetric = true 410 keyFunc = p.processAsym 411 } 412 413 recvmsg, keyid, from, err = keyFunc(envelope) 414 if err != nil { 415 return errors.New("Decryption failed") 416 } 417 payload = recvmsg.Payload 418 } 419 420 if len(pssmsg.To) < addressLength { 421 if err := p.enqueue(pssmsg); err != nil { 422 return err 423 } 424 } 425 p.executeHandlers(psstopic, payload, from, asymmetric, keyid) 426 427 return nil 428 429 } 430 431 func (p *Pss) executeHandlers(topic Topic, payload []byte, from *PssAddress, asymmetric bool, keyid string) { 432 handlers := p.getHandlers(topic) 433 peer := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%x", from), []p2p.Cap{}) 434 for f := range handlers { 435 err := (*f)(payload, peer, asymmetric, keyid) 436 if err != nil { 437 log.Warn("Pss handler %p failed: %v", f, err) 438 } 439 } 440 } 441 442 // will return false if using partial address 443 func (p *Pss) isSelfRecipient(msg *PssMsg) bool { 444 return bytes.Equal(msg.To, p.Kademlia.BaseAddr()) 445 } 446 447 // test match of leftmost bytes in given message to node's Kademlia address 448 func (p *Pss) isSelfPossibleRecipient(msg *PssMsg) bool { 449 local := p.Kademlia.BaseAddr() 450 return bytes.Equal(msg.To, local[:len(msg.To)]) 451 } 452 453 ///////////////////////////////////////////////////////////////////// 454 // SECTION: Encryption 455 ///////////////////////////////////////////////////////////////////// 456 457 // Links a peer ECDSA public key to a topic 458 // 459 // This is required for asymmetric message exchange 460 // on the given topic 461 // 462 // The value in `address` will be used as a routing hint for the 463 // public key / topic association 464 func (p *Pss) SetPeerPublicKey(pubkey *ecdsa.PublicKey, topic Topic, address *PssAddress) error { 465 pubkeybytes := crypto.FromECDSAPub(pubkey) 466 if len(pubkeybytes) == 0 { 467 return fmt.Errorf("invalid public key: %v", pubkey) 468 } 469 pubkeyid := common.ToHex(pubkeybytes) 470 psp := &pssPeer{ 471 address: address, 472 } 473 p.pubKeyPoolMu.Lock() 474 if _, ok := p.pubKeyPool[pubkeyid]; !ok { 475 p.pubKeyPool[pubkeyid] = make(map[Topic]*pssPeer) 476 } 477 p.pubKeyPool[pubkeyid][topic] = psp 478 p.pubKeyPoolMu.Unlock() 479 log.Trace("added pubkey", "pubkeyid", pubkeyid, "topic", topic, "address", common.ToHex(*address)) 480 return nil 481 } 482 483 // Automatically generate a new symkey for a topic and address hint 484 func (p *Pss) GenerateSymmetricKey(topic Topic, address *PssAddress, addToCache bool) (string, error) { 485 keyid, err := p.w.GenerateSymKey() 486 if err != nil { 487 return "", err 488 } 489 p.addSymmetricKeyToPool(keyid, topic, address, addToCache, false) 490 return keyid, nil 491 } 492 493 // Links a peer symmetric key (arbitrary byte sequence) to a topic 494 // 495 // This is required for symmetrically encrypted message exchange 496 // on the given topic 497 // 498 // The key is stored in the whisper backend. 499 // 500 // If addtocache is set to true, the key will be added to the cache of keys 501 // used to attempt symmetric decryption of incoming messages. 502 // 503 // Returns a string id that can be used to retrieve the key bytes 504 // from the whisper backend (see pss.GetSymmetricKey()) 505 func (p *Pss) SetSymmetricKey(key []byte, topic Topic, address *PssAddress, addtocache bool) (string, error) { 506 return p.setSymmetricKey(key, topic, address, addtocache, true) 507 } 508 509 func (p *Pss) setSymmetricKey(key []byte, topic Topic, address *PssAddress, addtocache bool, protected bool) (string, error) { 510 keyid, err := p.w.AddSymKeyDirect(key) 511 if err != nil { 512 return "", err 513 } 514 p.addSymmetricKeyToPool(keyid, topic, address, addtocache, protected) 515 return keyid, nil 516 } 517 518 // adds a symmetric key to the pss key pool, and optionally adds the key 519 // to the collection of keys used to attempt symmetric decryption of 520 // incoming messages 521 func (p *Pss) addSymmetricKeyToPool(keyid string, topic Topic, address *PssAddress, addtocache bool, protected bool) { 522 psp := &pssPeer{ 523 address: address, 524 protected: protected, 525 } 526 p.symKeyPoolMu.Lock() 527 if _, ok := p.symKeyPool[keyid]; !ok { 528 p.symKeyPool[keyid] = make(map[Topic]*pssPeer) 529 } 530 p.symKeyPool[keyid][topic] = psp 531 p.symKeyPoolMu.Unlock() 532 if addtocache { 533 p.symKeyDecryptCacheCursor++ 534 p.symKeyDecryptCache[p.symKeyDecryptCacheCursor%cap(p.symKeyDecryptCache)] = &keyid 535 } 536 key, _ := p.GetSymmetricKey(keyid) 537 log.Trace("added symkey", "symkeyid", keyid, "symkey", common.ToHex(key), "topic", topic, "address", fmt.Sprintf("%p", address), "cache", addtocache) 538 } 539 540 // Returns a symmetric key byte seqyence stored in the whisper backend 541 // by its unique id 542 // 543 // Passes on the error value from the whisper backend 544 func (p *Pss) GetSymmetricKey(symkeyid string) ([]byte, error) { 545 symkey, err := p.w.GetSymKey(symkeyid) 546 if err != nil { 547 return nil, err 548 } 549 return symkey, nil 550 } 551 552 // Returns all recorded topic and address combination for a specific public key 553 func (p *Pss) GetPublickeyPeers(keyid string) (topic []Topic, address []PssAddress, err error) { 554 p.pubKeyPoolMu.RLock() 555 defer p.pubKeyPoolMu.RUnlock() 556 for t, peer := range p.pubKeyPool[keyid] { 557 topic = append(topic, t) 558 address = append(address, *peer.address) 559 } 560 561 return topic, address, nil 562 } 563 564 func (p *Pss) getPeerAddress(keyid string, topic Topic) (PssAddress, error) { 565 p.pubKeyPoolMu.RLock() 566 defer p.pubKeyPoolMu.RUnlock() 567 if peers, ok := p.pubKeyPool[keyid]; ok { 568 if t, ok := peers[topic]; ok { 569 return *t.address, nil 570 } 571 } 572 return nil, fmt.Errorf("peer with pubkey %s, topic %x not found", keyid, topic) 573 } 574 575 // Attempt to decrypt, validate and unpack a 576 // symmetrically encrypted message 577 // If successful, returns the unpacked whisper ReceivedMessage struct 578 // encapsulating the decrypted message, and the whisper backend id 579 // of the symmetric key used to decrypt the message. 580 // It fails if decryption of the message fails or if the message is corrupted 581 func (p *Pss) processSym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) { 582 metrics.GetOrRegisterCounter("pss.process.sym", nil).Inc(1) 583 584 for i := p.symKeyDecryptCacheCursor; i > p.symKeyDecryptCacheCursor-cap(p.symKeyDecryptCache) && i > 0; i-- { 585 symkeyid := p.symKeyDecryptCache[i%cap(p.symKeyDecryptCache)] 586 symkey, err := p.w.GetSymKey(*symkeyid) 587 if err != nil { 588 continue 589 } 590 recvmsg, err := envelope.OpenSymmetric(symkey) 591 if err != nil { 592 continue 593 } 594 if !recvmsg.Validate() { 595 return nil, "", nil, fmt.Errorf("symmetrically encrypted message has invalid signature or is corrupt") 596 } 597 p.symKeyPoolMu.Lock() 598 from := p.symKeyPool[*symkeyid][Topic(envelope.Topic)].address 599 p.symKeyPoolMu.Unlock() 600 p.symKeyDecryptCacheCursor++ 601 p.symKeyDecryptCache[p.symKeyDecryptCacheCursor%cap(p.symKeyDecryptCache)] = symkeyid 602 return recvmsg, *symkeyid, from, nil 603 } 604 return nil, "", nil, fmt.Errorf("could not decrypt message") 605 } 606 607 // Attempt to decrypt, validate and unpack an 608 // asymmetrically encrypted message 609 // If successful, returns the unpacked whisper ReceivedMessage struct 610 // encapsulating the decrypted message, and the byte representation of 611 // the public key used to decrypt the message. 612 // It fails if decryption of message fails, or if the message is corrupted 613 func (p *Pss) processAsym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) { 614 metrics.GetOrRegisterCounter("pss.process.asym", nil).Inc(1) 615 616 recvmsg, err := envelope.OpenAsymmetric(p.privateKey) 617 if err != nil { 618 return nil, "", nil, fmt.Errorf("could not decrypt message: %s", err) 619 } 620 // check signature (if signed), strip padding 621 if !recvmsg.Validate() { 622 return nil, "", nil, fmt.Errorf("invalid message") 623 } 624 pubkeyid := common.ToHex(crypto.FromECDSAPub(recvmsg.Src)) 625 var from *PssAddress 626 p.pubKeyPoolMu.Lock() 627 if p.pubKeyPool[pubkeyid][Topic(envelope.Topic)] != nil { 628 from = p.pubKeyPool[pubkeyid][Topic(envelope.Topic)].address 629 } 630 p.pubKeyPoolMu.Unlock() 631 return recvmsg, pubkeyid, from, nil 632 } 633 634 // Symkey garbage collection 635 // a key is removed if: 636 // - it is not marked as protected 637 // - it is not in the incoming decryption cache 638 func (p *Pss) cleanKeys() (count int) { 639 for keyid, peertopics := range p.symKeyPool { 640 var expiredtopics []Topic 641 for topic, psp := range peertopics { 642 if psp.protected { 643 continue 644 } 645 646 var match bool 647 for i := p.symKeyDecryptCacheCursor; i > p.symKeyDecryptCacheCursor-cap(p.symKeyDecryptCache) && i > 0; i-- { 648 cacheid := p.symKeyDecryptCache[i%cap(p.symKeyDecryptCache)] 649 if *cacheid == keyid { 650 match = true 651 } 652 } 653 if !match { 654 expiredtopics = append(expiredtopics, topic) 655 } 656 } 657 for _, topic := range expiredtopics { 658 p.symKeyPoolMu.Lock() 659 delete(p.symKeyPool[keyid], topic) 660 log.Trace("symkey cleanup deletion", "symkeyid", keyid, "topic", topic, "val", p.symKeyPool[keyid]) 661 p.symKeyPoolMu.Unlock() 662 count++ 663 } 664 } 665 return 666 } 667 668 ///////////////////////////////////////////////////////////////////// 669 // SECTION: Message sending 670 ///////////////////////////////////////////////////////////////////// 671 672 func (p *Pss) enqueue(msg *PssMsg) error { 673 select { 674 case p.outbox <- msg: 675 return nil 676 default: 677 } 678 679 metrics.GetOrRegisterCounter("pss.enqueue.outbox.full", nil).Inc(1) 680 return errors.New("outbox full") 681 } 682 683 // Send a raw message (any encryption is responsibility of calling client) 684 // 685 // Will fail if raw messages are disallowed 686 func (p *Pss) SendRaw(address PssAddress, topic Topic, msg []byte) error { 687 if !p.allowRaw { 688 return errors.New("Raw messages not enabled") 689 } 690 pssMsgParams := &msgParams{ 691 raw: true, 692 } 693 payload := &whisper.Envelope{ 694 Data: msg, 695 Topic: whisper.TopicType(topic), 696 } 697 pssMsg := newPssMsg(pssMsgParams) 698 pssMsg.To = address 699 pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) 700 pssMsg.Payload = payload 701 p.addFwdCache(pssMsg) 702 return p.enqueue(pssMsg) 703 } 704 705 // Send a message using symmetric encryption 706 // 707 // Fails if the key id does not match any of the stored symmetric keys 708 func (p *Pss) SendSym(symkeyid string, topic Topic, msg []byte) error { 709 symkey, err := p.GetSymmetricKey(symkeyid) 710 if err != nil { 711 return fmt.Errorf("missing valid send symkey %s: %v", symkeyid, err) 712 } 713 p.symKeyPoolMu.Lock() 714 psp, ok := p.symKeyPool[symkeyid][topic] 715 p.symKeyPoolMu.Unlock() 716 if !ok { 717 return fmt.Errorf("invalid topic '%s' for symkey '%s'", topic.String(), symkeyid) 718 } else if psp.address == nil { 719 return fmt.Errorf("no address hint for topic '%s' symkey '%s'", topic.String(), symkeyid) 720 } 721 err = p.send(*psp.address, topic, msg, false, symkey) 722 return err 723 } 724 725 // Send a message using asymmetric encryption 726 // 727 // Fails if the key id does not match any in of the stored public keys 728 func (p *Pss) SendAsym(pubkeyid string, topic Topic, msg []byte) error { 729 if _, err := crypto.UnmarshalPubkey(common.FromHex(pubkeyid)); err != nil { 730 return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkeyid) 731 } 732 p.pubKeyPoolMu.Lock() 733 psp, ok := p.pubKeyPool[pubkeyid][topic] 734 p.pubKeyPoolMu.Unlock() 735 if !ok { 736 return fmt.Errorf("invalid topic '%s' for pubkey '%s'", topic.String(), pubkeyid) 737 } else if psp.address == nil { 738 return fmt.Errorf("no address hint for topic '%s' pubkey '%s'", topic.String(), pubkeyid) 739 } 740 go func() { 741 p.send(*psp.address, topic, msg, true, common.FromHex(pubkeyid)) 742 }() 743 return nil 744 } 745 746 // Send is payload agnostic, and will accept any byte slice as payload 747 // It generates an whisper envelope for the specified recipient and topic, 748 // and wraps the message payload in it. 749 // TODO: Implement proper message padding 750 func (p *Pss) send(to []byte, topic Topic, msg []byte, asymmetric bool, key []byte) error { 751 metrics.GetOrRegisterCounter("pss.send", nil).Inc(1) 752 753 if key == nil || bytes.Equal(key, []byte{}) { 754 return fmt.Errorf("Zero length key passed to pss send") 755 } 756 padding := make([]byte, p.paddingByteSize) 757 c, err := rand.Read(padding) 758 if err != nil { 759 return err 760 } else if c < p.paddingByteSize { 761 return fmt.Errorf("invalid padding length: %d", c) 762 } 763 wparams := &whisper.MessageParams{ 764 TTL: defaultWhisperTTL, 765 Src: p.privateKey, 766 Topic: whisper.TopicType(topic), 767 WorkTime: defaultWhisperWorkTime, 768 PoW: defaultWhisperPoW, 769 Payload: msg, 770 Padding: padding, 771 } 772 if asymmetric { 773 pk, err := crypto.UnmarshalPubkey(key) 774 if err != nil { 775 return fmt.Errorf("Cannot unmarshal pubkey: %x", key) 776 } 777 wparams.Dst = pk 778 } else { 779 wparams.KeySym = key 780 } 781 // set up outgoing message container, which does encryption and envelope wrapping 782 woutmsg, err := whisper.NewSentMessage(wparams) 783 if err != nil { 784 return fmt.Errorf("failed to generate whisper message encapsulation: %v", err) 785 } 786 // performs encryption. 787 // Does NOT perform / performs negligible PoW due to very low difficulty setting 788 // after this the message is ready for sending 789 envelope, err := woutmsg.Wrap(wparams) 790 if err != nil { 791 return fmt.Errorf("failed to perform whisper encryption: %v", err) 792 } 793 log.Trace("pssmsg whisper done", "env", envelope, "wparams payload", common.ToHex(wparams.Payload), "to", common.ToHex(to), "asym", asymmetric, "key", common.ToHex(key)) 794 795 // prepare for devp2p transport 796 pssMsgParams := &msgParams{ 797 sym: !asymmetric, 798 } 799 pssMsg := newPssMsg(pssMsgParams) 800 pssMsg.To = to 801 pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) 802 pssMsg.Payload = envelope 803 return p.enqueue(pssMsg) 804 } 805 806 // Forwards a pss message to the peer(s) closest to the to recipient address in the PssMsg struct 807 // The recipient address can be of any length, and the byte slice will be matched to the MSB slice 808 // of the peer address of the equivalent length. 809 func (p *Pss) forward(msg *PssMsg) error { 810 metrics.GetOrRegisterCounter("pss.forward", nil).Inc(1) 811 812 to := make([]byte, addressLength) 813 copy(to[:len(msg.To)], msg.To) 814 815 // send with kademlia 816 // find the closest peer to the recipient and attempt to send 817 sent := 0 818 p.Kademlia.EachConn(to, 256, func(sp *network.Peer, po int, isproxbin bool) bool { 819 info := sp.Info() 820 821 // check if the peer is running pss 822 var ispss bool 823 for _, cap := range info.Caps { 824 if cap == p.capstring { 825 ispss = true 826 break 827 } 828 } 829 if !ispss { 830 log.Trace("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps) 831 return true 832 } 833 834 // get the protocol peer from the forwarding peer cache 835 sendMsg := fmt.Sprintf("MSG TO %x FROM %x VIA %x", to, p.BaseAddr(), sp.Address()) 836 p.fwdPoolMu.RLock() 837 pp := p.fwdPool[sp.Info().ID] 838 p.fwdPoolMu.RUnlock() 839 840 // attempt to send the message 841 err := pp.Send(context.TODO(), msg) 842 if err != nil { 843 metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1) 844 log.Error(err.Error()) 845 return true 846 } 847 sent++ 848 log.Trace(fmt.Sprintf("%v: successfully forwarded", sendMsg)) 849 850 // continue forwarding if: 851 // - if the peer is end recipient but the full address has not been disclosed 852 // - if the peer address matches the partial address fully 853 // - if the peer is in proxbin 854 if len(msg.To) < addressLength && bytes.Equal(msg.To, sp.Address()[:len(msg.To)]) { 855 log.Trace(fmt.Sprintf("Pss keep forwarding: Partial address + full partial match")) 856 return true 857 } else if isproxbin { 858 log.Trace(fmt.Sprintf("%x is in proxbin, keep forwarding", common.ToHex(sp.Address()))) 859 return true 860 } 861 // at this point we stop forwarding, and the state is as follows: 862 // - the peer is end recipient and we have full address 863 // - we are not in proxbin (directed routing) 864 // - partial addresses don't fully match 865 return false 866 }) 867 868 if sent == 0 { 869 log.Debug("unable to forward to any peers") 870 if err := p.enqueue(msg); err != nil { 871 metrics.GetOrRegisterCounter("pss.forward.enqueue.error", nil).Inc(1) 872 log.Error(err.Error()) 873 return err 874 } 875 } 876 877 // cache the message 878 p.addFwdCache(msg) 879 return nil 880 } 881 882 ///////////////////////////////////////////////////////////////////// 883 // SECTION: Caching 884 ///////////////////////////////////////////////////////////////////// 885 886 // cleanFwdCache is used to periodically remove expired entries from the forward cache 887 func (p *Pss) cleanFwdCache() { 888 metrics.GetOrRegisterCounter("pss.cleanfwdcache", nil).Inc(1) 889 p.fwdCacheMu.Lock() 890 defer p.fwdCacheMu.Unlock() 891 for k, v := range p.fwdCache { 892 if v.expiresAt.Before(time.Now()) { 893 delete(p.fwdCache, k) 894 } 895 } 896 } 897 898 // add a message to the cache 899 func (p *Pss) addFwdCache(msg *PssMsg) error { 900 metrics.GetOrRegisterCounter("pss.addfwdcache", nil).Inc(1) 901 902 var entry pssCacheEntry 903 var ok bool 904 905 p.fwdCacheMu.Lock() 906 defer p.fwdCacheMu.Unlock() 907 908 digest := p.digest(msg) 909 if entry, ok = p.fwdCache[digest]; !ok { 910 entry = pssCacheEntry{} 911 } 912 entry.expiresAt = time.Now().Add(p.cacheTTL) 913 p.fwdCache[digest] = entry 914 return nil 915 } 916 917 // check if message is in the cache 918 func (p *Pss) checkFwdCache(msg *PssMsg) bool { 919 p.fwdCacheMu.Lock() 920 defer p.fwdCacheMu.Unlock() 921 922 digest := p.digest(msg) 923 entry, ok := p.fwdCache[digest] 924 if ok { 925 if entry.expiresAt.After(time.Now()) { 926 log.Trace("unexpired cache", "digest", fmt.Sprintf("%x", digest)) 927 metrics.GetOrRegisterCounter("pss.checkfwdcache.unexpired", nil).Inc(1) 928 return true 929 } 930 metrics.GetOrRegisterCounter("pss.checkfwdcache.expired", nil).Inc(1) 931 } 932 return false 933 } 934 935 // Digest of message 936 func (p *Pss) digest(msg *PssMsg) pssDigest { 937 hasher := p.hashPool.Get().(storage.SwarmHash) 938 defer p.hashPool.Put(hasher) 939 hasher.Reset() 940 hasher.Write(msg.serialize()) 941 digest := pssDigest{} 942 key := hasher.Sum(nil) 943 copy(digest[:], key[:digestLength]) 944 return digest 945 }