Kerberos Bug Introduced in d777e2918a77?

Daniel Jones daniel.jones at engineerbetter.com
Tue Apr 28 10:14:15 UTC 2015


Hi Weijun,

Thanks for your help. Sorry it's taken me a while to reply, I was give
other priorities over looking into this issue.

Your suggested workaround does indeed work. I've switched elements of the
byte array around with a debugger connected to the app, and that solves the
problem. Thankfully the position of the elements in the ticket seems to be
predictable.

It's a brittle and low-level fix, but at least it works, so thanks!

I noticed in the bug report Internet Explorer is mentioned. We see the same
behaviour with IE, Firefox and Chrome.

On Thu, Apr 23, 2015 at 3:14 PM, Weijun Wang <weijun.wang at oracle.com> wrote:

> 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
>>
>


-- 
Regards,

Daniel Jones
EngineerBetter.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/security-dev/attachments/20150428/80f0fabc/attachment-0001.html>


More information about the security-dev mailing list