Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
G
go-ipfs
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
jihao
go-ipfs
Commits
414ab636
提交
414ab636
authored
5月 12, 2015
作者:
Juan Batiz-Benet
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1227 from ipfs/parallelize-handshake
net/p2p + secio: parallelize crypto handshake
上级
0c8a0975
b84fa2b4
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
157 行增加
和
55 行删除
+157
-55
interface.go
p2p/crypto/secio/interface.go
+52
-19
protocol.go
p2p/crypto/secio/protocol.go
+42
-8
dial_test.go
p2p/net/conn/dial_test.go
+40
-3
secure_conn.go
p2p/net/conn/secure_conn.go
+14
-25
secure_conn_test.go
p2p/net/conn/secure_conn_test.go
+9
-0
没有找到文件。
p2p/crypto/secio/interface.go
浏览文件 @
414ab636
...
...
@@ -17,28 +17,13 @@ type SessionGenerator struct {
PrivateKey
ci
.
PrivKey
}
// NewSession takes an insecure io.ReadWriter,
performs
a TLS-like
// NewSession takes an insecure io.ReadWriter,
sets up
a TLS-like
// handshake with the other side, and returns a secure session.
// The handshake isn't run until the connection is read or written to.
// See the source for the protocol details and security implementation.
// The provided Context is only needed for the duration of this function.
func
(
sg
*
SessionGenerator
)
NewSession
(
ctx
context
.
Context
,
insecure
io
.
ReadWriter
)
(
Session
,
error
)
{
ss
,
err
:=
newSecureSession
(
sg
.
LocalID
,
sg
.
PrivateKey
)
if
err
!=
nil
{
return
nil
,
err
}
if
ctx
==
nil
{
ctx
=
context
.
Background
()
}
ctx
,
cancel
:=
context
.
WithCancel
(
ctx
)
if
err
:=
ss
.
handshake
(
ctx
,
insecure
);
err
!=
nil
{
cancel
()
return
nil
,
err
}
return
ss
,
nil
func
(
sg
*
SessionGenerator
)
NewSession
(
ctx
context
.
Context
,
insecure
io
.
ReadWriteCloser
)
(
Session
,
error
)
{
return
newSecureSession
(
ctx
,
sg
.
LocalID
,
sg
.
PrivateKey
,
insecure
)
}
type
Session
interface
{
...
...
@@ -64,6 +49,9 @@ type Session interface {
// SecureReadWriter returns the encrypted communication channel
func
(
s
*
secureSession
)
ReadWriter
()
msgio
.
ReadWriteCloser
{
if
err
:=
s
.
Handshake
();
err
!=
nil
{
return
&
closedRW
{
err
}
}
return
s
.
secure
}
...
...
@@ -79,15 +67,60 @@ func (s *secureSession) LocalPrivateKey() ci.PrivKey {
// RemotePeer retrieves the remote peer.
func
(
s
*
secureSession
)
RemotePeer
()
peer
.
ID
{
if
err
:=
s
.
Handshake
();
err
!=
nil
{
return
""
}
return
s
.
remotePeer
}
// RemotePeer retrieves the remote peer.
func
(
s
*
secureSession
)
RemotePublicKey
()
ci
.
PubKey
{
if
err
:=
s
.
Handshake
();
err
!=
nil
{
return
nil
}
return
s
.
remote
.
permanentPubKey
}
// Close closes the secure session
func
(
s
*
secureSession
)
Close
()
error
{
s
.
cancel
()
s
.
handshakeMu
.
Lock
()
defer
s
.
handshakeMu
.
Unlock
()
if
s
.
secure
==
nil
{
return
s
.
insecure
.
Close
()
// hadn't secured yet.
}
return
s
.
secure
.
Close
()
}
// closedRW implements a stub msgio interface that's already
// closed and errored.
type
closedRW
struct
{
err
error
}
func
(
c
*
closedRW
)
Read
(
buf
[]
byte
)
(
int
,
error
)
{
return
0
,
c
.
err
}
func
(
c
*
closedRW
)
Write
(
buf
[]
byte
)
(
int
,
error
)
{
return
0
,
c
.
err
}
func
(
c
*
closedRW
)
NextMsgLen
()
(
int
,
error
)
{
return
0
,
c
.
err
}
func
(
c
*
closedRW
)
ReadMsg
()
([]
byte
,
error
)
{
return
nil
,
c
.
err
}
func
(
c
*
closedRW
)
WriteMsg
(
buf
[]
byte
)
error
{
return
c
.
err
}
func
(
c
*
closedRW
)
Close
()
error
{
return
c
.
err
}
func
(
c
*
closedRW
)
ReleaseMsg
(
m
[]
byte
)
{
}
p2p/crypto/secio/protocol.go
浏览文件 @
414ab636
...
...
@@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"io"
"sync"
"time"
msgio
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
context
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
...
...
@@ -27,15 +29,23 @@ var ErrClosed = errors.New("connection closed")
// ErrEcho is returned when we're attempting to handshake with the same keys and nonces.
var
ErrEcho
=
errors
.
New
(
"same keys and nonces. one side talking to self."
)
// HandshakeTimeout governs how long the handshake will be allowed to take place for.
// Making this number large means there could be many bogus connections waiting to
// timeout in flight. Typical handshakes take ~3RTTs, so it should be completed within
// seconds across a typical planet in the solar system.
var
HandshakeTimeout
=
time
.
Second
*
30
// nonceSize is the size of our nonces (in bytes)
const
nonceSize
=
16
// secureSession encapsulates all the parameters needed for encrypting
// and decrypting traffic from an insecure channel.
type
secureSession
struct
{
secure
msgio
.
ReadWriteCloser
ctx
context
.
Context
cancel
context
.
CancelFunc
insecure
io
.
ReadWriter
secure
msgio
.
ReadWriteCloser
insecure
io
.
ReadWriteCloser
insecureM
msgio
.
ReadWriter
localKey
ci
.
PrivKey
...
...
@@ -46,6 +56,10 @@ type secureSession struct {
remote
encParams
sharedSecret
[]
byte
handshakeMu
sync
.
Mutex
// guards handshakeDone + handshakeErr
handshakeDone
bool
handshakeErr
error
}
func
(
s
*
secureSession
)
Loggable
()
map
[
string
]
interface
{}
{
...
...
@@ -56,8 +70,9 @@ func (s *secureSession) Loggable() map[string]interface{} {
return
m
}
func
newSecureSession
(
local
peer
.
ID
,
key
ci
.
PrivKey
)
(
*
secureSession
,
error
)
{
func
newSecureSession
(
ctx
context
.
Context
,
local
peer
.
ID
,
key
ci
.
PrivKey
,
insecure
io
.
ReadWriteCloser
)
(
*
secureSession
,
error
)
{
s
:=
&
secureSession
{
localPeer
:
local
,
localKey
:
key
}
s
.
ctx
,
s
.
cancel
=
context
.
WithCancel
(
ctx
)
switch
{
case
s
.
localPeer
==
""
:
...
...
@@ -66,18 +81,37 @@ func newSecureSession(local peer.ID, key ci.PrivKey) (*secureSession, error) {
return
nil
,
errors
.
New
(
"no local private key provided"
)
case
!
s
.
localPeer
.
MatchesPrivateKey
(
s
.
localKey
)
:
return
nil
,
fmt
.
Errorf
(
"peer.ID does not match PrivateKey"
)
case
insecure
==
nil
:
return
nil
,
fmt
.
Errorf
(
"insecure ReadWriter is nil"
)
}
s
.
ctx
=
ctx
s
.
insecure
=
insecure
s
.
insecureM
=
msgio
.
NewReadWriter
(
insecure
)
return
s
,
nil
}
// handsahke performs initial communication over insecure channel to share
func
(
s
*
secureSession
)
Handshake
()
error
{
s
.
handshakeMu
.
Lock
()
defer
s
.
handshakeMu
.
Unlock
()
if
s
.
handshakeErr
!=
nil
{
return
s
.
handshakeErr
}
if
!
s
.
handshakeDone
{
s
.
handshakeErr
=
s
.
runHandshake
()
s
.
handshakeDone
=
true
}
return
s
.
handshakeErr
}
// runHandshake performs initial communication over insecure channel to share
// keys, IDs, and initiate communication, assigning all necessary params.
// requires the duplex channel to be a msgio.ReadWriter (for framed messaging)
func
(
s
*
secureSession
)
handshake
(
ctx
context
.
Context
,
insecure
io
.
ReadWriter
)
error
{
s
.
insecure
=
insecure
s
.
insecureM
=
msgio
.
NewReadWriter
(
insecure
)
func
(
s
*
secureSession
)
runHandshake
()
error
{
ctx
,
cancel
:=
context
.
WithTimeout
(
s
.
ctx
,
HandshakeTimeout
)
// remove
defer
cancel
()
// =============================================================================
// step 1. Propose -- propose cipher suite + send pubkeys + nonce
...
...
p2p/net/conn/dial_test.go
浏览文件 @
414ab636
...
...
@@ -75,18 +75,35 @@ func setupConn(t *testing.T, ctx context.Context, secure bool) (a, b Conn, p1, p
done
:=
make
(
chan
error
)
go
func
()
{
defer
close
(
done
)
var
err
error
c2
,
err
=
d2
.
Dial
(
ctx
,
p1
.
Addr
,
p1
.
ID
)
if
err
!=
nil
{
done
<-
err
return
}
// if secure, need to read + write, as that's what triggers the handshake.
if
secure
{
if
err
:=
sayHello
(
c2
);
err
!=
nil
{
done
<-
err
}
}
close
(
done
)
}()
c1
,
err
:=
l1
.
Accept
()
if
err
!=
nil
{
t
.
Fatal
(
"failed to accept"
,
err
)
}
// if secure, need to read + write, as that's what triggers the handshake.
if
secure
{
if
err
:=
sayHello
(
c1
);
err
!=
nil
{
done
<-
err
}
}
if
err
:=
<-
done
;
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
@@ -94,6 +111,20 @@ func setupConn(t *testing.T, ctx context.Context, secure bool) (a, b Conn, p1, p
return
c1
.
(
Conn
),
c2
,
p1
,
p2
}
func
sayHello
(
c
net
.
Conn
)
error
{
h
:=
[]
byte
(
"hello"
)
if
_
,
err
:=
c
.
Write
(
h
);
err
!=
nil
{
return
err
}
if
_
,
err
:=
c
.
Read
(
h
);
err
!=
nil
{
return
err
}
if
string
(
h
)
!=
"hello"
{
return
fmt
.
Errorf
(
"did not get hello"
)
}
return
nil
}
func
testDialer
(
t
*
testing
.
T
,
secure
bool
)
{
// t.Skip("Skipping in favor of another test")
...
...
@@ -203,7 +234,7 @@ func testDialerCloseEarly(t *testing.T, secure bool) {
go
func
()
{
defer
func
()
{
done
<-
struct
{}{}
}()
_
,
err
:=
l1
.
Accept
()
c
,
err
:=
l1
.
Accept
()
if
err
!=
nil
{
if
strings
.
Contains
(
err
.
Error
(),
"closed"
)
{
gotclosed
<-
struct
{}{}
...
...
@@ -211,7 +242,13 @@ func testDialerCloseEarly(t *testing.T, secure bool) {
}
errs
<-
err
}
errs
<-
fmt
.
Errorf
(
"got conn"
)
if
_
,
err
:=
c
.
Write
([]
byte
(
"hello"
));
err
!=
nil
{
gotclosed
<-
struct
{}{}
return
}
errs
<-
fmt
.
Errorf
(
"wrote to conn"
)
}()
c
,
err
:=
d2
.
Dial
(
ctx
,
p1
.
Addr
,
p1
.
ID
)
...
...
p2p/net/conn/secure_conn.go
浏览文件 @
414ab636
...
...
@@ -5,7 +5,6 @@ import (
"net"
"time"
msgio
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
ma
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
context
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
...
...
@@ -16,15 +15,8 @@ import (
// secureConn wraps another Conn object with an encrypted channel.
type
secureConn
struct
{
// the wrapped conn
insecure
Conn
// secure io (wrapping insecure)
secure
msgio
.
ReadWriteCloser
// secure Session
session
secio
.
Session
insecure
Conn
// the wrapped conn
secure
secio
.
Session
// secure Session
}
// newConn constructs a new connection
...
...
@@ -37,23 +29,20 @@ func newSecureConn(ctx context.Context, sk ic.PrivKey, insecure Conn) (Conn, err
return
nil
,
errors
.
New
(
"insecure.LocalPeer() is nil"
)
}
if
sk
==
nil
{
panic
(
"way"
)
return
nil
,
errors
.
New
(
"private key is nil"
)
}
// NewSession performs the secure handshake, which takes multiple RTT
sessgen
:=
secio
.
SessionGenerator
{
LocalID
:
insecure
.
LocalPeer
(),
PrivateKey
:
sk
}
se
ssion
,
err
:=
sessgen
.
NewSession
(
ctx
,
insecure
)
se
cure
,
err
:=
sessgen
.
NewSession
(
ctx
,
insecure
)
if
err
!=
nil
{
return
nil
,
err
}
conn
:=
&
secureConn
{
insecure
:
insecure
,
session
:
session
,
secure
:
session
.
ReadWriter
(),
secure
:
secure
,
}
log
.
Debugf
(
"newSecureConn: %v to %v handshake success!"
,
conn
.
LocalPeer
(),
conn
.
RemotePeer
())
return
conn
,
nil
}
...
...
@@ -102,49 +91,49 @@ func (c *secureConn) RemoteMultiaddr() ma.Multiaddr {
// LocalPeer is the Peer on this side
func
(
c
*
secureConn
)
LocalPeer
()
peer
.
ID
{
return
c
.
se
ssion
.
LocalPeer
()
return
c
.
se
cure
.
LocalPeer
()
}
// RemotePeer is the Peer on the remote side
func
(
c
*
secureConn
)
RemotePeer
()
peer
.
ID
{
return
c
.
se
ssion
.
RemotePeer
()
return
c
.
se
cure
.
RemotePeer
()
}
// LocalPrivateKey is the public key of the peer on this side
func
(
c
*
secureConn
)
LocalPrivateKey
()
ic
.
PrivKey
{
return
c
.
se
ssion
.
LocalPrivateKey
()
return
c
.
se
cure
.
LocalPrivateKey
()
}
// RemotePubKey is the public key of the peer on the remote side
func
(
c
*
secureConn
)
RemotePublicKey
()
ic
.
PubKey
{
return
c
.
se
ssion
.
RemotePublicKey
()
return
c
.
se
cure
.
RemotePublicKey
()
}
// Read reads data, net.Conn style
func
(
c
*
secureConn
)
Read
(
buf
[]
byte
)
(
int
,
error
)
{
return
c
.
secure
.
Read
(
buf
)
return
c
.
secure
.
Read
Writer
()
.
Read
(
buf
)
}
// Write writes data, net.Conn style
func
(
c
*
secureConn
)
Write
(
buf
[]
byte
)
(
int
,
error
)
{
return
c
.
secure
.
Write
(
buf
)
return
c
.
secure
.
ReadWriter
()
.
Write
(
buf
)
}
func
(
c
*
secureConn
)
NextMsgLen
()
(
int
,
error
)
{
return
c
.
secure
.
NextMsgLen
()
return
c
.
secure
.
ReadWriter
()
.
NextMsgLen
()
}
// ReadMsg reads data, net.Conn style
func
(
c
*
secureConn
)
ReadMsg
()
([]
byte
,
error
)
{
return
c
.
secure
.
ReadMsg
()
return
c
.
secure
.
Read
Writer
()
.
Read
Msg
()
}
// WriteMsg writes data, net.Conn style
func
(
c
*
secureConn
)
WriteMsg
(
buf
[]
byte
)
error
{
return
c
.
secure
.
WriteMsg
(
buf
)
return
c
.
secure
.
ReadWriter
()
.
WriteMsg
(
buf
)
}
// ReleaseMsg releases a buffer
func
(
c
*
secureConn
)
ReleaseMsg
(
m
[]
byte
)
{
c
.
secure
.
ReleaseMsg
(
m
)
c
.
secure
.
Re
adWriter
()
.
Re
leaseMsg
(
m
)
}
p2p/net/conn/secure_conn_test.go
浏览文件 @
414ab636
...
...
@@ -23,6 +23,15 @@ func upgradeToSecureConn(t *testing.T, ctx context.Context, sk ic.PrivKey, c Con
if
err
!=
nil
{
return
nil
,
err
}
// need to read + write, as that's what triggers the handshake.
h
:=
[]
byte
(
"hello"
)
if
_
,
err
:=
s
.
Write
(
h
);
err
!=
nil
{
return
nil
,
err
}
if
_
,
err
:=
s
.
Read
(
h
);
err
!=
nil
{
return
nil
,
err
}
return
s
,
nil
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论