// Resolve implements Resolver. Uses the IPFS routing system to resolve SFS-like // names. func (r *routingResolver) Resolve(name string) (string, error) { log.Debugf("RoutingResolve: '%s'", name) ctx := context.TODO() hash, err := mh.FromB58String(name) if err != nil { log.Warning("RoutingResolve: bad input hash: [%s]\n", name) return "", err } // name should be a multihash. if it isn't, error out here. // use the routing system to get the name. // /ipns/<name> h := []byte("/ipns/" + string(hash)) ipnsKey := u.Key(h) val, err := r.routing.GetValue(ctx, ipnsKey) if err != nil { log.Warning("RoutingResolve get failed.") return "", err } entry := new(pb.IpnsEntry) err = proto.Unmarshal(val, entry) if err != nil { return "", err } // name should be a public key retrievable from ipfs // /ipfs/<name> key := u.Key("/pk/" + string(hash)) pkval, err := r.routing.GetValue(ctx, key) if err != nil { log.Warning("RoutingResolve PubKey Get failed.") return "", err } // get PublicKey from node.Data pk, err := ci.UnmarshalPublicKey(pkval) if err != nil { return "", err } hsh, _ := pk.Hash() log.Debugf("pk hash = %s", u.Key(hsh)) // check sig with pk if ok, err := pk.Verify(ipnsEntryDataForSig(entry), entry.GetSignature()); err != nil || !ok { return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pk) } // ok sig checks out. this is a valid name. return string(entry.GetValue()), nil }
func (dht *IpfsDHT) getPublicKey(pid peer.ID) (ci.PubKey, error) { log.Debug("getPublicKey for: %s", pid) p, err := dht.peerstore.Get(pid) if err == nil { return p.PubKey(), nil } log.Debug("not in peerstore, searching dht.") ctxT, _ := context.WithTimeout(dht.ContextCloser.Context(), time.Second*5) val, err := dht.GetValue(ctxT, u.Key("/pk/"+string(pid))) if err != nil { log.Warning("Failed to find requested public key.") return nil, err } pubkey, err := ci.UnmarshalPublicKey(val) if err != nil { log.Errorf("Failed to unmarshal public key: %s", err) return nil, err } return pubkey, nil }
// handsahke performs initial communication over insecure channel to share // keys, IDs, and initiate communication. func (s *SecurePipe) handshake() error { // Generate and send Hello packet. // Hello = (rand, PublicKey, Supported) nonce := make([]byte, 16) _, err := rand.Read(nonce) if err != nil { return err } log.Debugf("handshake: %s <--> %s", s.local, s.remote) myPubKey, err := s.local.PubKey().Bytes() if err != nil { return err } proposeMsg := new(pb.Propose) proposeMsg.Rand = nonce proposeMsg.Pubkey = myPubKey proposeMsg.Exchanges = &SupportedExchanges proposeMsg.Ciphers = &SupportedCiphers proposeMsg.Hashes = &SupportedHashes encoded, err := proto.Marshal(proposeMsg) if err != nil { return err } // Send our Propose packet select { case s.insecure.Out <- encoded: case <-s.ctx.Done(): return ErrClosed } // Parse their Propose packet and generate an Exchange packet. // Exchange = (EphemeralPubKey, Signature) var resp []byte select { case <-s.ctx.Done(): return ErrClosed case resp = <-s.insecure.In: } // u.POut("received encoded handshake\n") proposeResp := new(pb.Propose) err = proto.Unmarshal(resp, proposeResp) if err != nil { return err } // get remote identity remotePubKey, err := ci.UnmarshalPublicKey(proposeResp.GetPubkey()) if err != nil { return err } // get or construct peer s.remote, err = getOrConstructPeer(s.peers, remotePubKey) if err != nil { return err } log.Debugf("%s Remote Peer Identified as %s", s.local, s.remote) exchange, err := SelectBest(SupportedExchanges, proposeResp.GetExchanges()) if err != nil { return err } cipherType, err := SelectBest(SupportedCiphers, proposeResp.GetCiphers()) if err != nil { return err } hashType, err := SelectBest(SupportedHashes, proposeResp.GetHashes()) if err != nil { return err } // u.POut("Selected %s %s %s\n", exchange, cipherType, hashType) epubkey, genSharedKey, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey var handshake bytes.Buffer // Gather corpus to sign. handshake.Write(encoded) handshake.Write(resp) handshake.Write(epubkey) exPacket := new(pb.Exchange) exPacket.Epubkey = epubkey exPacket.Signature, err = s.local.PrivKey().Sign(handshake.Bytes()) if err != nil { return err } exEncoded, err := proto.Marshal(exPacket) // send out Exchange packet select { case s.insecure.Out <- exEncoded: case <-s.ctx.Done(): return ErrClosed } // Parse their Exchange packet and generate a Finish packet. // Finish = E('Finish') var resp1 []byte select { case <-s.ctx.Done(): return ErrClosed case resp1 = <-s.insecure.In: } exchangeResp := new(pb.Exchange) err = proto.Unmarshal(resp1, exchangeResp) if err != nil { return err } var theirHandshake bytes.Buffer theirHandshake.Write(resp) theirHandshake.Write(encoded) theirHandshake.Write(exchangeResp.GetEpubkey()) // u.POut("Remote Peer Identified as %s\n", s.remote) ok, err := s.remote.PubKey().Verify(theirHandshake.Bytes(), exchangeResp.GetSignature()) if err != nil { return err } if !ok { return errors.New("Bad signature!") } secret, err := genSharedKey(exchangeResp.GetEpubkey()) if err != nil { return err } cmp := bytes.Compare(myPubKey, proposeResp.GetPubkey()) mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret) go s.handleSecureIn(hashType, cipherType, tIV, tCKey, tMKey) go s.handleSecureOut(hashType, cipherType, mIV, mCKey, mMKey) finished := []byte("Finished") // send finished msg select { case <-s.ctx.Done(): return ErrClosed case s.Out <- finished: } // recv finished msg var resp2 []byte select { case <-s.ctx.Done(): return ErrClosed case resp2 = <-s.In: } if bytes.Compare(resp2, finished) != 0 { return fmt.Errorf("Negotiation failed, got: %s", resp2) } log.Debugf("%s handshake: Got node id: %s", s.local, s.remote) return nil }