func GetPublicKey(r IpfsRouting, ctx context.Context, pkhash []byte) (ci.PubKey, error) { if dht, ok := r.(PubKeyFetcher); ok { // If we have a DHT as our routing system, use optimized fetcher return dht.GetPublicKey(ctx, peer.ID(pkhash)) } else { key := key.Key("/pk/" + string(pkhash)) pkval, err := r.GetValue(ctx, key) if err != nil { return nil, err } // get PublicKey from node.Data return ci.UnmarshalPublicKey(pkval) } }
func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.PubKey, error) { // check locally, just in case... pk := dht.peerstore.PubKey(p) if pk != nil { return pk, nil } pkkey := routing.KeyForPublicKey(p) pmes, err := dht.getValueSingle(ctx, p, pkkey) if err != nil { return nil, err } // node doesn't have key :( record := pmes.GetRecord() if record == nil { return nil, fmt.Errorf("Node not responding with its public key: %s", p) } // Success! We were given the value. we don't need to check // validity because a) we can't. b) we know the hash of the // key we're looking for. val := record.GetValue() log.Debug("DHT got a value from other peer") pk, err = ci.UnmarshalPublicKey(val) if err != nil { return nil, err } id, err := peer.IDFromPublicKey(pk) if err != nil { return nil, err } if id != p { return nil, fmt.Errorf("public key does not match id: %s", p) } // ok! it's valid. we got it! log.Debugf("DHT got public key from node itself.") return pk, nil }
func (dht *IpfsDHT) GetPublicKey(ctx context.Context, p peer.ID) (ci.PubKey, error) { log.Debugf("getPublicKey for: %s", p) // check locally. pk := dht.peerstore.PubKey(p) if pk != nil { return pk, nil } // ok, try the node itself. if they're overwhelmed or slow we can move on. ctxT, cancelFunc := ctxfrac.WithDeadlineFraction(ctx, 0.3) defer cancelFunc() if pk, err := dht.getPublicKeyFromNode(ctx, p); err == nil { err := dht.peerstore.AddPubKey(p, pk) if err != nil { return pk, err } return pk, nil } // last ditch effort: let's try the dht. log.Debugf("pk for %s not in peerstore, and peer failed. Trying DHT.", p) pkkey := routing.KeyForPublicKey(p) val, err := dht.GetValue(ctxT, pkkey) if err != nil { log.Warning("Failed to find requested public key.") return nil, err } pk, err = ci.UnmarshalPublicKey(val) if err != nil { log.Debugf("Failed to unmarshal public key: %s", err) return nil, err } return pk, dht.peerstore.AddPubKey(p, pk) }
func TestValidatePublicKey(t *testing.T) { pkb, err := base64.StdEncoding.DecodeString(OffensiveKey) if err != nil { t.Fatal(err) } pubk, err := ci.UnmarshalPublicKey(pkb) if err != nil { t.Fatal(err) } pkh, err := pubk.Hash() if err != nil { t.Fatal(err) } k := key.Key("/pk/" + string(pkh)) err = ValidatePublicKeyRecord(k, pkb) if err != nil { t.Fatal(err) } }