< prev index next >

src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,116 +23,562 @@
  * questions.
  */
 
 package sun.security.ssl;
 
-import sun.security.action.GetPropertyAction;
-
-import java.io.File;
-import java.io.FilePermission;
 import java.io.IOException;
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.SecureRandom;
-import java.util.*;
-
-/**
- * Models a service that provides support for a particular client key exchange
- * mode. Currently used to implement Kerberos-related cipher suites.
- *
- * @since 9
- */
-public interface ClientKeyExchangeService {
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import sun.security.ssl.DHKeyExchange.DHEPossession;
+import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
+import sun.security.ssl.X509Authentication.X509Possession;
+
+final class SSLKeyExchange implements SSLKeyAgreement {
+    private final SSLAuthentication authentication;
+    private final SSLKeyAgreement keyAgreement;
+
+    SSLKeyExchange(X509Authentication authentication,
+            SSLKeyAgreement keyAgreement) {
+        this.authentication = authentication;
+        this.keyAgreement = keyAgreement;
+    }
 
-    static class Loader {
-        private static final Map<String,ClientKeyExchangeService>
-                providers = new HashMap<>();
+    SSLPossession[] createPossessions(HandshakeContext context) {
+        // authentication
+        SSLPossession authPossession = null;
+        if (authentication != null) {
+            authPossession = authentication.createPossession(context);
+            if (authPossession == null) {
+                return new SSLPossession[0];
+            } else if (context instanceof ServerHandshakeContext) {
+                // The authentication information may be used further for
+                // key agreement parameters negotiation.
+                ServerHandshakeContext shc = (ServerHandshakeContext)context;
+                shc.interimAuthn = authPossession;
+            }
+        }
 
-        static {
-            String path = GetPropertyAction.privilegedGetProperty("java.home");
-            ServiceLoader<ClientKeyExchangeService> sc =
-                    AccessController.doPrivileged(
-                            (PrivilegedAction<ServiceLoader<ClientKeyExchangeService>>)
-                                    () -> ServiceLoader.loadInstalled(ClientKeyExchangeService.class),
-                            null,
-                            new FilePermission(new File(path, "-").toString(), "read"));
-            Iterator<ClientKeyExchangeService> iter = sc.iterator();
-            while (iter.hasNext()) {
-                ClientKeyExchangeService cs = iter.next();
-                for (String ex: cs.supported()) {
-                    providers.put(ex, cs);
+        // key agreement
+        SSLPossession kaPossession;
+        if (keyAgreement == T12KeyAgreement.RSA_EXPORT) {
+            // a special case
+            X509Possession x509Possession = (X509Possession)authPossession;
+            if (JsseJce.getRSAKeyLength(
+                    x509Possession.popCerts[0].getPublicKey()) > 512) {
+                kaPossession = keyAgreement.createPossession(context);
+
+                if (kaPossession == null) {
+                    return new SSLPossession[0];
+                } else {
+                    return authentication != null ?
+                            new SSLPossession[] {authPossession, kaPossession} :
+                            new SSLPossession[] {kaPossession};
+                }
+            } else {
+                return authentication != null ?
+                        new SSLPossession[] {authPossession} :
+                        new SSLPossession[0];
+            }
+        } else {
+            kaPossession = keyAgreement.createPossession(context);
+            if (kaPossession == null) {
+                // special cases
+                if (keyAgreement == T12KeyAgreement.RSA ||
+                        keyAgreement == T12KeyAgreement.ECDH) {
+                    return authentication != null ?
+                            new SSLPossession[] {authPossession} :
+                            new SSLPossession[0];
+                } else {
+                    return new SSLPossession[0];
+                }
+            } else {
+                return authentication != null ?
+                        new SSLPossession[] {authPossession, kaPossession} :
+                        new SSLPossession[] {kaPossession};
                 }
             }
         }
 
+    @Override
+    public SSLPossession createPossession(HandshakeContext handshakeContext) {
+        // Please call createPossessions() so that the SSLAuthentication
+        // is counted.
+        throw new UnsupportedOperationException(
+                "SSLKeyExchange.createPossessions() should be used instead");
     }
 
-    public static ClientKeyExchangeService find(String ex) {
-        return Loader.providers.get(ex);
+    @Override
+    public SSLKeyDerivation createKeyDerivation(
+            HandshakeContext handshakeContext) throws IOException {
+        return keyAgreement.createKeyDerivation(handshakeContext);
     }
 
+    @Override
+    public SSLHandshake[] getRelatedHandshakers(
+            HandshakeContext handshakeContext) {
+        SSLHandshake[] auHandshakes;
+        if (authentication != null) {
+            auHandshakes =
+                authentication.getRelatedHandshakers(handshakeContext);
+        } else {
+            auHandshakes = null;
+        }
 
-    /**
-     * Returns the supported key exchange modes by this provider.
-     * @return the supported key exchange modes
-     */
-    String[] supported();
+        SSLHandshake[] kaHandshakes =
+                keyAgreement.getRelatedHandshakers(handshakeContext);
 
-    /**
-     * Returns a generalized credential object on the server side. The server
-     * side can use the info to determine if a cipher suite can be enabled.
-     * @param acc the AccessControlContext of the SSL session
-     * @return the credential object
-     */
-    Object getServiceCreds(AccessControlContext acc);
+        if (auHandshakes == null || auHandshakes.length == 0) {
+            return kaHandshakes;
+        } else if (kaHandshakes == null || kaHandshakes.length == 0) {
+            return auHandshakes;
+        } else {
+            SSLHandshake[] producers = Arrays.copyOf(
+                     auHandshakes, auHandshakes.length + kaHandshakes.length);
+            System.arraycopy(kaHandshakes, 0,
+                    producers, auHandshakes.length, kaHandshakes.length);
+            return producers;
+        }
+    }
 
-    /**
-     * Returns the host name for a service principal. The info can be used in
-     * SNI or host name verifier.
-     * @param principal the principal of a service
-     * @return the string formed host name
-     */
-    String getServiceHostName(Principal principal);
+    @Override
+    public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
+            HandshakeContext handshakeContext) {
+        Map.Entry<Byte, HandshakeProducer>[] auProducers;
+        if (authentication != null) {
+            auProducers =
+                authentication.getHandshakeProducers(handshakeContext);
+        } else {
+            auProducers = null;
+        }
 
-    /**
-     * Returns whether the specified principal is related to the current
-     * SSLSession. The info can be used to verify a SSL resume.
-     * @param isClient if true called from client side, otherwise from server
-     * @param acc the AccessControlContext of the SSL session
-     * @param p the specified principal
-     * @return true if related
-     */
-    boolean isRelated(boolean isClient, AccessControlContext acc, Principal p);
+        Map.Entry<Byte, HandshakeProducer>[] kaProducers =
+                keyAgreement.getHandshakeProducers(handshakeContext);
 
-    /**
-     * Creates the ClientKeyExchange object on the client side.
-     * @param serverName the intented peer name
-     * @param acc the AccessControlContext of the SSL session
-     * @param protocolVersion the TLS protocol version
-     * @param rand the SecureRandom that will used to generate the premaster
-     * @return the new Exchanger object
-     * @throws IOException if there is an error
-     */
-    ClientKeyExchange createClientExchange(String serverName, AccessControlContext acc,
-            ProtocolVersion protocolVersion, SecureRandom rand) throws IOException;
+        if (auProducers == null || auProducers.length == 0) {
+            return kaProducers;
+        } else if (kaProducers == null || kaProducers.length == 0) {
+            return auProducers;
+        } else {
+            Map.Entry<Byte, HandshakeProducer>[] producers = Arrays.copyOf(
+                     auProducers, auProducers.length + kaProducers.length);
+            System.arraycopy(kaProducers, 0,
+                    producers, auProducers.length, kaProducers.length);
+            return producers;
+        }
+    }
 
-    /**
-     * Create the ClientKeyExchange on the server side.
-     * @param protocolVersion the protocol version
-     * @param clientVersion the input protocol version
-     * @param rand a SecureRandom object used to generate premaster
-     *             (if the server has to create one)
-     * @param encodedTicket the ticket from client
-     * @param encrypted the encrypted premaster secret from client
-     * @param acc the AccessControlContext of the SSL session
-     * @param ServiceCreds the service side credentials object as retrived from
-     *                     {@link #getServiceCreds}
-     * @return the new Exchanger object
-     * @throws IOException if there is an error
-     */
-    ClientKeyExchange createServerExchange(
-            ProtocolVersion protocolVersion, ProtocolVersion clientVersion,
-            SecureRandom rand, byte[] encodedTicket, byte[] encrypted,
-            AccessControlContext acc, Object ServiceCreds) throws IOException;
+    @Override
+    public Map.Entry<Byte, SSLConsumer>[] getHandshakeConsumers(
+            HandshakeContext handshakeContext) {
+        Map.Entry<Byte, SSLConsumer>[] auConsumers;
+        if (authentication != null) {
+            auConsumers =
+                authentication.getHandshakeConsumers(handshakeContext);
+        } else {
+            auConsumers = null;
+        }
+
+        Map.Entry<Byte, SSLConsumer>[] kaConsumers =
+                keyAgreement.getHandshakeConsumers(handshakeContext);
+
+        if (auConsumers == null || auConsumers.length == 0) {
+            return kaConsumers;
+        } else if (kaConsumers == null || kaConsumers.length == 0) {
+            return auConsumers;
+        } else {
+            Map.Entry<Byte, SSLConsumer>[] producers = Arrays.copyOf(
+                     auConsumers, auConsumers.length + kaConsumers.length);
+            System.arraycopy(kaConsumers, 0,
+                    producers, auConsumers.length, kaConsumers.length);
+            return producers;
+        }
+    }
+
+    // SSL 3.0 - (D)TLS 1.2
+    static SSLKeyExchange valueOf(
+            CipherSuite.KeyExchange keyExchange) {
+        if (keyExchange == null) {
+            return null;
+        }
+
+        switch (keyExchange) {
+            case K_RSA:
+                return SSLKeyExRSA.KE;
+            case K_RSA_EXPORT:
+                return SSLKeyExRSAExport.KE;
+            case K_DHE_DSS:
+                return SSLKeyExDHEDSS.KE;
+            case K_DHE_DSS_EXPORT:
+                return SSLKeyExDHEDSSExport.KE;
+            case K_DHE_RSA:
+                return SSLKeyExDHERSA.KE;
+            case K_DHE_RSA_EXPORT:
+                return SSLKeyExDHERSAExport.KE;
+            case K_DH_ANON:
+                return SSLKeyExDHANON.KE;
+            case K_DH_ANON_EXPORT:
+                return SSLKeyExDHANONExport.KE;
+            case K_ECDH_ECDSA:
+                return SSLKeyExECDHECDSA.KE;
+            case K_ECDH_RSA:
+                return SSLKeyExECDHRSA.KE;
+            case K_ECDHE_ECDSA:
+                return SSLKeyExECDHEECDSA.KE;
+            case K_ECDHE_RSA:
+                return SSLKeyExECDHERSA.KE;
+            case K_ECDH_ANON:
+                return SSLKeyExECDHANON.KE;
+        }
+
+        return null;
+    }
+
+    // TLS 1.3
+    static SSLKeyExchange valueOf(NamedGroup namedGroup) {
+        SSLKeyAgreement ka = T13KeyAgreement.valueOf(namedGroup);
+        if (ka != null) {
+            return new SSLKeyExchange(
+                null, T13KeyAgreement.valueOf(namedGroup));
+        }
+
+        return null;
+    }
+
+    private static class SSLKeyExRSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA, T12KeyAgreement.RSA);
+    }
+
+    private static class SSLKeyExRSAExport {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA, T12KeyAgreement.RSA_EXPORT);
+    }
+
+    private static class SSLKeyExDHEDSS {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.DSA, T12KeyAgreement.DHE);
+    }
+
+    private static class SSLKeyExDHEDSSExport {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.DSA, T12KeyAgreement.DHE_EXPORT);
+    }
+
+    private static class SSLKeyExDHERSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA, T12KeyAgreement.DHE);
+    }
+
+    private static class SSLKeyExDHERSAExport {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA, T12KeyAgreement.DHE_EXPORT);
+    }
+
+    private static class SSLKeyExDHANON {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                null, T12KeyAgreement.DHE);
+    }
+
+    private static class SSLKeyExDHANONExport {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                null, T12KeyAgreement.DHE_EXPORT);
+    }
+
+    private static class SSLKeyExECDHECDSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.EC, T12KeyAgreement.ECDH);
+    }
+
+    private static class SSLKeyExECDHRSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.EC, T12KeyAgreement.ECDH);
+    }
+
+    private static class SSLKeyExECDHEECDSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.EC, T12KeyAgreement.ECDHE);
+    }
+
+    private static class SSLKeyExECDHERSA {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA, T12KeyAgreement.ECDHE);
+    }
+
+    private static class SSLKeyExECDHANON {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                null, T12KeyAgreement.ECDHE);
+    }
+
+    private enum T12KeyAgreement implements SSLKeyAgreement {
+        RSA             ("rsa",         null,
+                                        RSAKeyExchange.kaGenerator),
+        RSA_EXPORT      ("rsa_export",  RSAKeyExchange.poGenerator,
+                                        RSAKeyExchange.kaGenerator),
+        DHE             ("dhe",         DHKeyExchange.poGenerator,
+                                        DHKeyExchange.kaGenerator),
+        DHE_EXPORT      ("dhe_export",  DHKeyExchange.poExportableGenerator,
+                                        DHKeyExchange.kaGenerator),
+        ECDH            ("ecdh",        null,
+                                        ECDHKeyExchange.ecdhKAGenerator),
+        ECDHE           ("ecdhe",       ECDHKeyExchange.poGenerator,
+                                        ECDHKeyExchange.ecdheKAGenerator);
+
+        final String name;
+        final SSLPossessionGenerator possessionGenerator;
+        final SSLKeyAgreementGenerator keyAgreementGenerator;
+
+        T12KeyAgreement(String name,
+                SSLPossessionGenerator possessionGenerator,
+                SSLKeyAgreementGenerator keyAgreementGenerator) {
+            this.name = name;
+            this.possessionGenerator = possessionGenerator;
+            this.keyAgreementGenerator = keyAgreementGenerator;
+        }
+
+        @Override
+        public SSLPossession createPossession(HandshakeContext context) {
+            if (possessionGenerator != null) {
+                return possessionGenerator.createPossession(context);
+            }
+
+            return null;
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext context) throws IOException {
+            return keyAgreementGenerator.createKeyDerivation(context);
+        }
+
+        @Override
+        public SSLHandshake[] getRelatedHandshakers(
+                HandshakeContext handshakeContext) {
+            if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
+                if (this.possessionGenerator != null) {
+                    return new SSLHandshake[] {
+                            SSLHandshake.SERVER_KEY_EXCHANGE
+                        };
+                }
+            }
+
+            return new SSLHandshake[0];
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
+                HandshakeContext handshakeContext) {
+            if (handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
+                return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
+            }
+
+            if (handshakeContext.sslConfig.isClientMode) {
+                switch (this) {
+                    case RSA:
+                    case RSA_EXPORT:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                    RSAClientKeyExchange.rsaHandshakeProducer
+                            )
+                        });
+
+                    case DHE:
+                    case DHE_EXPORT:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<Byte, HandshakeProducer>(
+                                    SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                    DHClientKeyExchange.dhHandshakeProducer
+                            )
+                        });
+
+                    case ECDH:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                ECDHClientKeyExchange.ecdhHandshakeProducer
+                            )
+                        });
+
+                    case ECDHE:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                ECDHClientKeyExchange.ecdheHandshakeProducer
+                            )
+                        });
+                }
+            } else {
+                switch (this) {
+                    case RSA_EXPORT:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    RSAServerKeyExchange.rsaHandshakeProducer
+                            )
+                        });
+
+                    case DHE:
+                    case DHE_EXPORT:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    DHServerKeyExchange.dhHandshakeProducer
+                            )
+                        });
+
+                    case ECDHE:
+                        return (Map.Entry<Byte,
+                                HandshakeProducer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    ECDHServerKeyExchange.ecdheHandshakeProducer
+                            )
+                        });
+                }
+            }
+
+            return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Map.Entry<Byte, SSLConsumer>[] getHandshakeConsumers(
+                HandshakeContext handshakeContext) {
+            if (handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
+                return (Map.Entry<Byte, SSLConsumer>[])(new Map.Entry[0]);
+            }
+
+            if (handshakeContext.sslConfig.isClientMode) {
+                switch (this) {
+                    case RSA_EXPORT:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    RSAServerKeyExchange.rsaHandshakeConsumer
+                            )
+                        });
+
+                    case DHE:
+                    case DHE_EXPORT:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    DHServerKeyExchange.dhHandshakeConsumer
+                            )
+                        });
+
+                    case ECDHE:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.SERVER_KEY_EXCHANGE.id,
+                                    ECDHServerKeyExchange.ecdheHandshakeConsumer
+                            )
+                        });
+                }
+            } else {
+                switch (this) {
+                    case RSA:
+                    case RSA_EXPORT:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                    RSAClientKeyExchange.rsaHandshakeConsumer
+                            )
+                        });
+
+                    case DHE:
+                    case DHE_EXPORT:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                    SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                    DHClientKeyExchange.dhHandshakeConsumer
+                            )
+                        });
+
+                    case ECDH:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                ECDHClientKeyExchange.ecdhHandshakeConsumer
+                            )
+                        });
+
+                    case ECDHE:
+                        return (Map.Entry<Byte,
+                                SSLConsumer>[])(new Map.Entry[] {
+                            new SimpleImmutableEntry<>(
+                                SSLHandshake.CLIENT_KEY_EXCHANGE.id,
+                                ECDHClientKeyExchange.ecdheHandshakeConsumer
+                            )
+                        });
+                }
+            }
+
+            return (Map.Entry<Byte, SSLConsumer>[])(new Map.Entry[0]);
+        }
+    }
+
+    private static final class T13KeyAgreement implements SSLKeyAgreement {
+        private final NamedGroup namedGroup;
+        static final Map<NamedGroup, T13KeyAgreement>
+                supportedKeyShares = new HashMap<>();
+
+        static {
+            for (NamedGroup namedGroup :
+                    SupportedGroups.supportedNamedGroups) {
+                supportedKeyShares.put(
+                        namedGroup, new T13KeyAgreement(namedGroup));
+            }
+        }
+
+        private T13KeyAgreement(NamedGroup namedGroup) {
+            this.namedGroup = namedGroup;
+        }
+
+        static T13KeyAgreement valueOf(NamedGroup namedGroup) {
+            return supportedKeyShares.get(namedGroup);
+        }
+
+        @Override
+        public SSLPossession createPossession(HandshakeContext hc) {
+            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+                return new ECDHEPossession(
+                        namedGroup, hc.sslContext.getSecureRandom());
+            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
+                return new DHEPossession(
+                        namedGroup, hc.sslContext.getSecureRandom());
+            }
+
+            return null;
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException {
+            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+                return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
+            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
+                return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+            }
+
+            return null;
+        }
+    }
 }
< prev index next >