Skip to content
This repository has been archived by the owner on Jan 7, 2023. It is now read-only.

Added basic support for TLS 1.3 using openssl min/max proto version functions #13

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Geo25rey
Copy link

@Geo25rey Geo25rey commented Oct 22, 2020

Closes: #8

Required for: libp2p/go-libp2p-tls#71, ipfs/kubo#7150

@Geo25rey
Copy link
Author

@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() {

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?

Copy link
Author

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.

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).

Copy link
Author

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()

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?

Copy link
Author

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.

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 use Set{Min,Max}ProtoVersion, or
  • not introducing Set{Min,Max}ProtoVersion as a public function, but making it private and then calling it from NewCtxWithVersion

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?

Copy link
Author

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.

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

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.

Copy link
Author

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)
//}

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.

Copy link
Author

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.

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:

go-openssl/key.go

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).

Copy link
Author

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()

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?

Copy link
Author

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() {

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 {

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?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add support for TLS 1.3
2 participants