Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Bradford Wetmore



On 6/15/2016 1:35 AM, Simone Bordet wrote:

We have not heard from Oracle yet, but I can prepare a webrev if that helps.


Hi all,

Nice to see different folks are trying things out.  I do appreciate the 
discussion/feedback.  I am on a high-priority project right now, so I 
haven't had a chance to parse/respond to the discussion, but should be 
able to cycle back to this in 1-2 weeks.


Best,

Brad


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Greg Wilkins
On 15 June 2016 at 21:31, David M. Lloyd  wrote:
>
>
>> I am proposing 3 simple changes to be done:
>>
>> 1) Introduce a TLSProtocolNames class that can convert from TLS
>> protocol bytes to TLS protocol names.
>> 2) Introduce a TLSCipherSuiteNames class that can convert from TLS
>> cipher suite bytes to TLS cipher suite names.
>> 3) Delay handshaker.started=true so that it would simpler and more
>> precise for an application to handle ALPN.
>>
>
> I agree with 1 and 2, at least in concept if not in specifics, but I think
> 3 is a mistake: if you've committed to an SSL context then it's already too
> late to make some possibly important decisions, and SNI can play a factor
> here too.  We can make this easier but I think that trying to do this all
> inside of the handshake process is going to cut off some important use
> cases.
>
>>
>>
Note that with 3 :

   - Not all decisions have to be made late.  Some logic will need to be
   executed before unwrapping hello, such as trimming the set of available
   ciphers to mutually acceptable ones.
   - You are still free to pick a protocol early - ie before hello unwrap
   if you can/want

The process we are working towards in jetty is three phase: firstly we trim
ciphers and protocol list; then we allow SslEngine to pick the specific
cipher (using certificates and/or SNI); finally we want to pick the
protocol based on the cipher AND the earlier work trimming
ciphers/protocols.

So definitely don't want to "do this all inside of the handshake process".
Just want to ability to make the final protocol choice after the final
cipher decision has been made in the hello unwrap.Again, this would be
optional and you could do it all before if you don't want to support the
edge cases where this is needed.

cheers



-- 
Greg Wilkins  CTO http://webtide.com


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Jason Greene

> On Jun 15, 2016, at 2:25 PM, Simone Bordet  wrote:
> 
> Hi,
> 
> On Wed, Jun 15, 2016 at 8:12 PM, Jason Greene  wrote:
>> Here is an H2 example:
>> 
>> The ClientHello expressing interest in both h2, and h1, and lists the 
>> ciphers:
>>TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
>>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
>> 
>> So in this case the client is expressing a preference for a CBC cipher using 
>> stronger keys, but is blacklisted by h2 due to not being GCM, but this is 
>> allowed by h1. The JDK will follow the client hello as the TLS spec 
>> describes, and so it will select TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, and 
>> the protocol stack will incorrectly select h1.
>> 
>> Now technically H2 clients can avoid this by ordering h2 compliant ciphers 
>> on top, but they might not do so.
>> 
>> The flaw really starts to show when you have multiple alternative protocols 
>> with completely different requirements. As an example, if you have a 
>> hypothetical protocol which does not perform certificate based 
>> authentication, and instead utilizes pre-shared keys or anonymous ciphers, 
>> that protocol can never be selected unless those algs are on the top of the 
>> list, if they are on the top of the list then h2 can’t be selected.
>> 
> 
> I'm not sure what you want to show here.
> If you want to prefer ciphers, you have to give up on protocol and
> viceversa, that's normal business.
> 
> If there is no decision, then there is a conflict; if there is a
> decision, then the solution I propose works equally well to what you
> guys propose.
> 
> There is no "flaw", it is just undecidable.
> What am I missing ?

The point is that protocol isn’t a function of cipher, rather protocol and 
cipher are two inputs that must be cooperatively analyzed when making a 
decision. If H2 is the preferred protocol, then you analyze the cipher set to 
find the most preferred compliant match. So the best outcome is cipher = 
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256” & protocol = h2. If there isn’t a 
compliant h2 match, then you fall back to h1.

-Jason






Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Simone Bordet
Hi,

On Wed, Jun 15, 2016 at 8:12 PM, Jason Greene  wrote:
> Here is an H2 example:
>
> The ClientHello expressing interest in both h2, and h1, and lists the ciphers:
> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
> TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
>
> So in this case the client is expressing a preference for a CBC cipher using 
> stronger keys, but is blacklisted by h2 due to not being GCM, but this is 
> allowed by h1. The JDK will follow the client hello as the TLS spec 
> describes, and so it will select TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, and 
> the protocol stack will incorrectly select h1.
>
> Now technically H2 clients can avoid this by ordering h2 compliant ciphers on 
> top, but they might not do so.
>
> The flaw really starts to show when you have multiple alternative protocols 
> with completely different requirements. As an example, if you have a 
> hypothetical protocol which does not perform certificate based 
> authentication, and instead utilizes pre-shared keys or anonymous ciphers, 
> that protocol can never be selected unless those algs are on the top of the 
> list, if they are on the top of the list then h2 can’t be selected.
>

I'm not sure what you want to show here.
If you want to prefer ciphers, you have to give up on protocol and
viceversa, that's normal business.

If there is no decision, then there is a conflict; if there is a
decision, then the solution I propose works equally well to what you
guys propose.

There is no "flaw", it is just undecidable.
What am I missing ?

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Jason Greene

> On Jun 15, 2016, at 7:07 AM, David M. Lloyd  wrote:
> 
> On 06/14/2016 09:28 PM, Greg Wilkins wrote:
>> 
>> 
>> On 15 June 2016 at 11:40, Jason T. Greene > > wrote:
>> 
>> 
>>> On Jun 14, 2016, at 7:04 PM, Greg Wilkins > > wrote:
>>>
>>> If SslEngine is changed to allow the negotiated application protocol to 
>> be set up until the time the hello response was wrapped, that would fix the 
>> problem.  Would it create any others?
>> 
>>Well the fundamental issue is that the application protocol isn't a
>>direct function of a cipher, rather the application protocol has a
>>policy of allowed ciphers and optimal selection is finding the most
>>recent protocol with a matching allowed cipher.
>> 
>> 
>> So doesn't that make application protocol a function of the negotiated
>> cipher? Isn't working out which of the acceptable protocols allows
>> the negotiated cipher a function?
> 
> No, you can't take the ciphers and spit out a protocol during handshake.  You 
> also have to consider the host name(s) and available key(s) for each, and in 
> addition you might have separate (possibly pre-existing) SSL contexts for 
> different protocols (after all, protocols aren't just limited to two flavors 
> of HTTP), or you might even want to proxy the connection instead of handling 
> it locally in certain cases.
> 
> But leaving the multiple-SSLContext case aside, the pieces of information 
> that are relevant are:

-snip-

Here is an H2 example:

The ClientHello expressing interest in both h2, and h1, and lists the ciphers:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

So in this case the client is expressing a preference for a CBC cipher using 
stronger keys, but is blacklisted by h2 due to not being GCM, but this is 
allowed by h1. The JDK will follow the client hello as the TLS spec describes, 
and so it will select TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, and the protocol 
stack will incorrectly select h1.

Now technically H2 clients can avoid this by ordering h2 compliant ciphers on 
top, but they might not do so.

The flaw really starts to show when you have multiple alternative protocols 
with completely different requirements. As an example, if you have a 
hypothetical protocol which does not perform certificate based authentication, 
and instead utilizes pre-shared keys or anonymous ciphers, that protocol can 
never be selected unless those algs are on the top of the list, if they are on 
the top of the list then h2 can’t be selected.

-Jason

Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread David M. Lloyd

On 06/15/2016 07:36 AM, Simone Bordet wrote:

Hi,

On Wed, Jun 15, 2016 at 1:31 PM, David M. Lloyd  wrote:

The problem is that this is quite subjective.  In my opinion the current
solution is both clean and precise:

1) Read the hello packet
2) Examine the protocols, host names, and cipher suites
3) Apply arbitrary user policy to select the enabled cipher suites and even
possibly the SSL context to use based on:
* The above information
* The supported cipher suites (for each SSL context, if multiple)
* The available host key types for each host and/or protocol
* Any user-driven factor that goes beyond *just* HTTP 2


Sure, that's the duplication of what the JDK does.
Change logic in the JDK, change logic above.


Sure, the JDK has the same logic but does it go beyond matching the key 
type with the cipher suite?  You can't avoid doing this in the user 
handler AFAICT, so yes that duplication stands.  What kind of change in 
the JDK logic are you thinking of?



How do you avoid to run the application SNI logic twice, once by you,
and once by the JDK ?


You can't avoid it.  But this is different logic: the user chooses which 
host to use (and what SSL context, key, etc.) and the JDK simply 
verifies that choice.



What if that SNI logic, provided by an external application, has side effects ?

Your bullets above are "precise" only under the assumption that those
bullets are exactly what the JDK does.
If it's not the case, then they're broken.

I understand for you is not a big deal to replicate the JDK logic and
keeping it up to date, and banning certain versions of your code to
run with certain versions of the JDK.
I hope you understand it's not the case for others; for example, we
don't control with what JDK versions people run Jetty.

If JDK 10 changes the logic, we will have to say: "Oh, sorry, you
cannot run Jetty 9 (the current version) with JDK 10".
And we won't be able to change the logic in Jetty 9, because we would
break previous JDKs.
We will be back to sniffing what JDK it is. Yuck.


No matter what the JDK does, it will not be able to encapsulate a completely
arbitrary user policy - certainly not precisely - during handshake, nor will
it be able to allow for the selection of different SSLContexts based on that
policy (let alone proxying the connection).


Can you detail a case ?


A very simple case: you have two completely different protocols 
multiplexed on port 443.  Each of these protocols has its own 
SSLContext.  You read the client hello and dispatch to the appropriate 
downstream service based on protocol (and possibly other factors).


Another case is that you have a service running on a separate system. 
If the protocol and/or host matches, the network connection is proxied 
to the downstream system, otherwise it is handled locally.



The best that can be done in the
JDK, in my opinion, is to provide various utilities to simplify implementing
the above: a helpful SSL explorer style class, which includes mapping the
protocol and cipher suite list (which I believe we agree on) and perhaps
providing information about the key type(s) supported by each cipher suite,
so the user can compare this against the available key types.


Unfortunately this SSL Explorer class has not yet been provided.
If it was, it would be helpful. But I think it will just hit the same
problems I hit: logic duplication and running SNI twice.


Once you know what cipher suites are offered, and you have selected the
protocol, host, and enabled cipher suites, there isn't a great deal of
mystery left in the JDK: it simply carries out the negotiation that you
specified.


IFF your logic is the same as the JDK.

I don't want to check this every time a JDK release is made.
Why you enjoy doing this this check, it's a mystery to me :)


I agree with 1 and 2, at least in concept if not in specifics, but I think 3 is 
a mistake:
if you've committed to an SSL context then it's already too late to make some
possibly important decisions, and SNI can play a factor here too.
We can make this easier but I think that trying to do this all inside of the
handshake process is going to cut off some important use cases.


Which use cases ?


Multiple SSLContext, network proxying.


BTW, the delay of handshaker.started=true would be irrelevant to the
TLS mechanism, it's just an implementation detail.
The information that needs to be reported in the ServerHello is only
needed when the ServerHello is being constructed.

Had the JDK implementation been written with a delayed
handshaker.started=true we would have the best of both worlds.
You could write your own solution, we could write our own.
Yours will have some restrictions, and so will ours (just different ones).


Fair enough.

--
- DML


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Simone Bordet
Hi,

On Wed, Jun 15, 2016 at 1:31 PM, David M. Lloyd  wrote:
> The problem is that this is quite subjective.  In my opinion the current
> solution is both clean and precise:
>
> 1) Read the hello packet
> 2) Examine the protocols, host names, and cipher suites
> 3) Apply arbitrary user policy to select the enabled cipher suites and even
> possibly the SSL context to use based on:
>* The above information
>* The supported cipher suites (for each SSL context, if multiple)
>* The available host key types for each host and/or protocol
>* Any user-driven factor that goes beyond *just* HTTP 2

Sure, that's the duplication of what the JDK does.
Change logic in the JDK, change logic above.

How do you avoid to run the application SNI logic twice, once by you,
and once by the JDK ?
What if that SNI logic, provided by an external application, has side effects ?

Your bullets above are "precise" only under the assumption that those
bullets are exactly what the JDK does.
If it's not the case, then they're broken.

I understand for you is not a big deal to replicate the JDK logic and
keeping it up to date, and banning certain versions of your code to
run with certain versions of the JDK.
I hope you understand it's not the case for others; for example, we
don't control with what JDK versions people run Jetty.

If JDK 10 changes the logic, we will have to say: "Oh, sorry, you
cannot run Jetty 9 (the current version) with JDK 10".
And we won't be able to change the logic in Jetty 9, because we would
break previous JDKs.
We will be back to sniffing what JDK it is. Yuck.

> No matter what the JDK does, it will not be able to encapsulate a completely
> arbitrary user policy - certainly not precisely - during handshake, nor will
> it be able to allow for the selection of different SSLContexts based on that
> policy (let alone proxying the connection).

Can you detail a case ?

> The best that can be done in the
> JDK, in my opinion, is to provide various utilities to simplify implementing
> the above: a helpful SSL explorer style class, which includes mapping the
> protocol and cipher suite list (which I believe we agree on) and perhaps
> providing information about the key type(s) supported by each cipher suite,
> so the user can compare this against the available key types.

Unfortunately this SSL Explorer class has not yet been provided.
If it was, it would be helpful. But I think it will just hit the same
problems I hit: logic duplication and running SNI twice.

> Once you know what cipher suites are offered, and you have selected the
> protocol, host, and enabled cipher suites, there isn't a great deal of
> mystery left in the JDK: it simply carries out the negotiation that you
> specified.

IFF your logic is the same as the JDK.

I don't want to check this every time a JDK release is made.
Why you enjoy doing this this check, it's a mystery to me :)

> I agree with 1 and 2, at least in concept if not in specifics, but I think 3 
> is a mistake:
> if you've committed to an SSL context then it's already too late to make some
> possibly important decisions, and SNI can play a factor here too.
> We can make this easier but I think that trying to do this all inside of the
> handshake process is going to cut off some important use cases.

Which use cases ?

BTW, the delay of handshaker.started=true would be irrelevant to the
TLS mechanism, it's just an implementation detail.
The information that needs to be reported in the ServerHello is only
needed when the ServerHello is being constructed.

Had the JDK implementation been written with a delayed
handshaker.started=true we would have the best of both worlds.
You could write your own solution, we could write our own.
Yours will have some restrictions, and so will ours (just different ones).

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread David M. Lloyd

On 06/14/2016 09:28 PM, Greg Wilkins wrote:



On 15 June 2016 at 11:40, Jason T. Greene mailto:jason.gre...@redhat.com>> wrote:


> On Jun 14, 2016, at 7:04 PM, Greg Wilkins mailto:gr...@webtide.com>> wrote:
>
> If SslEngine is changed to allow the negotiated application protocol to 
be set up until the time the hello response was wrapped, that would fix the 
problem.  Would it create any others?

Well the fundamental issue is that the application protocol isn't a
direct function of a cipher, rather the application protocol has a
policy of allowed ciphers and optimal selection is finding the most
recent protocol with a matching allowed cipher.


So doesn't that make application protocol a function of the negotiated
cipher? Isn't working out which of the acceptable protocols allows
the negotiated cipher a function?


No, you can't take the ciphers and spit out a protocol during handshake. 
 You also have to consider the host name(s) and available key(s) for 
each, and in addition you might have separate (possibly pre-existing) 
SSL contexts for different protocols (after all, protocols aren't just 
limited to two flavors of HTTP), or you might even want to proxy the 
connection instead of handling it locally in certain cases.


But leaving the multiple-SSLContext case aside, the pieces of 
information that are relevant are:


* The requested cipher suites and TLS protocol version
* The requested ALPN protocol names (the name, BTW, is all that appears 
in the ClientHello)

* The requested SNI server names
* The SSL context's supported TLS protocol and cipher suite lists
* The available server key(s) (and possibly client key(s) as well), 
which may vary by host as well as by ALPN protocol

* A way to determine which cipher suites can use which key types
* A way to determine which cipher suites can/should be used with which 
TLS protocol versions
* Information about which cipher suites are supported by various ALPN 
protocols


Some of these bits of information are already an existing part of the 
handshake but are done too late in the process to be useful to protocol 
or host selection (for example, choosing a key by key type or trimming 
the cipher suite list by TLS protocol version).  Some of this 
information varies by ALPN protocol, and thus (IMO) has no place in the 
JDK, rather belonging in the protocol server code (for example, the 
policy as to which cipher suites are blacklisted by the ALPN protocol).


You can definitely encapsulate some of this in a general "SSL connection 
information" structure, which is in fact what we (JBoss) are doing now. 
 But the fact remains that you have to do all of this analysis before 
handshake starts for it to work.  And you can't avoid duplicating some 
of the decisions that the target SSL engine has to make.



[...]
In short, either the cipher/SNI logic of SslEngine has to be duplicated
or the selection of the protocol needs to be deferred until after the
cipher is negotiated - either by allowing the setter to be called after
negotiation or by giving the SslEngine the information to know what
protocols are acceptable for which ciphers.


But, you can't negotiate the cipher without considering the ALPN 
protocol.  It's not a one-way decision where the protocol decides the 
cipher suite.  You have to choose a protocol which has a chance to 
succeed because the corresponding cipher suites and key, but also you 
choose the cipher suites based on the policy of the protocol and 
available keys.  The decision has to be made all at once, otherwise you 
risk choosing a protocol and cipher suite for which you have no key, or 
a protocol and key for which there is no matching cipher suite, etc.



I believe that duplication is unacceptable for a new feature like ALPN.
   Does anybody really believe that it is acceptable?
Are there any other alternatives other than the ones I've outlined above?


Well, I agree it's not ideal.  But I do not think a better (and also 
achievable) option has yet been proposed which does not exclude 
important use cases.  The current approach has the distinct advantage of 
being workable, imperfect though it may seem.


--
- DML


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread David M. Lloyd

On 06/15/2016 03:35 AM, Simone Bordet wrote:

Hi,

On Wed, Jun 15, 2016 at 10:15 AM, Andrew Haley  wrote:

The problem I have with reading posts about JDK9 problems is that I
can't tell the *severity* of the problems.  I don't know if something
is a total blocker or an inconvenience.  When someone uses an internal
sun.* class they may be doing something which must be done in order to
get access which would be impossible otherwise.


I don't understand this comment.

The main issue of this thread is the current impossibility to have a
clean and precise ALPN implementation with minimal code.


The problem is that this is quite subjective.  In my opinion the current 
solution is both clean and precise:


1) Read the hello packet
2) Examine the protocols, host names, and cipher suites
3) Apply arbitrary user policy to select the enabled cipher suites and 
even possibly the SSL context to use based on:

   * The above information
   * The supported cipher suites (for each SSL context, if multiple)
   * The available host key types for each host and/or protocol
   * Any user-driven factor that goes beyond *just* HTTP 2

No matter what the JDK does, it will not be able to encapsulate a 
completely arbitrary user policy - certainly not precisely - during 
handshake, nor will it be able to allow for the selection of different 
SSLContexts based on that policy (let alone proxying the connection). 
The best that can be done in the JDK, in my opinion, is to provide 
various utilities to simplify implementing the above: a helpful SSL 
explorer style class, which includes mapping the protocol and cipher 
suite list (which I believe we agree on) and perhaps providing 
information about the key type(s) supported by each cipher suite, so the 
user can compare this against the available key types.


Once you know what cipher suites are offered, and you have selected the 
protocol, host, and enabled cipher suites, there isn't a great deal of 
mystery left in the JDK: it simply carries out the negotiation that you 
specified.



Sure we can fallback to less optimal solutions that won't work in all cases.
Sure we can duplicate the JDK logic and keep it up-to-date, invoke SNI
twice, etc.
But I don't see the point of settling for a less than optimal solution
when there is room to make it better, and the effort is minimal.

Is this issue a blocker ? Surely not, it is possible to rewrite from
scratch a JSSE provider.
Would I do that ? No, thanks.

I am proposing 3 simple changes to be done:

1) Introduce a TLSProtocolNames class that can convert from TLS
protocol bytes to TLS protocol names.
2) Introduce a TLSCipherSuiteNames class that can convert from TLS
cipher suite bytes to TLS cipher suite names.
3) Delay handshaker.started=true so that it would simpler and more
precise for an application to handle ALPN.


I agree with 1 and 2, at least in concept if not in specifics, but I 
think 3 is a mistake: if you've committed to an SSL context then it's 
already too late to make some possibly important decisions, and SNI can 
play a factor here too.  We can make this easier but I think that trying 
to do this all inside of the handshake process is going to cut off some 
important use cases.



I think these changes will benefit all the people involved in network
servers having to play with ALPN.

We *are* still in time, according to Mark Reinhold.
The changes are simple.

We have not heard from Oracle yet, but I can prepare a webrev if that helps.



--
- DML


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Simone Bordet
Hi,

On Wed, Jun 15, 2016 at 10:15 AM, Andrew Haley  wrote:
> The problem I have with reading posts about JDK9 problems is that I
> can't tell the *severity* of the problems.  I don't know if something
> is a total blocker or an inconvenience.  When someone uses an internal
> sun.* class they may be doing something which must be done in order to
> get access which would be impossible otherwise.

I don't understand this comment.

The main issue of this thread is the current impossibility to have a
clean and precise ALPN implementation with minimal code.
Sure we can fallback to less optimal solutions that won't work in all cases.
Sure we can duplicate the JDK logic and keep it up-to-date, invoke SNI
twice, etc.
But I don't see the point of settling for a less than optimal solution
when there is room to make it better, and the effort is minimal.

Is this issue a blocker ? Surely not, it is possible to rewrite from
scratch a JSSE provider.
Would I do that ? No, thanks.

I am proposing 3 simple changes to be done:

1) Introduce a TLSProtocolNames class that can convert from TLS
protocol bytes to TLS protocol names.
2) Introduce a TLSCipherSuiteNames class that can convert from TLS
cipher suite bytes to TLS cipher suite names.
3) Delay handshaker.started=true so that it would simpler and more
precise for an application to handle ALPN.

I think these changes will benefit all the people involved in network
servers having to play with ALPN.

We *are* still in time, according to Mark Reinhold.
The changes are simple.

We have not heard from Oracle yet, but I can prepare a webrev if that helps.

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Andrew Haley
On 15/06/16 09:11, Simone Bordet wrote:
> Sure, but then every ALPN implementer out there will have their own,
> they will need to be kept up to date when a new TLS protocol or a new
> cipher is introduced in the JDK, etc. etc.

OK, I get that.

The problem I have with reading posts about JDK9 problems is that I
can't tell the *severity* of the problems.  I don't know if something
is a total blocker or an inconvenience.  When someone uses an internal
sun.* class they may be doing something which must be done in order to
get access which would be impossible otherwise.

Andrew.



Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Simone Bordet
Hi,

On Wed, Jun 15, 2016 at 10:03 AM, Andrew Haley  wrote:
> On 14/06/16 14:57, Simone Bordet wrote:
>> * Lack of facilities to convert TLS protocol bytes to protocol strings.
>> This class already exist in JDK, sun.security.ssl.ProtocolVersion, it
>> would just need to be exposed in javax.net.ssl.
>>
>> * Lack of facilities to convert TLS cipher bytes to cipher name strings.
>> As above, sun.security.ssl.CipherSuite exists, needs to be exposed publicly.
>>
>> Note that for the 2 bullets above, a recent message from Mark Reinhold
>> to jdk9-dev confirmed that JDK 9 is *not yet* feature complete, so I
>> hope they can be considered for inclusion.
>
> It's very late,

It's not too late, like Mark Reinhold said.

> and they certainly won't be considered unless
> someone proposes it.

I just did.

>  But can't we simply clone this class anyway?

Sure, but then every ALPN implementer out there will have their own,
they will need to be kept up to date when a new TLS protocol or a new
cipher is introduced in the JDK, etc. etc.
The TLS ciphers in the JDK have non-standard names for historical reasons, etc.

The classes are trivial, and can be tiny wrappers around the existing
ones like TLSProtocolNames and CipherSuiteNames.

> Incidentally, I can't tell which (if any) of the issues you describe
> are specific to JDK 9 (i.e. they would not be problems in JDK 8.)

Not sure what you mean here.
Unless you parse the TLS protocol in JDK 8, there is no particular
need for those classes.
With JDK9 we now need to parse the TLS protocol to handle ALPN, so
those classes would be handy.

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-15 Thread Andrew Haley
On 14/06/16 14:57, Simone Bordet wrote:
> * Lack of facilities to convert TLS protocol bytes to protocol strings.
> This class already exist in JDK, sun.security.ssl.ProtocolVersion, it
> would just need to be exposed in javax.net.ssl.
> 
> * Lack of facilities to convert TLS cipher bytes to cipher name strings.
> As above, sun.security.ssl.CipherSuite exists, needs to be exposed publicly.
> 
> Note that for the 2 bullets above, a recent message from Mark Reinhold
> to jdk9-dev confirmed that JDK 9 is *not yet* feature complete, so I
> hope they can be considered for inclusion.

It's very late, and they certainly won't be considered unless
someone proposes it.  But can't we simply clone this class anyway?

Incidentally, I can't tell which (if any) of the issues you describe
are specific to JDK 9 (i.e. they would not be problems in JDK 8.)

Andrew.



Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Greg Wilkins
On 15 June 2016 at 11:40, Jason T. Greene  wrote:
>
>
> > On Jun 14, 2016, at 7:04 PM, Greg Wilkins  wrote:
> >
> > If SslEngine is changed to allow the negotiated application protocol to
> be set up until the time the hello response was wrapped, that would fix the
> problem.  Would it create any others?
>
> Well the fundamental issue is that the application protocol isn't a direct
> function of a cipher, rather the application protocol has a policy of
> allowed ciphers and optimal selection is finding the most recent protocol
> with a matching allowed cipher.


So doesn't that make application protocol a function of the negotiated
cipher? Isn't working out which of the acceptable protocols allows the
negotiated cipher a function?


Put another way,  it is not possible to implement:

Protocol selectProtocol(List mutualAcceptableCiphers,
List mutualAcceptableProtocols)

such that it always returns a correct result, as a acceptable cipher may
not allowable for a given acceptable protocol.   Furthermore it ls not
possible to implement:

String selectProtocol(List> mutualAcceptable)

because within that function there is no indication of what ciphers might
be negotiated.


So further information is needed, which could either be:

String selectProtocol(List> mutualAcceptable,
  List availableCertificates,
  IPAddress host)

Which requires the implementation to rework the certificate selection and
SNI logic that is already performed by SslEngine.  Either this logic needs
to be duplicated (fragile) or an extra instance of SslEngine would need to
be used to duplicate the logic.

Alternately the function could be implemented as:

String selectProtocol(List> mutualAcceptable,

  Cipher negotiatedCipher)

ie a function of the negotiated cipher, but as the negotiatedCipher is
known only after the Hello message is unwrapped, this would require that
SslEngine allows setApplicationProtocol to be called after the hello unwrap
but before the hello response wrap.

I guess the other alternative would be to replace the SSLParameters.
setApplicationProtocols(List) method with something like:

SSLParameters.setApplicationProtocols(Function
selectProtocol)

or

SSLParameters.setApplicationProtocols(List>
cipherProtocolPairs)

or

SSLParameters.setApplicationProtocols(Map>
protocolsForCiphers)



In short, either the cipher/SNI logic of SslEngine has to be duplicated or
the selection of the protocol needs to be deferred until after the cipher
is negotiated - either by allowing the setter to be called after
negotiation or by giving the SslEngine the information to know what
protocols are acceptable for which ciphers.


I believe that duplication is unacceptable for a new feature like ALPN.
Does anybody really believe that it is acceptable?
Are there any other alternatives other than the ones I've outlined above?

cheers

PS. The Cipher and Protocol types would most likely just be String in all
of the above examples. Using strong typing in the examples for clarity.










-- 
Greg Wilkins  CTO http://webtide.com


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Jason T. Greene



> On Jun 14, 2016, at 7:04 PM, Greg Wilkins  wrote:
> 
> If SslEngine is changed to allow the negotiated application protocol to be 
> set up until the time the hello response was wrapped, that would fix the 
> problem.  Would it create any others?

Well the fundamental issue is that the application protocol isn't a direct 
function of a cipher, rather the application protocol has a policy of allowed 
ciphers and optimal selection is finding the most recent protocol with a 
matching allowed cipher.

Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Greg Wilkins
I think this discussion can be simplified to the following points:

   - ALPN allows for a negotiated application protocol to be a function of
   the cipher negotiated ( h2 vs h1 selection being the prime use-case).
   - The cipher is negotiated by SslEngine during the unwrap of the Hello
   message
   - The negotiated application protocol is sent by SslEngine during the
   following wrap of the Hello response.
   - SslEngined does not allow the negotiated protocol to be set after the
   unwrap of the Hello message.

So this last point means that SslEngine does not allow the negotiated
protocol to be a function of the negotiated cipher.  Sure there are
ways to work around this limitation (guessing, running duplicate sslEngine
instances etc.), but we should have to work around limitations in a newly
released feature!

If SslEngine is changed to allow the negotiated application protocol to be
set up until the time the hello response was wrapped, that would fix the
problem.  Would it create any others?

cheers

-- 
Greg Wilkins  CTO http://webtide.com


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Jason Greene

> On Jun 14, 2016, at 2:52 PM, Simone Bordet  wrote:
> 
> Hi,
> 
> On Tue, Jun 14, 2016 at 8:11 PM, Jason Greene  wrote:
>> If the case is that H3 blacks all RSA, then thats an easy test right? Just 
>> verify that keystore has an ECDSA key.
> 
> I don't think it is that easy.

Well certificate mechanisms aren’t introduced that often, so its probably good 
enough under such a scenario.

As a related tangent, it’s hard to imagine that RSA would get blacklisted 
unless quantum immune algorithms were rolling out, but that seems a long long 
long way away. 

> 
> The server logic has to mimic exactly what the JDK logic is, that is
> to verify the cipher and certificate compatibility.
> Not only, the server has to run the logic for SNI, the same logic that
> the JDK runs to get the right certificate. This logic would now run
> twice.
> 
> As I said, it is doable as long as the server logic duplicates and
> keeps in sync with the JDK logic so that it is guaranteed that the
> application protocol chosen by the server ends up with a cipher,
> chosen by the JDK, valid for that protocol.
> The moment the logic is different, there is a problem.

I think the issue is that to make the decision 100% perfect, you have to 
evaluate a number of factors together (ciphers, tls protocol, alpn protocol, 
key material, etc). The JDK TLS impl could certainly do it, but unfortunately, 
as you know, it was decided there wasn’t enough time to redesign the 
implementaiton in 9 to accommodate a multi factor negotiation incorporating 
alpn (the tuple approach). There’s also a secondary problem that new 
application protocols could be introduced before the JDK is aware of them, and 
with varying cipher requirements. So to make a tuple based JDK impl work, you 
would have to introduce a callback API with rich information for the 
application to use, and it would have to understand a lot about ciphers to use 
this. 

Ultimately we ended with a defer to application plan, which does allow for a 
perfect decision, but it does put a burden on the app for sure, but its not 
much more than what a callback approach like I mentioned above would require. 

If we let the JDK negotiate the cipher, and then the app negotiates the 
protocol separately, you can end up with wrong answers as well. For example, 
stick an h2 blacklisted cipher higher on the order list in ClientHello, and you 
can end up forcing h1 instead of h2, even if there is a perfectly valid h2 
cipher present. 
> 
> Every time the JDK updates, you and me have to go and look inside the
> JDK to check whether the logic is changed, and if so, update our
> servers.
> And then we have to say that version X of our server only works with
> JDKs up to version Y, and that version X+1 of our server only works
> with JDK version Y+1.
> Been there, done that. I'd like to move to a better model that is future 
> proof.
> I don't control which JDK people use to run Jetty.


I don’t see the challenge in supporting old JDK versions with the same 
up-to-date server code (at least after Java 9 where the app can control all of 
this)? 


> 
> I would rather not duplicate all the JDK logic into an application.

Well I think the “lazy” approach I described before would work quite well with 
very few application updates necessary, basically zero today, and another 
whenever a new HTTP/X version rolls out, but you have to do that anyway. With a 
more thorough application stack though its possible to make perfect decisions 
on these sorts of things. 

I can appreciate the desire not to duplicate the JDK; it would be nice to see a 
richer tuple based impl in the future. 

> 
> Thanks !
> 






Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Simone Bordet
Hi,

On Tue, Jun 14, 2016 at 8:11 PM, Jason Greene  wrote:
> If the case is that H3 blacks all RSA, then thats an easy test right? Just 
> verify that keystore has an ECDSA key.

I don't think it is that easy.

The server logic has to mimic exactly what the JDK logic is, that is
to verify the cipher and certificate compatibility.
Not only, the server has to run the logic for SNI, the same logic that
the JDK runs to get the right certificate. This logic would now run
twice.

As I said, it is doable as long as the server logic duplicates and
keeps in sync with the JDK logic so that it is guaranteed that the
application protocol chosen by the server ends up with a cipher,
chosen by the JDK, valid for that protocol.
The moment the logic is different, there is a problem.

Every time the JDK updates, you and me have to go and look inside the
JDK to check whether the logic is changed, and if so, update our
servers.
And then we have to say that version X of our server only works with
JDKs up to version Y, and that version X+1 of our server only works
with JDK version Y+1.
Been there, done that. I'd like to move to a better model that is future proof.
I don't control which JDK people use to run Jetty.

I would rather not duplicate all the JDK logic into an application.

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Jason Greene

> On Jun 14, 2016, at 10:58 AM, Simone Bordet  wrote:
> 
> Hi,
> 
> On Tue, Jun 14, 2016 at 5:26 PM, Jason T. Greene
>  wrote:
>> With H2 all impls are required to support 
>> TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
> 
> Unless it is discovered vulnerable.

Sure, but in that case we have to rev the H2 protocol to fix it (h2.1 or 
something), and users will probably have to deploy intermediate solutions (like 
JSSE configs) to address it. 

> 
>> so that should be selectable either by your protocol stack or the TLS layer. 
>>  If you wanted to be especially lazy you could just exclude any blacklisted 
>> cipher list presented in the client hello,  and verify that additional ones 
>> are present, and if so set the rest as the available cipher set in SSL 
>> params. The TLS stack will pick appropriately at that point.
> 
> Not in general, see my example.
> The server could choose an ECDSA cipher for h3, the mandatory cipher
> for h2, so the list of cipher is (ECDSA, RSA). If, at this point, the
> server chooses the protocol *before* the JDK chooses the cipher, it
> may think that h3 is a good choice, but the TLS stack chooses the RSA
> cipher.
> At this point, you have the h3 protocol with the RSA cipher, which may
> be an invalid combination.

In the case that the client doesn’t present a valid H3 cipher, that can be 
determined by removing all blacklisted ciphers (and unsupported ciphers), and 
ultimately wind up with an empty set. 

If the case is that H3 blacks all RSA, then thats an easy test right? Just 
verify that keystore has an ECDSA key.


-Jason



Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Simone Bordet
Hi,

On Tue, Jun 14, 2016 at 5:58 PM, Simone Bordet  wrote:
> The server could choose an ECDSA cipher for h3, the mandatory cipher
> for h2, so the list of cipher is (ECDSA, RSA). If, at this point, the
> server chooses the protocol *before* the JDK chooses the cipher, it
> may think that h3 is a good choice, but the TLS stack chooses the RSA
> cipher.
> At this point, you have the h3 protocol with the RSA cipher, which may
> be an invalid combination.

Just to add more information here.

If the server logic chooses h3 and also restricts the ciphers to only
(ECDSA) to make sure that h3 is chosen, the JDK may find that the
cipher is not good for the certificate, and therefore there are no
ciphers in common and the connection is terminated. There is no
negotiation, although h2 with RSA would have been a valid combination.

If handshaker.started=true is delayed, the server could wait for the
JDK to choose a cipher, and then a suitable protocol for that cipher,
which in the example would be h2, and the negotiation would be
successful.

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Thomas Lußnig

Hi,

i think not only the cipher suite and protocol version. But many other 
parts should be also

be public. Like Supported digest, curve types, etc...
And also these information should be available for the keymanger.
So that he is able to select certificate also based on the curve types.

Gruß Thomas


Am 14.06.2016 um 15:57 schrieb Simone Bordet:

Hi,

I gave a shot at implementing ALPN in JDK 9 in Jetty.

TLDR: I could not find a way to make it work. This email is to discuss
whether I am off road or discuss possible solutions.

Below my feedback.

* Lack of facilities to convert TLS protocol bytes to protocol strings.
This class already exist in JDK, sun.security.ssl.ProtocolVersion, it
would just need to be exposed in javax.net.ssl.

* Lack of facilities to convert TLS cipher bytes to cipher name strings.
As above, sun.security.ssl.CipherSuite exists, needs to be exposed publicly.

Note that for the 2 bullets above, a recent message from Mark Reinhold
to jdk9-dev confirmed that JDK 9 is *not yet* feature complete, so I
hope they can be considered for inclusion.

* Server-side Implementation
I followed the guidelines reported here:
http://mail.openjdk.java.net/pipermail/security-dev/2015-December/013132.html,
namely:

1) Read network bytes after initial connection.
2) Parse network bytes, expecting TLS ClientHello message.
3) Extract from ClientHello the TLS protocol version, the TLS ciphers,
the ALPN protocols.

At this point, I should negotiate the application protocol, and it
must be only one.

Assuming the ClientHello TLS protocol is spoken by both peers, the
server logic can create pairs (cipher, app_proto) for each of the
ciphers in common between client and server, and discard the ciphers
that are not good for any protocol.

At this point, among all the valid pairs, I need to choose a protocol.
Let's make an example; the pairs are:

(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, h3)
(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, h2)
(TLS_WHATEVER, http/1.1)

Here "h3" is the future HTTP/3 protocol which I picked as an example
to show the problem I will encounter.

Because at this point the server logic must choose one protocol only
(so that it can be returned in the ServerHello), it picks h3, which
goes along with a ECDSA cipher, so:

sslParams.setApplicationProtocols(new String[]{"h3"});
sslParams.setCipherSuites(new
String[]{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ...);
sslEngine.setSSLParameters(sslParams);

At this point, the server logic is good to let SSLEngine do the
unwrap(), and pass the original network bytes to unwrap().

During the unwrap(), the JDK implementation picks a cipher based on
the JDK logic.
In particular, in my case, I had a keystore with a certificate that
was *not* ECDSA.
If, in the snippet above, I set more than one cipher on the
SSLParameters, then perhaps a weaker cipher could be negotiated that
is not good for h3.
Otherwise, if I set only one cipher, there are no ciphers in common
and the TLS handshake is terminated with an error.

Bottom line, no negotiation is possible with this approach.

Next attempt I made was that before calling unwrap(), the server code
opens the keystore, and verifies if the certificate is ECDSA, handles
SNI, etc.

However, this means duplicating all the JDK logic to make sure that
the server logic *before* calling unwrap() is the same of the JDK so
that when unwrap() is called there will be no failures.

I don't think this is maintainable; the JDK is entitled to change the
logic following CVEs, optimizations and what not, and each such change
risks to break existing server code.

I then tried another approach.

In the server code, before calling unwrap(), I would remember the
pairs (cipher, app_proto), but *not* calling
SSLParameters.setApplicationProtocol().

I would then call unwrap(), where the JDK would choose the cipher.
The cipher is chosen in the NEED_TASK step of the unwrap(), so after
the task is run, the cipher chosen by the JDK is now available to the
server logic.

At this point I called again the server logic and, given the exact
cipher, choose the right protocol among the pairs that I have
previously stored.
In the example above, the JDK would have chose the RSA cipher because
the certificate was not ECDSA, and the server logic would have chosen
h2 as the application protocol:

sslParams.setApplicationProtocol(new String[]{"h2"});

Then let the unwrap()/wrap() code to finish the TLS handshake (in
particular, generate the ServerHello).

This approach has the benefit of cipher pre-selection done by the
server logic (it will retain not the intersection of ciphers between
client and server, but a possibly more restricted set that is valid
for the application protocols that are supported - imagine when
http/1.1 is not supported), coupled with JDK logic to interact with
SNI and certificates, coupled with a "late" selection of the
application protocol based on the cipher selected by the JDK logic.

Unfortunately, it does not work.

It does n

Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Simone Bordet
Hi,

On Tue, Jun 14, 2016 at 5:26 PM, Jason T. Greene
 wrote:
> With H2 all impls are required to support 
> TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Unless it is discovered vulnerable.

> so that should be selectable either by your protocol stack or the TLS layer.  
> If you wanted to be especially lazy you could just exclude any blacklisted 
> cipher list presented in the client hello,  and verify that additional ones 
> are present, and if so set the rest as the available cipher set in SSL 
> params. The TLS stack will pick appropriately at that point.

Not in general, see my example.
The server could choose an ECDSA cipher for h3, the mandatory cipher
for h2, so the list of cipher is (ECDSA, RSA). If, at this point, the
server chooses the protocol *before* the JDK chooses the cipher, it
may think that h3 is a good choice, but the TLS stack chooses the RSA
cipher.
At this point, you have the h3 protocol with the RSA cipher, which may
be an invalid combination.

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Jason T. Greene


> On Jun 14, 2016, at 8:58 AM, Simone Bordet  wrote:
> 
> During the unwrap(), the JDK implementation picks a cipher based on
> the JDK logic.
> In particular, in my case, I had a keystore with a certificate that
> was *not* ECDSA.
> If, in the snippet above, I set more than one cipher on the
> SSLParameters, then perhaps a weaker cipher could be negotiated that
> is not good for h3.
> Otherwise, if I set only one cipher, there are no ciphers in common
> and the TLS handshake is terminated with an error.

With H2 all impls are required to support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
, so that should be selectable either by your protocol stack or the TLS layer.  
If you wanted to be especially lazy you could just exclude any blacklisted 
cipher list presented in the client hello,  and verify that additional ones are 
present, and if so set the rest as the available cipher set in SSL params. The 
TLS stack will pick appropriately at that point. This is future proof, because 
an H protocol version increase is required to introduce further restrictions. 
Once you have code that understands the new H version you can add additional 
blacklisted values for that version, and you are once again future proof.

Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Simone Bordet
Hi,

On Tue, Jun 14, 2016 at 4:53 PM, David M. Lloyd  wrote:
> Yes.  Basically the server logic always has to be up to date with the latest
> cipher suites and that sort of thing.  Our solution to this is to have a
> security framework that is responsible for this (among other things).  It's
> not ideal but it seems to work OK so far.

Right, but this is not always possible.

To cite our experience, we have people running Jetty 5 in JDK 1.4.
That some few hundreds releases back for both Jetty and the JDK.
Point being, we never know what version of Jetty people run with what JDK.

We already painfully maintain Jetty's alpn-boot implementation for JDK
8 changing it for every JDK change.
We hoped to get rid of that with JDK 9, but currently that does not
seem possible.

I really hope that handshaker.started=true could be delayed (or a
similar solution) to give room to a forward compatible ALPN
implementation that can be run with any JDK 9+.

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread David M. Lloyd

On 06/14/2016 09:47 AM, Simone Bordet wrote:

Hi,

On Tue, Jun 14, 2016 at 4:31 PM, David M. Lloyd  wrote:

During the unwrap(), the JDK implementation picks a cipher based on
the JDK logic.
In particular, in my case, I had a keystore with a certificate that
was *not* ECDSA.


Could you not use the available keys as an input into your own protocol
selection?  Granted you have to know what kind of key works with what
algorithm, but if you already have a table of cipher suites, you might as
well just add it on there...


By "keys" here you mean, exactly ?


I'm referring to where you point out that when you read your server key 
from the key store, it didn't work with the cipher(s) that was/were 
associated with the protocol that was selected.



However, this means duplicating all the JDK logic to make sure that
the server logic *before* calling unwrap() is the same of the JDK so
that when unwrap() is called there will be no failures.


I don't think you have to duplicate the exact logic though.  It's not really
a "black box": if you know the cipher suites supported by your available
key(s) then you should have enough information to know, based on the client
cipher suites and the per-protocol suites, and the cipher suites available
in the SSL context(s), which protocols can complete.


Well, perhaps.

My point is that I implement some logic in the server, say version 10.
Server 10 works with JDK 9.1.0.
Time passes, JDK gets updated to 9.1.173, which has now a different
logic, for whatever reason.
Try to run server 10 with JDK 9.1.173 does not negotiate the right protocol.


I don't think this is maintainable; the JDK is entitled to change the
logic following CVEs, optimizations and what not, and each such change
risks to break existing server code.



What kind of change do you anticipate being a breaking change?  Are you
thinking of e.g. blacklisting some known-bad cipher suite or something?


Well, take ECDSA for instance. Before that, my logic on server version
10 was not caring about ECDSA.
My server version 10 was working with JDK 5, but not with JDK 9
(assuming that JDK 5 did not have support for ECDSA).
That is a breaking change to me.

I imagine in the future ECDSA be replaced by something else, or a
different DSA being used, I have to change the server code.
I would like to avoid that, and keep the server logic independent of
how the JDK chooses the cipher.

Makes sense ?


Yes.  Basically the server logic always has to be up to date with the 
latest cipher suites and that sort of thing.  Our solution to this is to 
have a security framework that is responsible for this (among other 
things).  It's not ideal but it seems to work OK so far.


--
- DML


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread Simone Bordet
Hi,

On Tue, Jun 14, 2016 at 4:31 PM, David M. Lloyd  wrote:
>> During the unwrap(), the JDK implementation picks a cipher based on
>> the JDK logic.
>> In particular, in my case, I had a keystore with a certificate that
>> was *not* ECDSA.
>
> Could you not use the available keys as an input into your own protocol
> selection?  Granted you have to know what kind of key works with what
> algorithm, but if you already have a table of cipher suites, you might as
> well just add it on there...

By "keys" here you mean, exactly ?

>> However, this means duplicating all the JDK logic to make sure that
>> the server logic *before* calling unwrap() is the same of the JDK so
>> that when unwrap() is called there will be no failures.
>
> I don't think you have to duplicate the exact logic though.  It's not really
> a "black box": if you know the cipher suites supported by your available
> key(s) then you should have enough information to know, based on the client
> cipher suites and the per-protocol suites, and the cipher suites available
> in the SSL context(s), which protocols can complete.

Well, perhaps.

My point is that I implement some logic in the server, say version 10.
Server 10 works with JDK 9.1.0.
Time passes, JDK gets updated to 9.1.173, which has now a different
logic, for whatever reason.
Try to run server 10 with JDK 9.1.173 does not negotiate the right protocol.

>> I don't think this is maintainable; the JDK is entitled to change the
>> logic following CVEs, optimizations and what not, and each such change
>> risks to break existing server code.
>
>
> What kind of change do you anticipate being a breaking change?  Are you
> thinking of e.g. blacklisting some known-bad cipher suite or something?

Well, take ECDSA for instance. Before that, my logic on server version
10 was not caring about ECDSA.
My server version 10 was working with JDK 5, but not with JDK 9
(assuming that JDK 5 did not have support for ECDSA).
That is a breaking change to me.

I imagine in the future ECDSA be replaced by something else, or a
different DSA being used, I have to change the server code.
I would like to avoid that, and keep the server logic independent of
how the JDK chooses the cipher.

Makes sense ?

Thanks !

-- 
Simone Bordet

http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.


Re: Issues with ALPN implementation in JDK 9

2016-06-14 Thread David M. Lloyd

I have a few questions, inline.

On 06/14/2016 08:57 AM, Simone Bordet wrote:

Hi,

I gave a shot at implementing ALPN in JDK 9 in Jetty.

TLDR: I could not find a way to make it work. This email is to discuss
whether I am off road or discuss possible solutions.

Below my feedback.

* Lack of facilities to convert TLS protocol bytes to protocol strings.
This class already exist in JDK, sun.security.ssl.ProtocolVersion, it
would just need to be exposed in javax.net.ssl.



* Lack of facilities to convert TLS cipher bytes to cipher name strings.
As above, sun.security.ssl.CipherSuite exists, needs to be exposed publicly.


This would *definitely* be a real nice-to-have. Just having spent way 
too long creating our own lookup table...



Note that for the 2 bullets above, a recent message from Mark Reinhold
to jdk9-dev confirmed that JDK 9 is *not yet* feature complete, so I
hope they can be considered for inclusion.

* Server-side Implementation
I followed the guidelines reported here:
http://mail.openjdk.java.net/pipermail/security-dev/2015-December/013132.html,
namely:

1) Read network bytes after initial connection.
2) Parse network bytes, expecting TLS ClientHello message.
3) Extract from ClientHello the TLS protocol version, the TLS ciphers,
the ALPN protocols.

At this point, I should negotiate the application protocol, and it
must be only one.

Assuming the ClientHello TLS protocol is spoken by both peers, the
server logic can create pairs (cipher, app_proto) for each of the
ciphers in common between client and server, and discard the ciphers
that are not good for any protocol.

At this point, among all the valid pairs, I need to choose a protocol.
Let's make an example; the pairs are:

(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, h3)
(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, h2)
(TLS_WHATEVER, http/1.1)

Here "h3" is the future HTTP/3 protocol which I picked as an example
to show the problem I will encounter.

Because at this point the server logic must choose one protocol only
(so that it can be returned in the ServerHello), it picks h3, which
goes along with a ECDSA cipher, so:

sslParams.setApplicationProtocols(new String[]{"h3"});
sslParams.setCipherSuites(new
String[]{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ...);
sslEngine.setSSLParameters(sslParams);

At this point, the server logic is good to let SSLEngine do the
unwrap(), and pass the original network bytes to unwrap().

During the unwrap(), the JDK implementation picks a cipher based on
the JDK logic.
In particular, in my case, I had a keystore with a certificate that
was *not* ECDSA.


Could you not use the available keys as an input into your own protocol 
selection?  Granted you have to know what kind of key works with what 
algorithm, but if you already have a table of cipher suites, you might 
as well just add it on there...



If, in the snippet above, I set more than one cipher on the
SSLParameters, then perhaps a weaker cipher could be negotiated that
is not good for h3.
Otherwise, if I set only one cipher, there are no ciphers in common
and the TLS handshake is terminated with an error.

Bottom line, no negotiation is possible with this approach.

Next attempt I made was that before calling unwrap(), the server code
opens the keystore, and verifies if the certificate is ECDSA, handles
SNI, etc.

However, this means duplicating all the JDK logic to make sure that
the server logic *before* calling unwrap() is the same of the JDK so
that when unwrap() is called there will be no failures.


I don't think you have to duplicate the exact logic though.  It's not 
really a "black box": if you know the cipher suites supported by your 
available key(s) then you should have enough information to know, based 
on the client cipher suites and the per-protocol suites, and the cipher 
suites available in the SSL context(s), which protocols can complete.



I don't think this is maintainable; the JDK is entitled to change the
logic following CVEs, optimizations and what not, and each such change
risks to break existing server code.


What kind of change do you anticipate being a breaking change?  Are you 
thinking of e.g. blacklisting some known-bad cipher suite or something?


(eom)


I then tried another approach.

In the server code, before calling unwrap(), I would remember the
pairs (cipher, app_proto), but *not* calling
SSLParameters.setApplicationProtocol().

I would then call unwrap(), where the JDK would choose the cipher.
The cipher is chosen in the NEED_TASK step of the unwrap(), so after
the task is run, the cipher chosen by the JDK is now available to the
server logic.

At this point I called again the server logic and, given the exact
cipher, choose the right protocol among the pairs that I have
previously stored.
In the example above, the JDK would have chose the RSA cipher because
the certificate was not ECDSA, and the server logic would have chosen
h2 as the application protocol:

sslParams.setApplicationProtocol(new String[]{"h2"});