Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SSL_get0_raw_cipherlist() #2280

Closed

Conversation

mattcaswell
Copy link
Member

Checklist
  • CLA is signed
Description of change

SSL_get0_raw_cipherlist() was a little too "raw" in the case of an SSLv2
compat ClientHello. In 1.0.2 and below, during version negotiation, if
we received an SSLv2 compat ClientHello but actually wanted to do SSLv3+
then we would construct a "fake" SSLv3+ ClientHello. This "fake" ClientHello
would have its ciphersuite list converted to the SSLv3+ format. It was
this "fake" raw list that got saved away to later be returned by a call to
SSL_get0_raw_cipherlist().

In 1.1.0+ version negotiation works differently and we process an SSLv2
compat ClientHello directly without the need for an intermediary "fake"
ClientHello. This meant that the raw ciphersuite list being saved was in
the SSLv2 format. Any caller of this function would not expect that and
potentially overread the returned buffer by one byte.

Fixes #2189

Note: There is a test that fails due to this issue in the 1.1.0 branch. However it does not get triggered in master even though the test is there. The reason is that the test in question gets skipped in no-shared builds, and the asan travis configuration (where this occurs) is marked as no-shared in master but not in 1.1.0. We might want to consider changing that in master. Not part of this PR though.

SSL_get0_raw_cipherlist() was a little too "raw" in the case of an SSLv2
compat ClientHello. In 1.0.2 and below, during version negotiation, if
we received an SSLv2 compat ClientHello but actually wanted to do SSLv3+
then we would construct a "fake" SSLv3+ ClientHello. This "fake" ClientHello
would have its ciphersuite list converted to the SSLv3+ format. It was
this "fake" raw list that got saved away to later be returned by a call to
SSL_get0_raw_cipherlist().

In 1.1.0+ version negotiation works differently and we process an SSLv2
compat ClientHello directly without the need for an intermediary "fake"
ClientHello. This meant that the raw ciphersuite list being saved was in
the SSLv2 format. Any caller of this function would not expect that and
potentially overread the returned buffer by one byte.

Fixes openssl#2189
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.

Looks good to me

@levitte
Copy link
Member

levitte commented Jan 24, 2017

Note: There is a test that fails due to this issue in the 1.1.0 branch. However it does not get triggered in master even though the test is there. The reason is that the test in question gets skipped in no-shared builds, and the asan travis configuration (where this occurs) is marked as no-shared in master but not in 1.1.0. We might want to consider changing that in master. Not part of this PR though.

I think that would be a good idea. Possibly separate the two intents of that build into two builds.

@snhenson
Copy link
Contributor

Err the whole point of SSL_get0_raw_cipherlist is that you get exactly what the client sent you without any further processing by OpenSSL. The bug is assuming it will always return 2.

@mattcaswell
Copy link
Member Author

Err the whole point of SSL_get0_raw_cipherlist is that you get exactly what the client sent you without any further processing by OpenSSL. The bug is assuming it will always return 2.

Yeah, I get that - but that is not the way it has ever worked when dealing with an SSLv2 compat ClientHello (and we're not actually going to do SSLv2). In versions prior to 1.1.0 we converted an SSLv2 cipher list into SSLv3 format before saving away the raw cipherlist data. This is just restoring the behaviour to how it has always been rather than crashing. The only time it was 3 in <=1.0.2 was if we do real SSLv2 (which obviously doesn't apply in 1.1.0+).

@mattcaswell
Copy link
Member Author

Yeah, I get that - but that is not the way it has ever worked when dealing with an SSLv2 compat ClientHello (and we're not actually going to do SSLv2). In versions prior to 1.1.0 we converted an SSLv2 cipher list into SSLv3 format before saving away the raw cipherlist data. This is just restoring the behaviour to how it has always been rather than crashing. The only time it was 3 in <=1.0.2 was if we do real SSLv2 (which obviously doesn't apply in 1.1.0+).

BTW, I did consider an alternative solution where we save the encoding type in the SSL object rather than doing the conversion - but that would mean you would get different behaviour between 1.0.2 and 1.1.0, which is why I went with this approach.

@snhenson
Copy link
Contributor

Ugh it's unfortunate that it never worked. There might be cases where getting the "true" raw format is useful e.g. seeing if the peer sent any "real" SSLv2 ciphers.

@mattcaswell
Copy link
Member Author

Ugh it's unfortunate that it never worked. There might be cases where getting the "true" raw format is useful e.g. seeing if the peer sent any "real" SSLv2 ciphers.

So do you have no objection to this solution?

@snhenson
Copy link
Contributor

No, no objection, just a pity it didn't work originally. Hopefully no one will send SSLv2 compatible client hellos in the foreseeable furture.

levitte pushed a commit that referenced this pull request Jan 24, 2017
SSL_get0_raw_cipherlist() was a little too "raw" in the case of an SSLv2
compat ClientHello. In 1.0.2 and below, during version negotiation, if
we received an SSLv2 compat ClientHello but actually wanted to do SSLv3+
then we would construct a "fake" SSLv3+ ClientHello. This "fake" ClientHello
would have its ciphersuite list converted to the SSLv3+ format. It was
this "fake" raw list that got saved away to later be returned by a call to
SSL_get0_raw_cipherlist().

In 1.1.0+ version negotiation works differently and we process an SSLv2
compat ClientHello directly without the need for an intermediary "fake"
ClientHello. This meant that the raw ciphersuite list being saved was in
the SSLv2 format. Any caller of this function would not expect that and
potentially overread the returned buffer by one byte.

Fixes #2189

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from #2280)
(cherry picked from commit 07afdf3)
levitte pushed a commit that referenced this pull request Jan 24, 2017
SSL_get0_raw_cipherlist() was a little too "raw" in the case of an SSLv2
compat ClientHello. In 1.0.2 and below, during version negotiation, if
we received an SSLv2 compat ClientHello but actually wanted to do SSLv3+
then we would construct a "fake" SSLv3+ ClientHello. This "fake" ClientHello
would have its ciphersuite list converted to the SSLv3+ format. It was
this "fake" raw list that got saved away to later be returned by a call to
SSL_get0_raw_cipherlist().

In 1.1.0+ version negotiation works differently and we process an SSLv2
compat ClientHello directly without the need for an intermediary "fake"
ClientHello. This meant that the raw ciphersuite list being saved was in
the SSLv2 format. Any caller of this function would not expect that and
potentially overread the returned buffer by one byte.

Fixes #2189

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from #2280)
@mattcaswell
Copy link
Member Author

Pushed. Thanks.

@kaduk kaduk mentioned this pull request Jan 24, 2017
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
branch: master Merge to master branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Heap buffer overflow in print_raw_cipherlist (apps/s_cb.c)
3 participants