Skip to content

Conversation

Lukasa
Copy link
Contributor

@Lukasa Lukasa commented Jan 25, 2017

Checklist
  • tests are added or updated
  • CLA is signed
Description of change

Follows on from #1646.

This change adds support for logging out several of the secrets from the TLSv1.3 key schedule for debugging purposes. These secrets are the same as the ones logged by BoringSSL, and are logged in the same format. They are used to continue to allow tools like Wireshark to decrypt TLS traffic when needed.

This change also fixes a bug from the previous code. This slipped past because the tests did not adequately validate the RSA key exchange logging actually occurred: they would pass even if that log never fired. This patch updates the test to correctly exercise that code, and then fixes the underlying bug as well.

I strongly recommend at least one TLSv1.3 expert validates this code. I did my best to read the draft specification and log at the appropriate point, but it is not yet possible to sensibly validate that these logs are actually ok. We should confirm that the TLSv1.3 logs are actually logging the correct secret before we merge this.

ssl/ssl_lib.c Outdated
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is basically identical to the one above it, except that the one above doesn't fire for TLSv1.3. I suspect we should collapse these two and hoist up the check for TLSv1.3 into the calling scope of the above function, but I wanted a code reviewer to confirm that was a good idea.

An alternative would be to have the function above call this one: either would work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it could be merged with the function above. Have a TLSv1.3 section and a non-TLSv1.3 one.

ssl/ssl_lib.c Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that you don't use this for anything useful. Isn't it enough that the length parameter for the encrypted premaster was changed to 8 in the call to nss_keylog_int?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh...yes, yes it is. Honestly not sure what I was thinking there.

ssl/ssl_lib.c Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm starting to think this might do better as an assertion. After all, it is a length that we specify internally and that we should get correctly at all times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me.

ssl/ssl_lib.c Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it could be merged with the function above. Have a TLSv1.3 section and a non-TLSv1.3 one.

ssl/tls13_enc.c Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe these strings should be made into macros in ssl_locl.h...

@richsalz
Copy link
Contributor

Can you split the bugfix into a separate PR? No need to hold that up for the TLS 1.3 review part. Thanks!

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 25, 2017

@richsalz My gift to you: #2288.

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 25, 2017

Ok, I've updated a bunch of stuff.

Right now the tests will fail because the RSA log doesn't come out correctly, so the tests won't pass until #2288 is merged. At that point, I'll rebase onto a new master and we should be good to go.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation of the ssl_log_secret parameters is off by one space. If you used tabs, convert them to spaces, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@levitte
Copy link
Member

levitte commented Jan 25, 2017

#2288 just got merged, so this should build as soon as it's rebased

@Lukasa Lukasa force-pushed the tlsv13-keylogs branch 2 times, most recently from e62f9f6 to ac6a3fd Compare January 25, 2017 21:21
@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 25, 2017

Alrighty, updated.

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 26, 2017

Hrm, what's up with that Windows build? It seems like there's a problem with the linkage on Windows.

@levitte
Copy link
Member

levitte commented Jan 26, 2017

In test/build.info, you need to add ../ssl/ssl_lib.c to the source files for tls13secretstest

@levitte
Copy link
Member

levitte commented Jan 26, 2017

Hold that thought, you did guard it against building when configured shared... I'll have a closer look

@levitte
Copy link
Member

levitte commented Jan 26, 2017

Found it. You got the condition in test/build.info wrong:

diff --git a/test/build.info b/test/build.info
index c11623894..b1a69da24 100644
--- a/test/build.info
+++ b/test/build.info
@@ -371,7 +371,7 @@ IF[{- !$disabled{tests} -}]
   # We disable this test completely in a shared build because it deliberately
   # redefines some internal libssl symbols. This doesn't work in a non-shared
   # build
-  IF[{- !$disabled{shared} -}]
+  IF[{- $disabled{shared} -}]
     PROGRAMS_NO_INST=tls13secretstest
     SOURCE[tls13secretstest]=tls13secretstest.c testutil.c test_main.c
     SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../ssl/packet.c

@levitte
Copy link
Member

levitte commented Jan 26, 2017

As a matter of fact, you can remove one of the source lines as well:

diff --git a/test/build.info b/test/build.info
index c11623894..579cf7562 100644
--- a/test/build.info
+++ b/test/build.info
@@ -371,10 +371,9 @@ IF[{- !$disabled{tests} -}]
   # We disable this test completely in a shared build because it deliberately
   # redefines some internal libssl symbols. This doesn't work in a non-shared
   # build
-  IF[{- !$disabled{shared} -}]
+  IF[{- $disabled{shared} -}]
     PROGRAMS_NO_INST=tls13secretstest
     SOURCE[tls13secretstest]=tls13secretstest.c testutil.c test_main.c
-    SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../ssl/packet.c
     INCLUDE[tls13secretstest]=.. ../include
     DEPEND[tls13secretstest]=../libcrypto ../libssl
   ENDIF

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 26, 2017

I mean, I didn't touch test/build.info at all. ;) But I'm certainly happy to add that delta to my patch.

@mattcaswell
Copy link
Member

So why was this working before?

@levitte
Copy link
Member

levitte commented Jan 26, 2017

So why was this working before?

I have no clue. did we fail to pay attention to Windows back in #1646?

@mattcaswell
Copy link
Member

Reading the comment (which I wrote) it doesn't make any sense:

   # We disable this test completely in a shared build because it deliberately
   # redefines some internal libssl symbols. This doesn't work in a non-shared
   # build

We disable the shared build because it doesn't work in non-shared??? Huh? I really have no idea what I was thinking at the time.

Anyway - it would be a shame to lose this from testing in shared builds because that is the default.

@richsalz
Copy link
Contributor

FYI, from a posting in the TLS mailing list:

This is indeed work in progress, the current state can be tracked at:
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=12779

Note for TLS implementers: Wireshark supports decryption when provided with the master secret (TLS 1.2 and before), but with TLS 1.3 there are more secrets. The current plan is to accept the client/server handshake/application traffic secrets (as opposed to the more sensitive Handshake/Master secrets) following the format proposed by BoringSSL:
https://code.wireshark.org/review/19801

If everything goes well, Wireshark 2.4 should be the first stable version with TLS 1.3 support.

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 26, 2017

No, we didn't support TLSv1.3 in #1646. So I don't think these functions would have needed to be linked in. The change here is that we now log from tls13_enc.c.

@levitte
Copy link
Member

levitte commented Jan 26, 2017

Ok, I'll experiment a bit more...

@mattcaswell
Copy link
Member

No, we didn't support TLSv1.3 in #1646. So I don't think these functions would have needed to be linked in. The change here is that we now log from tls13_enc.c.

Right but the test existed and works fine in master now. So why should we need to change it to work only on non-shared because you added a function call?

@levitte
Copy link
Member

levitte commented Jan 26, 2017

Right but the test existed and works fine in master now. So why should we need to change it to work only on non-shared because you added a function call?

Because ssl/tls13_enc.c, which is mentioned as a specific source module for tls13secretstest, now calls ssl_log_secret, which is a private symbol in ssl/ssl_lib.c

@levitte
Copy link
Member

levitte commented Jan 26, 2017

Unfortunately, ssl/ssl_lib.c has dependencies to a number of libssl modules...

@Lekensteyn
Copy link
Contributor

Matt, this PR (and some other implementations) are mentioned in the commit message of https://code.wireshark.org/review/19801

@levitte
Copy link
Member

levitte commented Jan 26, 2017

@Lukasa, I think that the best you can do to resolve this is to move the key logging functions to a separate source file, so tls13secretstest doesn't have to depend on ssl/ssl_lib.c...

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 26, 2017

Yeah, we can do that. ssl_log.c acceptable? (I considered calling it ssl_keylog.c but I figured that'd give the tinfoil-hat brigade heart attacks.)

@Lukasa
Copy link
Contributor Author

Lukasa commented Jan 31, 2017

Ok, I've squashed this all down to two commits. I'm pretty happy with this at the moment, though as always better testing would be better. Should be good for another round of code review.

ssl/tls13_enc.c Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "goto err" to make sure secret is cleansed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what this means?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially it means: can I not just confirm that the structure is right, but actually validate the secret? Is it hung off an object that I can use to compare it against, or can I derive it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only way to do that would be to reach inside the SSL object. That might not be an unreasonable thing to do in a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So all four of the derived secrets we're logging out here are stored on the SSL object after the connection is established?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well not exactly. We store the handshake_secret and the master_secret. We also store the server finished hash. That should be enough to derive the two application traffic secrets. We don't store the hash of ClientHello..ServerHello which is necessary for the handshake traffic secrets. It would be possible to calculate the hash using a custom BIO to watch the communication between client and server and pick out the first two messages, because those messages are sent in the clear....but that is definitely harder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm.

This is ultimately a balance between the effort needed to write this test code and risk of this code breaking or being wrong. BoringSSL has no tests for this functionality because ultimately it's not that important to them.

The breakage we're risking here is a breakage where the secret we log out is not right. This kind of breakage is of low likelihood once the code is written, but unless we test that it's right we don't really stand a chance of preventing it. Of course, the amount of code required to get it right is...high.

Ultimately this is a question for the maintenance team: all patches should be written with the assumption that the contributor will be hit by a bus 20 seconds after it's merged and the maintenance team will have to live with it with no assistance for the rest of time. So it's your call, not mine. 😁

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking it might be useful to do at least the application traffic secrets bit - it has value as a test beyond the logging functionality. However, thinking about it more you would need to have access to the internal tls13_hkdf_expand() function which, wile doable, probably would mean moving the test to the tls13secretstest.c file. Perhaps a separate PR? For now just leave the TODO in, make it something like TODO(TLS1.3): test that application traffic secrets are what we expect

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's clarify the TODO and consider approaching it in a further PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is not aligned

ssl/tls13_enc.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be const char?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this old comment refer to? maybe it can be removed now after you check the count?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a similar question about whether I can extract the RSA premaster secret once the test has run to validate the secret. An OpenSSL core dev would probably be able to tell me this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the pre-master is held only transiently. Once we've generated the master secret it is removed. In theory you could probably derive the master secret independently from the logged pre-master and check that it is equal to the master in the session...but that is non-trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok then, in that case I'll remove the comment as written and replace it with one that notes that we can't easily validate the log. =)

@Lekensteyn
Copy link
Contributor

@Lukasa Without early data the secret would not be very useful (nothing to test). BoringSSL also does not implement early data as far as I could see, so that did not help either. I should probably look into Tris (Go implementation from Cloudflare) for a more complete 0-RTT implementation for testing.

@levitte levitte dismissed their stale review January 31, 2017 19:19

My change requests have been answered

@Lukasa
Copy link
Contributor Author

Lukasa commented Feb 1, 2017

Ok, I've updated in response to code review.

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I spotted some style nits for multi-line comments that I hadn't noticed before. Approved subject to those being fixed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Multi-line comments should look like this:

 /*
 * Log the master secret, if logging is enabled. We don't log it for
 * TLSv1.3: there's a different key schedule for that.
 */

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: multi-line comment style

@Lukasa
Copy link
Contributor Author

Lukasa commented Feb 1, 2017

Updated the multiline comments.

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great...still missed a couple though. Also needs a second team review...@levitte?

ssl/ssl_locl.h Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this one.

Copy link
Member

@levitte levitte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

Copy link
Contributor

@Lekensteyn Lekensteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I have tested it with a modified s_client version and am able to decrypt the handshake and application data in both direction with Wireshark. Will put a PR for that as well.

@mattcaswell
Copy link
Member

Pushed. Thanks!!

@mattcaswell mattcaswell closed this Feb 2, 2017
levitte pushed a commit that referenced this pull request Feb 2, 2017
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #2287)
levitte pushed a commit that referenced this pull request Feb 2, 2017
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #2287)
@Lekensteyn
Copy link
Contributor

What is the first public version where support for this API can be expected? 1.1.1, 1.2.0 or something else?

What is the suggested method to detect the API availability? There is no macro, so either there will be ifdef checks against the version or there needs to be a configure-time check.

@levitte
Copy link
Member

levitte commented Mar 22, 2017

Our aim is to release a 1.1.1 that includes TLS 1.3. Either way, the following would be safe to check for the availability:

#if OPENSSL_VERSION_NUMBER >= 0x10101000L

The reasoning is that TLSv1.3 can only appear in the next feature release, which must at least be 1.1.1.

@mattcaswell
Copy link
Member

In addition to @levitte's comment, the key logging API will also be in 1.1.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants