Repository navigation
KNOX-3519 - Set the JWKS host on the TLS socket so HTTPS endpoint identification works under BC-FIPS - #1459
KNOX-3519 - Set the JWKS host on the TLS socket so HTTPS endpoint identification works under BC-FIPS#1459moresandeep wants to merge 2 commits into
Conversation
Test Results 4 files 4 suites 1m 26s ⏱️ Results for commit a7131cf. ♻️ This comment has been updated with latest results. |
lmccay
left a comment
There was a problem hiding this comment.
Made some comments and asked questions.
| /* Not reachable through this type; a public interface may still expose it. */ | ||
| continue; | ||
| } catch (InvocationTargetException | RuntimeException e) { | ||
| return false; |
There was a problem hiding this comment.
Should a single failure to set it even though it appears to have such a method fail the entire iteration over the types? Should we not continue to walk the hierarchy to see if one will work? Are we assuming that someone overrode another implementation in order to purposely not support it and throw a RTE rather than just no-op it?
There was a problem hiding this comment.
The IllegalAccessException which we tolerate and keep moving is caused due to reflection access, with this exception we know we hit, say a private method in impl e.g. org.bouncycastle.jsse.provider.ProvSSLSocketDirect
InvocationTargetException and RuntimeException errors will be thown in (or within) the method body, e.g. BCSSLSocket.setHost (interface) and ProvSSLSocketDirect.setHost (concrete impl) land on the same method body so If the call itself throws, continuing the walk will invokes the identical code and gets an identical exception. So, we'll just be throwing errors and not gaining much.
I will make sure to add docs to the method, let me know if this explanation helps!
| * @return {@code true} when the host was applied, {@code false} when the socket does not | ||
| * support it or the call failed | ||
| */ | ||
| static boolean setHost(Socket socket, String host) { |
There was a problem hiding this comment.
It seems that we are iterating over the class hierarchy of the socket looking for the first one that accepts or rejects a setHost method call. IIUC, then this looks for the most specific implementation of setHost that is public. If it fails due to method visibility it continues to walk the hierarchy to try and find a public one that will work. If that's accurate then I think we should document this a bit here to describe the intent at least.
There was a problem hiding this comment.
Yes this needs some more docs. Specifically, we walk the hierarchy and add interfaces first then the classes, this is due to the fact that BC's socket implementations are package private e.g. org.bouncycastle.jsse.provider.ProvSSLSocketDirect, no public method, so setHost is only invocable through the public org.bouncycastle.jsse.BCSSLSocket interface.
I will document it better.
| * HTTPS endpoint identification can run under the BouncyCastle FIPS provider. See | ||
| * SetHostSSLSocketFactory. Timeouts and size limit match the Nimbus defaults. | ||
| */ | ||
| private static ResourceRetriever defaultResourceRetriever(URL jwksUrl) { |
There was a problem hiding this comment.
We should gate this on FIPS. We already have the FipsUtils class that identifies FIPS environments.
There was a problem hiding this comment.
We actuially gate this on FIPS so the actual socket setHost(String) only exists on BCSSLSocket, for stock JSSE forUrl's decorator hands the socket back untouched.
THis is also covered in testLeavesSocketWithoutSetHostUnchanged.
Plus we don't want this fix just for FIPS, we want this independent of provider.
| * License for the specific language governing permissions and limitations under | ||
| * the License. | ||
| */ | ||
| package org.apache.knox.gateway.services.token.impl; |
There was a problem hiding this comment.
There is already a Fips related package in gateway-spi org.apache.knox.gateway.fips
There was a problem hiding this comment.
Similar to previous comment, this fix is not really FIPS-specific in nature (even though the manifestation is in fips) it fixes a HttpsURLConnection/Nimbus interaction and is a no-op elsewhere, BC is just where the symptom shows up. So fips would mislabel it.
There was a problem hiding this comment.
I understand that your saying it isn't FIPS specific but isn't there a risk of some unrelated socket type hierarchy having a setHost method available? Shouldn't we be explicitly enabling this for deployments that we know we want this behavior? So there is really only a no-op when there is no unknown type with a setHost method. Right?
There was a problem hiding this comment.
True, the noop is conditional on setHost being absent, any type in the hierarchy (for JSSE provider) with a public setHost(String) gets called regardless.
I'll make the lookup itself specific to match on the declaring type by name org.bouncycastle.jsse.BCSSLSocket, and call setHost only through that interface.
I'll also move this to gateway-spi's fips package
KNOX-3519 - Set the JWKS host on the TLS socket so HTTPS endpoint identification works under BC-FIPS
What changes were proposed in this pull request?
Under the BouncyCastle FIPS JSSE provider, fetching a JWKS over HTTPS fails before any
certificate is examined:
JWT verification then fails and the request is rejected with 401, even when the JWKS
endpoint's certificate is fully trusted and carries a matching SAN.
The change. A new
SetHostSSLSocketFactorydecorator stamps the JWKS URL's host ontoevery socket it creates, via
setHost(String)as declared byorg.bouncycastle.jsse.BCSSLSocket. It is wired in at both JWKS retrieval paths:DefaultTokenAuthorityService.buildJwkSource(default truststore) andIssuerTrustResourceRetriever(per-issuer CA bundle).Notes on the implementation:
TLS provider, it is present only in FIPS deployments. Lookup walks interfaces first,
because BC's socket implementations are package-private and the method is only invocable
through the public
BCSSLSocketinterface.setHostthe decorator is a no-op. That is correct for thestock JSSE, which identifies HTTPS endpoints from the URL already, so non-FIPS deployments
are unaffected.
carry a SAN matching the JWKS host.
(connect/read 500 ms, 51200 byte limit,
disconnectAfterUse = true), so timeout and sizebehaviour are unchanged.
How was this patch tested?
Patch was tested locally.