Merge pull request #652 from yggdrasil-network/neilalexander/api

Use public keys in API functions
This commit is contained in:
Neil Alexander 2020-02-17 00:00:08 +00:00 committed by GitHub
commit 0b26551f07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 21 deletions

View File

@ -194,6 +194,16 @@ type BoxSharedKey [BoxSharedKeyLen]byte
// BoxNonce is the nonce used in NaCl-like crypto "box" operations (curve25519+xsalsa20+poly1305), and must not be reused for different messages encrypted using the same BoxSharedKey. // BoxNonce is the nonce used in NaCl-like crypto "box" operations (curve25519+xsalsa20+poly1305), and must not be reused for different messages encrypted using the same BoxSharedKey.
type BoxNonce [BoxNonceLen]byte type BoxNonce [BoxNonceLen]byte
// String returns a string representation of the "box" key.
func (k BoxPubKey) String() string {
return hex.EncodeToString(k[:])
}
// Network returns "curve25519" for "box" keys.
func (n BoxPubKey) Network() string {
return "curve25519"
}
// NewBoxKeys generates a new pair of public/private crypto box keys. // NewBoxKeys generates a new pair of public/private crypto box keys.
func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) { func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) {
pubBytes, privBytes, err := box.GenerateKey(rand.Reader) pubBytes, privBytes, err := box.GenerateKey(rand.Reader)

View File

@ -92,8 +92,7 @@ func (s *tunConn) _read(bs []byte) (err error) {
// The destination address isn't in our CKR allowed range // The destination address isn't in our CKR allowed range
skip = true skip = true
} else if key, err := s.tun.ckr.getPublicKeyForAddress(srcAddr, addrlen); err == nil { } else if key, err := s.tun.ckr.getPublicKeyForAddress(srcAddr, addrlen); err == nil {
srcNodeID := crypto.GetNodeID(&key) if *s.conn.RemoteAddr().(*crypto.BoxPubKey) == key {
if *s.conn.RemoteAddr().(*crypto.NodeID) == *srcNodeID {
// This is the one allowed CKR case, where source and destination addresses are both good // This is the one allowed CKR case, where source and destination addresses are both good
} else { } else {
// The CKR key associated with this address doesn't match the sender's NodeID // The CKR key associated with this address doesn't match the sender's NodeID
@ -169,8 +168,7 @@ func (s *tunConn) _write(bs []byte) (err error) {
// The source address isn't in our CKR allowed range // The source address isn't in our CKR allowed range
skip = true skip = true
} else if key, err := s.tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil { } else if key, err := s.tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
dstNodeID := crypto.GetNodeID(&key) if *s.conn.RemoteAddr().(*crypto.BoxPubKey) == key {
if *s.conn.RemoteAddr().(*crypto.NodeID) == *dstNodeID {
// This is the one allowed CKR case, where source and destination addresses are both good // This is the one allowed CKR case, where source and destination addresses are both good
} else { } else {
// The CKR key associated with this address doesn't match the sender's NodeID // The CKR key associated with this address doesn't match the sender's NodeID

View File

@ -251,7 +251,8 @@ func (tun *TunAdapter) _wrap(conn *yggdrasil.Conn) (c *tunConn, err error) {
} }
c = &s c = &s
// Get the remote address and subnet of the other side // Get the remote address and subnet of the other side
remoteNodeID := conn.RemoteAddr().(*crypto.NodeID) remotePubKey := conn.RemoteAddr().(*crypto.BoxPubKey)
remoteNodeID := crypto.GetNodeID(remotePubKey)
s.addr = *address.AddrForNodeID(remoteNodeID) s.addr = *address.AddrForNodeID(remoteNodeID)
s.snet = *address.SubnetForNodeID(remoteNodeID) s.snet = *address.SubnetForNodeID(remoteNodeID)
// Work out if this is already a destination we already know about // Work out if this is already a destination we already know about

View File

@ -350,16 +350,19 @@ func (c *Conn) Close() (err error) {
return return
} }
// LocalAddr returns the complete node ID of the local side of the connection. // LocalAddr returns the complete public key of the local side of the
// This is always going to return your own node's node ID. // connection. This is always going to return your own node's public key.
func (c *Conn) LocalAddr() net.Addr { func (c *Conn) LocalAddr() net.Addr {
return crypto.GetNodeID(&c.core.boxPub) return &c.core.boxPub
} }
// RemoteAddr returns the complete node ID of the remote side of the connection. // RemoteAddr returns the complete public key of the remote side of the
// connection.
func (c *Conn) RemoteAddr() net.Addr { func (c *Conn) RemoteAddr() net.Addr {
// RemoteAddr is set during the dial or accept, and isn't changed, so it's safe to access directly if c.session != nil {
return c.nodeID return &c.session.theirPermPub
}
return nil
} }
// SetDeadline is equivalent to calling both SetReadDeadline and // SetDeadline is equivalent to calling both SetReadDeadline and

View File

@ -17,19 +17,32 @@ type Dialer struct {
core *Core core *Core
} }
// Dial opens a session to the given node. The first parameter should be "nodeid" // Dial opens a session to the given node. The first parameter should be
// and the second parameter should contain a hexadecimal representation of the // "curve25519" or "nodeid" and the second parameter should contain a
// target node ID. It uses DialContext internally. // hexadecimal representation of the target. It uses DialContext internally.
func (d *Dialer) Dial(network, address string) (net.Conn, error) { func (d *Dialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(nil, network, address) return d.DialContext(nil, network, address)
} }
// DialContext is used internally by Dial, and should only be used with a context that includes a timeout. It uses DialByNodeIDandMask internally. // DialContext is used internally by Dial, and should only be used with a
// context that includes a timeout. It uses DialByNodeIDandMask internally when
// the network is "nodeid", or DialByPublicKey when the network is "curve25519".
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
var nodeID crypto.NodeID var nodeID crypto.NodeID
var nodeMask crypto.NodeID var nodeMask crypto.NodeID
// Process // Process
switch network { switch network {
case "curve25519":
dest, err := hex.DecodeString(address)
if err != nil {
return nil, err
}
if len(dest) != crypto.BoxPubKeyLen {
return nil, errors.New("invalid key length supplied")
}
var pubKey crypto.BoxPubKey
copy(pubKey[:], dest)
return d.DialByPublicKey(ctx, &pubKey)
case "nodeid": case "nodeid":
// A node ID was provided - we don't need to do anything special with it // A node ID was provided - we don't need to do anything special with it
if tokens := strings.Split(address, "/"); len(tokens) == 2 { if tokens := strings.Split(address, "/"); len(tokens) == 2 {
@ -62,8 +75,9 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.
} }
} }
// DialByNodeIDandMask opens a session to the given node based on raw // DialByNodeIDandMask opens a session to the given node based on raw NodeID
// NodeID parameters. If ctx is nil or has no timeout, then a default timeout of 6 seconds will apply, beginning *after* the search finishes. // parameters. If ctx is nil or has no timeout, then a default timeout of 6
// seconds will apply, beginning *after* the search finishes.
func (d *Dialer) DialByNodeIDandMask(ctx context.Context, nodeID, nodeMask *crypto.NodeID) (net.Conn, error) { func (d *Dialer) DialByNodeIDandMask(ctx context.Context, nodeID, nodeMask *crypto.NodeID) (net.Conn, error) {
startDial := time.Now() startDial := time.Now()
conn := newConn(d.core, nodeID, nodeMask, nil) conn := newConn(d.core, nodeID, nodeMask, nil)
@ -92,3 +106,15 @@ func (d *Dialer) DialByNodeIDandMask(ctx context.Context, nodeID, nodeMask *cryp
return nil, errors.New("session handshake timeout") return nil, errors.New("session handshake timeout")
} }
} }
// DialByPublicKey opens a session to the given node based on the public key. If
// ctx is nil or has no timeout, then a default timeout of 6 seconds will apply,
// beginning *after* the search finishes.
func (d *Dialer) DialByPublicKey(ctx context.Context, pubKey *crypto.BoxPubKey) (net.Conn, error) {
nodeID := crypto.GetNodeID(pubKey)
var nodeMask crypto.NodeID
for i := range nodeMask {
nodeMask[i] = 0xFF
}
return d.DialByNodeIDandMask(ctx, nodeID, &nodeMask)
}

View File

@ -113,9 +113,9 @@ a Dialer:
// ... // ...
} }
You can then dial using the 16-byte node ID in hexadecimal format, for example: You can then dial using the node's public key in hexadecimal format, for example:
conn, err := dialer.Dial("nodeid", "24a58cfce691ec016b0f698f7be1bee983cea263781017e99ad3ef62b4ef710a45d6c1a072c5ce46131bd574b78818c9957042cafeeed13966f349e94eb771bf") conn, err := dialer.Dial("curve25519", "55071be281f50d0abbda63aadc59755624280c44b2f1f47684317aa4e0325604")
if err != nil { if err != nil {
// ... // ...
} }

View File

@ -39,7 +39,7 @@ func (l *Listener) Close() (err error) {
return nil return nil
} }
// Addr is not implemented for this type yet // Addr returns the address of the listener
func (l *Listener) Addr() net.Addr { func (l *Listener) Addr() net.Addr {
return nil return &l.core.boxPub
} }