Simone,

I'm sorry for the delay in responding, I've been getting familiar with lambdas the last couple days, and how we might be able to apply it to the ALPNSelector code. Interesting stuff.


To the question in this email. I'll leave the previous discussion for context. See my responses inline.

On 5/27/2015 4:47 AM, Simone Bordet wrote:
Hi,

On Tue, May 26, 2015 at 8:46 PM, Bradford Wetmore
<bradford.wetm...@oracle.com> wrote:
I am not sure I follow this. Can you please sketch the steps/algorithm
that will be done in your proposed solution ?

I'm assuming you are talking about 1a and not 1b.

Sure, most of the heavy lifting takes place in ServerHandshaker.

ServerHandshaker.java
=====================

In the SunJSSE code:

     // currently line 330.
     private void clientHello(ClientHello mesg) throws IOException {

             // Was an ALPNExtension received?
             ALPNExtension alpnExt = (ALPNExtension)
                 mesg.extensions.get(ExtensionTyp.EXT_ALPN);
...
             // Currently line 706 in JDK9.
             session = new SSLSessionImpl(protocolVersion,
                      CipherSuite.C_NULL,
                      getLocalSupportedSignAlgs(),
                      sslContext.getSecureRandom(),
                      getHostAddressSE(), getPortSE());
...
             session.setALPNNames(alpnExt.getNames());
...
             // choose cipher suite and corresponding private key
             // This function is at 987 currently.
             chooseCipherSuite(mesg);
...
             // Only adds an ALPN extension if non-empty.
             m1.extensions.add(applicationProtocolSelector.select(...));
...

Above, chooseCipherSuite() iterates through the collection of suites. Inside
that, trySetCipherSuite() attempts to verify that the suite is acceptable to
use.  Inside that, setupPrivateKeyAndChain() does the actual KeyManager
calls.

         if (conn != null) {
             alias = km.chooseServerAlias(algorithm, null, conn);
         } else {
             alias = km.chooseEngineServerAlias(algorithm, null, engine);
         }

Now in the Application's Code:

If you want the KeyManager to take this info into account, you need to
create your own customer KM.

public String chooseEngineServerAlias(String keyType,
                                       Principal[] issuers,
                                       SSLEngine engine) {

     ExtendedSSLSession session = engine.getHandshakeSession();
     String protocol = session.getProtocol();
     String ciphersuite = session.getCipherSuite();
     List<String> alpns =
         session.getRequestedApplicationProtocolNames();

     // Some logic for which key to use...
     return choose(protocol, ciphersuite, alpns);
}

And then your actual ALPN selector:

public String select(...) throws SSLProtocolException {
     ExtendedSSLSession session = engine.getHandshakeSession()
     String ciphersuite = session.getCipherSuite();
     List<String> alpns =
         session.getRequestedApplicationProtocolNames();

     // Some logic for which key to use...
     return choose(protocol, ciphersuite, alpns);
}

Hopefully that is clear.

Let me see if I understand correctly.

In chooseEngineServerAlias() I will have a proposed cipher and the
list of app protos from the client.
The goal would be to choose the alias based on the app proto, as stated by 7301.

However, the app proto is not yet chosen here. If I don't have other
constraints to choose the app proto (e.g. SNI), the usual algorithm
applies: pick the first server app proto that is in common with the
client.
Let's assume this is h2; but looking at the cipher, it's not good, so
we have to pick another app proto, say http/1.1. Now the cipher is
good and we return the alias.
This is similar to what happens now with Jetty's ALPN: the cipher will
be chosen, then the ALPN callback invoked and there, by looking at the
cipher, we know we have to use http/1.1.

Let's assume now I have the constraint to choose h2 (e.g. I have a SNI
of http2.domain.com).
In chooseEngineServerAlias() I will look at SNI, and therefore choose
h2, then look at the proposed cipher, which is not good, so return
null.
Method chooseEngineServerAlias() will be called repeatedly for other
ciphers, until a cipher good for h2 is found, otherwise it's an alert
120.

Correct.  To expand a bit...

You will have the SSLSocket/SSLEngine which will give you access to the Socket's attributes (e.g. local/remote IP address/ports), along with the handshakeSession which is being negotiated. The handshakeSession will give access to the selected TLS protocol version number plus the received SNI and ALPN names. With my change to the ciphersuites, it will now give you to the "proposed" ciphersuite, the one being probed for valid key material. If your custom KeyManager don't like this combination of protocol/ciphersuite/sni/alpn/Socket attributes, the KeyManager can report back no valid key material is available, thus meeting that constraint.

Are you proposing to call select(...) from chooseEngineServerAlias(),
and give the ALPN callback a semantic that it may be called multiple
times, each time with a different cipher, and give access to the ALPN
callback implementation to SNI to choose the right protocol based on
that ?

That's another approach, add an SSLSocket/SSLEngine API to set the selected value from the KM callback. But that won't work for KM-less ciphersuites (anonymous).

I was planning on calling select() after the KM has returned to make the final selection once the ciphersuite has been officially selected, rather than requiring the KM to make the call.

Brad

Reply via email to