-
Notifications
You must be signed in to change notification settings - Fork 9.2k
Handshake returns cleaned peer certificates #5311
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
Conversation
okhttp/src/main/java/okhttp3/internal/connection/RealConnection.kt
Outdated
Show resolved
Hide resolved
@swankjesse Any advice for testing here? We test RealConnection through CallTest, and the JVM code around KeyManager will likely send the clean certificates. |
This situation is frustrating. Cleaning the certificates could be non-trivial, so this has the potential of breaking or slowing code that works otherwise. I’d like to land 4.1 without this, and then put this in 4.2 early with lots of bake time. |
That said, the change itself looks great! As for testing . . . wanna test with a fake cleaner? |
That route isn't great. It makes new internal APIs for setting the cleaner in OkHttpClient.Builder. Cleaner currently comes from the Platform, or via the TrustManager if you customise that. But they are on a public API, so they tend to show up for Java clients. |
@swankjesse I'm tempted to move this into sslSocketSession.handshake() But also wondering whether we should retain the uncleaned certificates? Handshake could have both, potentially interesting when trying to understand why a decision was made. e.g. if certificates are served that have multiple root CAs for different clients. Not sure if that happens in the wild. |
We can hide things from Java clients with a |
Can we always use the cleaner from the pinner? What’s the benefit of wiring it through the connection? If that one is null we shouldn’t bother. I’m still unsatisfied with the performance cost here. It has a non-zero cost and a nearly-zero benefit. |
OK, so cost is cleaning certificates when we aren't currently doing certificate pinning. The benefit is that callers can rely on the handshake certificates being those that we trust and validate. If we choose to expose the handshake certificates (public API), I'd argue that we must provide the validated ones. I'll take a look if we can defer cleaning until these are requested in the handshake. |
Now deferring cleaning until we either
But only done at most once. |
n.b. I removed the test because the change otherwise becomes awkward with OkHttpClient, since that constructor generally always fetches a new cleaner from Platform :( |
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 love the structure of this. You get clean certificates if you use ’em, but you don’t pay until use. Very nice.
} | ||
} | ||
|
||
internal fun check(hostname: String, cleanedPeerCertificatesFn: () -> List<X509Certificate>) { |
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 passing a lambda here is too surprising; it might be better to make this take cleanedCertificates
, and then make the one callsite guard the call with like hasPins()
check
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.
It's not a simple check without cost if there is pinning in place. e.g. a client configures pinning on their API host, but not on the CDN (unknown hosts).
In this case, findMatchingPins(hostname)
is the check we need to do externally rather than hasPins.
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.
It's also internal API, for a class with public API.
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.
SGTM
} | ||
} | ||
|
||
internal fun check(hostname: String, cleanedPeerCertificatesFn: () -> List<X509Certificate>) { |
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.
SGTM
@get:JvmName( | ||
"localCertificates") val localCertificates: List<Certificate>, | ||
|
||
// Delayed provider of peerCertificates, to allow lazy cleaning. |
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.
Nice.
I think this is a very nice improvement. |
#5138
Pass through clean certificates with only a single pass of cert cleaning.