-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
okhttp: properly verify IPv6 address hosts #4292
Changes from 1 commit
13f0d5a
99e7e71
d310a23
5fd7dfd
1065eb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,9 +70,24 @@ public static SSLSocket upgrade(SSLSocketFactory sslSocketFactory, | |
if (hostnameVerifier == null) { | ||
hostnameVerifier = OkHostnameVerifier.INSTANCE; | ||
} | ||
if (!hostnameVerifier.verify(host, sslSocket.getSession())) { | ||
if (!hostnameVerifier.verify(canonicalizeHost(host), sslSocket.getSession())) { | ||
throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); | ||
} | ||
return sslSocket; | ||
} | ||
|
||
/** | ||
* Converts a host from URI to X509 format. | ||
* | ||
* <p>IPv6 host addresses derived from URIs are enclosed in square brackets per RFC2732, but | ||
* omit these brackets in X509 certificate subjectAltName extensions per RFC5280. | ||
* | ||
* @see <a href="https://www.ietf.org/rfc/rfc2732.txt">RFC2732</a> | ||
* @see <a href="https://tools.ietf.org/html/rfc5280#section-4.2.1.6">RFC5280</a> | ||
* | ||
* @return {@param host} in a form consistent with X509 certificates | ||
*/ | ||
static String canonicalizeHost(String host) { | ||
return host.replaceAll("[\\[\\]]", ""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may be safe as-is, but we should be more conservative here: if the first and last characters are This would mean that we can add a test like |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ | |
|
||
package io.grpc.okhttp; | ||
|
||
import static io.grpc.okhttp.OkHttpTlsUpgrader.canonicalizeHost; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import io.grpc.okhttp.internal.Protocol; | ||
|
@@ -32,4 +34,44 @@ public class OkHttpTlsUpgraderTest { | |
|| OkHttpTlsUpgrader.TLS_PROTOCOLS.indexOf(Protocol.GRPC_EXP) | ||
< OkHttpTlsUpgrader.TLS_PROTOCOLS.indexOf(Protocol.HTTP_2)); | ||
} | ||
|
||
@Test public void upgrade_canonicalizeHost() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests coverage look good to me (with the addition of a case to ensure we don't strip out additional brackets for malformed URIs). Out of curiosity, what methodology went into choosing the test hosts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will update to ensure we don't strip out additional brackets. I lifted these from okhttp's HostnameVerifierTest, so I'll add some attribution. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's simplify the tests somewhat here, which will also remove the need for attribution - we actually don't care about all of the edge cases that the linked test case covers, because we don't need to distinguish between IP addresses and hostnames. Probably just the following are enough:
Also, does it make sense to rename the test method to just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good to me |
||
// IPv4 | ||
assertEquals(canonicalizeHost("127.0.0.1"), "127.0.0.1"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The argument order for |
||
assertEquals(canonicalizeHost("1.2.3.4"), "1.2.3.4"); | ||
|
||
// IPv6 | ||
assertEquals(canonicalizeHost("::1"), "::1"); | ||
assertEquals(canonicalizeHost("[::1]"), "::1"); | ||
assertEquals(canonicalizeHost("2001:db8::1"), "2001:db8::1"); | ||
assertEquals(canonicalizeHost("[2001:db8::1]"), "2001:db8::1"); | ||
assertEquals(canonicalizeHost("::192.168.0.1"), "::192.168.0.1"); | ||
assertEquals(canonicalizeHost("[::192.168.0.1]"), "::192.168.0.1"); | ||
assertEquals(canonicalizeHost("::ffff:192.168.0.1"), "::ffff:192.168.0.1"); | ||
assertEquals(canonicalizeHost("[::ffff:192.168.0.1]"), "::ffff:192.168.0.1"); | ||
assertEquals(canonicalizeHost("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"), | ||
"FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"); | ||
assertEquals(canonicalizeHost("[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]"), | ||
"FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"); | ||
assertEquals(canonicalizeHost("1080:0:0:0:8:800:200C:417A"), "1080:0:0:0:8:800:200C:417A"); | ||
assertEquals(canonicalizeHost("[1080:0:0:0:8:800:200C:417A]"), "1080:0:0:0:8:800:200C:417A"); | ||
assertEquals(canonicalizeHost("1080::8:800:200C:417A"), "1080::8:800:200C:417A"); | ||
assertEquals(canonicalizeHost("[1080::8:800:200C:417A]"), "1080::8:800:200C:417A"); | ||
assertEquals(canonicalizeHost("FF01::101"), "FF01::101"); | ||
assertEquals(canonicalizeHost("[FF01::101]"), "FF01::101"); | ||
assertEquals(canonicalizeHost("0:0:0:0:0:0:13.1.68.3"), "0:0:0:0:0:0:13.1.68.3"); | ||
assertEquals(canonicalizeHost("[0:0:0:0:0:0:13.1.68.3]"), "0:0:0:0:0:0:13.1.68.3"); | ||
assertEquals(canonicalizeHost("0:0:0:0:0:FFFF:129.144.52.38"), "0:0:0:0:0:FFFF:129.144.52.38"); | ||
assertEquals(canonicalizeHost("[0:0:0:0:0:FFFF:129.144.52.38]"), "0:0:0:0:0:FFFF:129.144.52.38"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this fails checkstyle (100 char limit per line) |
||
assertEquals(canonicalizeHost("::13.1.68.3"), "::13.1.68.3"); | ||
assertEquals(canonicalizeHost("[::13.1.68.3]"), "::13.1.68.3"); | ||
assertEquals(canonicalizeHost("::FFFF:129.144.52.38"), "::FFFF:129.144.52.38"); | ||
assertEquals(canonicalizeHost("[::FFFF:129.144.52.38]"), "::FFFF:129.144.52.38"); | ||
|
||
// Hostnames | ||
assertEquals(canonicalizeHost("go"), "go"); | ||
assertEquals(canonicalizeHost("localhost"), "localhost"); | ||
assertEquals(canonicalizeHost("squareup.com"), "squareup.com"); | ||
assertEquals(canonicalizeHost("www.nintendo.co.jp"), "www.nintendo.co.jp"); | ||
} | ||
} |
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 can be private
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.
Is package-private with
@VisibleForTesting
(alaTLS_PROTOCOLS
) acceptable?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.
Oops, my mistake - yes, the visibility is fine, but the
@VisibleForTesting
annotation would be helpful.