Kerberos Bug Introduced in d777e2918a77?
Weijun Wang
weijun.wang at oracle.com
Thu Apr 23 14:14:39 UTC 2015
Hi Daniel
Sorry for the trouble.
On 4/23/2015 7:25 PM, Daniel Jones wrote:
> Hi all,
>
> Thanks to everyone taking the time to look into this.
>
> Before I get into the detail of the technical issue, can anyone
> postulate as to *how quickly fixes tend to make it into releases of
> OpenJDK*? Are we talking days, weeks, or months? I'm just trying to
> advise my client on the best mitigation strategy until the issue is
> resolved.
Oracle does not releases binaries for OpenJDK, you only get the source
codes on http://hg.openjdk.java.net. Once we made a fix, the changeset
will be there. So if you build your own JDK, that's quite fast.
If you use Oracle JDK, it has a release schedule at
https://www.java.com/en/download/faq/release_dates.xml
So it's months.
>
> The Spring code in question actually changed this morning to throw a
> more useful error:
> https://github.com/spring-projects/spring-security-kerberos/commit/f046bd7c69d6dad74eb06a7651cd68060b31ff6f
>
> On the other hand, your program has
> context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
> String user = context.getSrcName().toString();
> which is not standard. The acceptSecContext call should be in a loop
> until a context is established, and then you can call getSrcName().
If you look at the class spec in
http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/debb4ce14251/src/share/classes/org/ietf/jgss/GSSContext.java
the formal context establishment should be like
* while (!context.isEstablished()) {
* inToken = readToken();
* outToken = context.acceptSecContext(inToken, 0,
* inToken.length);
* // send output token if generated
* if (outToken != null)
* sendToken(outToken);
* }
In your case, before 8048194, it just happens that the while loop only
runs once.
What is the client here? A browser?
On the other hand, I am looking at your code and see if there is a
workaround. Can you capture some packets and send to me? Especially I'd
like the content of "kerberosTicket" in
byte[] responseToken = context.acceptSecContext(kerberosTicket, 0,
kerberosTicket.length);
In my experiment, the first 48 bytes look like this:
0000: 60 82 02 2D 06 06 2B 06 01 05 05 02 A0 82 02 21
0010: 30 82 02 1D A0 18 30 16 06 09 2A 86 48 82 F7 12
0020: 01 02 02 06 09 2A 86 48 86 F7 12 01 02 02 A1 04
Here, the OIDs are the 11 bytes from 0x18 and 0x23 starting with 06 09.
You can see the only difference between the 2 OIDs are 82 (at 0x1D) and
86 (at 0x28). If you swap them, Java will happily accept it.
Please note this is only a workaround and the real fix should be inside
JDK. If your packet is bigger the 2nd byte might be 83 and you need to
look a bit further for the OIDs (still starting with 06 09).
Thanks
Max
>
>
> I'm not sure that this would work. I'm not at all familiar with what is
> best practice in handling Kerberos tickets, but let me explain what
> happens at present in u40:
>
> 1. Spring's SunJaasKerberosTicketValidator gets a GSSContextImpl, and
> calls acceptSecContext on it.
> 2. The GSSContextImpl calls an overloaded accetSecContext method, which
> successfully creates a SpNegoContext and assigns it as the mechCtxt
> member.
> 3. GSSContextImpl#acceptSecContext then calls
> SpNegoContext#acceptSecContext
> 4. In SpNegoContext#acceptSecContext we have the new functionality that
> only looks at the top item of the list of OIDs from the service ticket.
> 5. The inner mechContext of the SpNegoContext is not set.
> 6. We return back to the Spring code, with a GSSContextImpl wrapping a
> SpNegoContext
> 7. Spring calls GSSContextImpl#getSrcName(), which delegates to
> SpNegoContext#getSrcName(), which returns null as its mechContext
> member is null.
Yes.
>
>
> Spring passes the whole ticket into GSSContextImpl, and doesn't know
> about OIDs and the list of acceptable mechanisms. It seems like it's a
> responsibility of either SpNegoContext or GSSContextImpl to know about
> this list and iterate over it.
Yes. Unfortunately Java does not understand that 1st OID now.
>
> If the Spring code were to attempt a repeat, how should it know that the
> inner context was not set? What action should it perform next? It's
> passed in the ticket it knows about, and got back a populated byte[],
> without any exceptions. What would it use to determine that one of the
> side affects of GSSContextImpl#acceptSecContext hasn't succeeded?
Like what I quoted above, loop until context.isEstablished() is true. Of
course, this means the client side must also coded formally to loop on
its side. I don't know what the client is and not sure if its
application protocol has this loop defined.
>
> Does the above make sense? Please do get in touch if I an provide any
> other assistance in helping with the issue, and thanks again to everyone
> looking into it.
Thanks.
>
>
>
> On Thu, Apr 23, 2015 at 1:58 AM, Weijun Wang <weijun.wang at oracle.com
> <mailto:weijun.wang at oracle.com>> wrote:
>
> Hi Daniel
>
> I've read more about your bug report and know what's happening.
>
> You are proposing 2 OIDs, [1.2.840.48018.1.2.2,
> 1.2.840.113554.1.2.2], 1st one being Microsoft's own krb5 OID and
> 2nd the standard one. Java only understands the 2nd one but before
> that changeset it blindly accepts the mechToken without looking at
> the OID. Since it's also krb5, the mechToken is processed correctly
> and everything goes on. After the changeset, it does not recognize
> the OID anymore and asks the client to send another mechToken with
> 1.2.840.113554.1.2.2.
>
> I believe a lot of people is using the Microsoft OID. I will see if
> it's possible to recognize both OIDs.
>
> On the other hand, your program has
>
> context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
> String user = context.getSrcName().toString();
>
> which is not standard. The acceptSecContext call should be in a loop
> until a context is established, and then you can call getSrcName().
> Can you try that? Hopefully after the client sees the server request
> for a 1.2.840.113554.1.2.2 mechToken it can send one and the server
> can go on.
>
> Thanks
> Max
>
>
> On 4/23/2015 7:22 AM, Weijun Wang wrote:
>
> Hi Daniel
>
> Thanks for the report.
>
> In fact, the bug behind the changeset you mentioned -- 8048194
> -- was
> just meant to make your case work. Before that, the server blindly
> accepts the mechToken and process it no matter if the OID is
> supported.
> Now it first looks at the OID and accept the token if it
> supports the
> OID; otherwise, only the negotiated result (its supported OID)
> is sent
> back, and waits for the client sending the correct mechToken in
> the next
> round.
>
> It seems the logic above is not implemented correctly, can you
> show me
> the full stack of your NullPointerException? If it includes any
> sensitive info you can write me privately.
>
> Thanks
> Max
>
> On 4/23/2015 12:21 AM, Rob McKenna wrote:
>
> Hi Daniel,
>
> Thanks for the report, I'm cc'ing the security-dev alias.
>
> -Rob
>
> On 22/04/15 13:10, Daniel Jones wrote:
>
> Hi all,
>
> Apologies if this is the wrong mailing list - please
> direct me to the
> correct one if so.
>
> I believe I've found a bug in OpenJDK 1.8.0_40,
> introduced in commit
> d777e2918a77:
> http://hg.openjdk.java.net/jdk8u/jdk8u40/jdk/file/d777e2918a77/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
>
>
>
> The change introduced on line 548 means that an
> authentication
> mechanism is
> only accepted if the OID of the mechanism desired is the
> *first* in the
> list of mechanisms specified as acceptable in the
> incoming ticket.
>
> In the case of my current client their service tickets
> are specifying 4
> acceptable mechanism OIDs, but the only available
> mechanism's OID
> appears
> second on that list. So whilst the server *can *satisfy
> the ticket, the
> code change on line 548 prevents this from happening.
>
> Using the same server code, the same Kerberos KDC, and
> OpenJDK 1.8.0_31,
> everything works. Changing only the JDK results in the
> mechContext not
> being properly populated, which in turn causes a
> NullPointerException
> from
> some Spring Security Kerberos code.
>
> Has anyone else experienced this?
>
>
>
>
>
>
> --
> Regards,
>
> Daniel Jones
> EngineerBetter.com
More information about the security-dev
mailing list