-
Notifications
You must be signed in to change notification settings - Fork 20
Added basic support for TLS 1.3 using openssl min/max proto version functions #13
base: master
Are you sure you want to change the base?
Conversation
@Stebalien Can you help me get this merged so I can more easily test libp2p/go-libp2p-tls#71? |
@@ -383,6 +405,16 @@ func (c *Conn) shutdown() func() error { | |||
defer c.mtx.Unlock() | |||
runtime.LockOSThread() | |||
defer runtime.UnlockOSThread() | |||
timed_out := false | |||
time.AfterFunc(300*time.Millisecond, func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this value come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marten-seemann It's a local variable meant to prevent an infinite loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, I don't understand where an infinite loop would come from (I don't understand the whole handshake_started
/ handshake_finished
logic in this PR.
Second, starting a timer here is definitely not the solution. 300 ms seem to be an arbitrary value, and it will just cause problems later on. Furthermore, this code is racy anyway (you're writing to and reading from timed_out
from separate go routines).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marten-seemann The point of the timeout loop is that it prevents a connection being closed while a handshake is in progress, which occurs in the C portion of the OpenSSL library. I consistently run into that error in my libp2p-tls PR. I can remove this from this PR for now, but it will still be necessary I think. Also, I can't test how well this PR helps with libp2p integration until this is merged.
Assuming that Go booleans are equivalent to C booleans once compiled, they are atomic (modified and read in 1 instruction) and thus don't actually have any race conditions.
@@ -95,7 +95,7 @@ func NewCtxWithVersion(version SSLVersion) (*Ctx, error) { | |||
case TLSv1_2: | |||
method = C.X_TLSv1_2_method() | |||
case AnyVersion: | |||
method = C.X_SSLv23_method() | |||
method = C.X_TLS_method() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is here no case for TLSv1_3
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the method parameter is deprecated in openssl now, so there is no TLSv1_3. That's why I added the min and max proto functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll need to build an abstraction around that then, i.e. we shouldn't have a NewCtxWithVersion
and a Set{Min,Max}ProtoVersion
at the same time.
I'd be ok with either:
- removing
NewCtxWithVersion
, and forcing users to useSet{Min,Max}ProtoVersion
, or - not introducing
Set{Min,Max}ProtoVersion
as a public function, but making it private and then calling it fromNewCtxWithVersion
The first option probably allows for more flexibility (as you can set min and max separately), whereas NewCtxWithVersion
forces you to use min = max, right?
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the real question is what is the policy for deprecated functions in OpenSSL?
I've seen in some other Go wrapper libraries that by default they don't include deprecated functions but have a tag to enable them at compile time. I can see implementing something before the next version, but that's a PR in itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a general rule, I'd try to avoid deprecated functions, if possible. After all, they're deprecated for a reason.
My point in my previous comment was that we should abstract away that complexity from users of go-openssl
. That means, we should either offer NewCtxWithVersion
or Set{Min,Max}ProtoVersion
.
|
||
func (c *Ctx) SetMinProtoVersion(version Version) bool { | ||
return C.X_SSL_CTX_set_min_proto_version( | ||
c.ctx, C.int(version)) == 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under which circumstances can this fail? I wouldn't expect a return value on a setter function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how it could fail. I'm just passing along the value from the openssl C library.
//_, err = key.MarshalPKCS1PrivateKeyPEM() | ||
//if err != nil { | ||
// t.Fatal(err) | ||
//} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unrelated to TLS 1.3 so I'm just suppressing the error for now. I think the function is also deprecated. I'm sure if you the tests without this commit you'll see the function fails there. It doesn't seem to affect overall functionality of the go-openssl library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any deprecation in the interface:
Lines 97 to 110 in 6f65c2c
type PrivateKey interface { | |
PublicKey | |
// Signs the data using PKCS1.15 | |
SignPKCS1v15(Method, []byte) ([]byte, error) | |
// MarshalPKCS1PrivateKeyPEM converts the private key to PEM-encoded PKCS1 | |
// format | |
MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error) | |
// MarshalPKCS1PrivateKeyDER converts the private key to DER-encoded PKCS1 | |
// format | |
MarshalPKCS1PrivateKeyDER() (der_block []byte, err error) | |
} |
I can confirm that the test is failing on my local machine though, and I think this should be fixed in a separate PR (with a proper fix, not a FIXME).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove the FIXMEs for now.
@@ -303,11 +310,26 @@ func (c *Conn) handshake() func() error { | |||
// Handshake performs an SSL handshake. If a handshake is not manually | |||
// triggered, it will run before the first I/O on the encrypted stream. | |||
func (c *Conn) Handshake() error { | |||
c.mtx.Lock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand these changes. Why do you need those state bools?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the go-libp2p-tls test, the handshake tests seem to fail because the tls connection is still being initialize when it is requested to be closed. This should hopefully fix it. But the only way to test if it works is adding it to the go-openssl repo. If the test results aren't promising then we can remove these.
@@ -383,6 +405,16 @@ func (c *Conn) shutdown() func() error { | |||
defer c.mtx.Unlock() | |||
runtime.LockOSThread() | |||
defer runtime.UnlockOSThread() | |||
timed_out := false | |||
time.AfterFunc(300*time.Millisecond, func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, I don't understand where an infinite loop would come from (I don't understand the whole handshake_started
/ handshake_finished
logic in this PR.
Second, starting a timer here is definitely not the solution. 300 ms seem to be an arbitrary value, and it will just cause problems later on. Furthermore, this code is racy anyway (you're writing to and reading from timed_out
from separate go routines).
c.ctx, C.int(version)) == 1 | ||
} | ||
|
||
func (c *Ctx) GetMinProtoVersion() Version { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do we need these getter functions for? This value was set by the user before, so it seems like there's no need for it?
Closes: #8
Required for: libp2p/go-libp2p-tls#71, ipfs/kubo#7150