117 lines
3.8 KiB
Go
117 lines
3.8 KiB
Go
package noise
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
|
|
"github.com/libp2p/go-libp2p-core/crypto"
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
"github.com/libp2p/go-libp2p-core/sec"
|
|
)
|
|
|
|
// ID is the protocol ID for noise
|
|
const ID = "/noise"
|
|
|
|
var _ sec.SecureTransport = &Transport{}
|
|
|
|
// Transport implements the interface sec.SecureTransport
|
|
// https://godoc.org/github.com/libp2p/go-libp2p-core/sec#SecureConn
|
|
type Transport struct {
|
|
localID peer.ID
|
|
privateKey crypto.PrivKey
|
|
noisePipesSupport bool
|
|
noiseStaticKeyCache *KeyCache
|
|
noiseKeypair *Keypair
|
|
}
|
|
|
|
type transportConstructor func(crypto.PrivKey) (*Transport, error)
|
|
|
|
// Maker returns a function that will construct a new Noise transport
|
|
// using the given Options. The returned function may be provided as a libp2p.Security
|
|
// option when configuring a libp2p Host using libp2p.New, and is compatible with the
|
|
// "reflection magic" that libp2p.New uses to inject the private identity key:
|
|
//
|
|
// host := libp2p.New(
|
|
// libp2p.Security(noise.ID, noise.Maker()))
|
|
//
|
|
// The transport can be configured by passing in Options.
|
|
//
|
|
// To enable the Noise Pipes pattern (which can be more efficient when reconnecting
|
|
// to a known peer), pass in the UseNoisePipes Option:
|
|
//
|
|
// Maker(UseNoisePipes)
|
|
//
|
|
// To use a specific Noise keypair, pass in the NoiseKeyPair(kp) option, where
|
|
// kp is a noise.Keypair struct. This is most useful when using Noise Pipes, whose
|
|
// efficiency gains rely on the static Noise key being known in advance. Persisting
|
|
// the Noise keypair across process restarts makes it more likely that other peers
|
|
// will be able to use the more efficient IK handshake pattern.
|
|
//
|
|
// Maker(UseNoisePipes, NoiseKeypair(keypairLoadedFromDisk))
|
|
func Maker(options ...Option) transportConstructor {
|
|
return func(privKey crypto.PrivKey) (*Transport, error) {
|
|
return New(privKey, options...)
|
|
}
|
|
}
|
|
|
|
// New creates a new Noise transport using the given private key as its
|
|
// libp2p identity key. This function may be used when you want a transport
|
|
// instance and know the libp2p Host's identity key before the Host is initialized.
|
|
// When configuring a go-libp2p Host using libp2p.New, it's simpler to use
|
|
// Maker instead, which will receive the identity key when the Host
|
|
// is initialized.
|
|
//
|
|
// New supports all the same Options as noise.Maker.
|
|
//
|
|
// To configure a go-libp2p Host to use the newly created transport, pass it into
|
|
// libp2p.New wrapped in a libp2p.Security Option. You will also need to
|
|
// make sure to set the libp2p.Identity option so that the Host uses the same
|
|
// identity key:
|
|
//
|
|
// privkey := loadPrivateKeyFromSomewhere()
|
|
// noiseTpt := noise.New(privkey)
|
|
// host := libp2p.New(
|
|
// libp2p.Identity(privkey),
|
|
// libp2p.Security(noise.ID, noiseTpt))
|
|
func New(privkey crypto.PrivKey, options ...Option) (*Transport, error) {
|
|
localID, err := peer.IDFromPrivateKey(privkey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cfg := config{}
|
|
cfg.applyOptions(options...)
|
|
|
|
kp := cfg.noiseKeypair
|
|
if kp == nil {
|
|
kp, err = GenerateKeypair()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// the static key cache is only useful if Noise Pipes is enabled
|
|
var keyCache *KeyCache
|
|
if cfg.noisePipesSupport {
|
|
keyCache = NewKeyCache()
|
|
}
|
|
|
|
return &Transport{
|
|
localID: localID,
|
|
privateKey: privkey,
|
|
noisePipesSupport: cfg.noisePipesSupport,
|
|
noiseKeypair: kp,
|
|
noiseStaticKeyCache: keyCache,
|
|
}, nil
|
|
}
|
|
|
|
// SecureInbound runs noise handshake as the responder
|
|
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
|
|
return newSecureSession(t, ctx, insecure, "", false)
|
|
}
|
|
|
|
// SecureOutbound runs noise handshake as the initiator
|
|
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
|
return newSecureSession(t, ctx, insecure, p, true)
|
|
}
|