+ public final @Nullable SslHandler createSslHandler(final @NonNull Channel channel) {
+ final var sslContext = getSslContext(channel.remoteAddress());
+ return sslContext == null ? null : sslContext.newHandler(channel.alloc());
+ }
+
+ protected abstract @Nullable SslContext getSslContext(SocketAddress remoteAddress);
+
+ protected static final @NonNull SslContext createSslContext(final @NonNull TlsClientGrouping clientParams)
+ throws UnsupportedConfigurationException {
+ final var builder = SslContextBuilder.forClient();
+
+ final var clientIdentity = clientParams.getClientIdentity();
+ if (clientIdentity != null) {
+ final var authType = clientIdentity.getAuthType();
+ if (authType instanceof Certificate cert) {
+ // if-feature "client-ident-x509-cert"
+ final var certificate = cert.getCertificate();
+ if (certificate == null) {
+ throw new UnsupportedConfigurationException("Missing certificate in " + cert);
+ }
+ builder.keyManager(newKeyManager(certificate));
+ } else if (authType instanceof RawPublicKey rawKey) {
+ // if-feature "client-ident-raw-public-key"
+ final var rawPrivateKey = rawKey.getRawPrivateKey();
+ if (rawPrivateKey == null) {
+ throw new UnsupportedConfigurationException("Missing key in " + rawKey);
+ }
+ builder.keyManager(newKeyManager(rawPrivateKey));
+ } else if (authType != null) {
+ throw new UnsupportedConfigurationException("Unsupported client authentication type " + authType);
+ }
+ }
+
+ final var serverAuth = clientParams.getServerAuthentication();
+ if (serverAuth != null) {
+ // CA && EE X509 certificates : if-feature "server-ident-x509-cert"
+ // Raw public key : if-feature "server-ident-raw-public-key"
+ final var trustManager = newTrustManager(serverAuth.getCaCerts(), serverAuth.getEeCerts(),
+ serverAuth.getRawPublicKeys());
+ if (trustManager == null) {
+ throw new UnsupportedOperationException("No server authentication methods in " + serverAuth);
+ }
+ builder.trustManager(trustManager);
+ }
+
+ return buildSslContext(builder, clientParams.getHelloParams());
+ }
+
+ protected static final @NonNull SslContext createSslContext(final @NonNull TlsServerGrouping serverParams)
+ throws UnsupportedConfigurationException {
+ final var serverIdentity = serverParams.getServerIdentity();
+ if (serverIdentity == null) {
+ throw new UnsupportedConfigurationException("Missing server identity");
+ }
+ final SslContextBuilder builder;
+ final var authType = serverIdentity.getAuthType();
+ if (authType
+ instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev231228
+ .tls.server.grouping.server.identity.auth.type.Certificate cert) {
+ // if-feature "server-ident-x509-cert"
+ final var certificate = cert.getCertificate();
+ if (certificate == null) {
+ throw new UnsupportedConfigurationException("Missing certificate in " + cert);
+ }
+ builder = SslContextBuilder.forServer(newKeyManager(certificate));
+ } else if (authType instanceof RawPrivateKey rawKey) {
+ // if-feature "server-ident-raw-public-key"
+ final var rawPrivateKey = rawKey.getRawPrivateKey();
+ if (rawPrivateKey == null) {
+ throw new UnsupportedConfigurationException("Missing key in " + rawKey);
+ }
+ builder = SslContextBuilder.forServer(newKeyManager(rawPrivateKey));
+ } else if (authType != null) {
+ throw new UnsupportedConfigurationException("Unsupported server authentication type " + authType);
+ } else {
+ throw new UnsupportedConfigurationException("Missing server authentication type");
+ }
+
+ final var clientAuth = serverParams.getClientAuthentication();
+ if (clientAuth != null) {
+ // CA && EE Certs : if-feature "client-ident-x509-cert"
+ // Raw public keys : if-feature "client-ident-raw-public-key"
+ final var trustManager = newTrustManager(clientAuth.getCaCerts(), clientAuth.getEeCerts(),
+ clientAuth.getRawPublicKeys());
+ if (trustManager == null) {
+ throw new UnsupportedOperationException("No client authentication methods in " + clientAuth);
+ }
+ builder.clientAuth(ClientAuth.REQUIRE).trustManager(trustManager);
+ } else {
+ builder.clientAuth(ClientAuth.NONE);
+ }
+
+ return buildSslContext(builder, serverParams.getHelloParams());
+ }
+
+ // FIXME: should be TrustManagerBuilder
+ private static @Nullable TrustManagerFactory newTrustManager(
+ final @Nullable InlineOrTruststoreCertsGrouping caCerts,
+ final @Nullable InlineOrTruststoreCertsGrouping eeCerts,
+ final @Nullable InlineOrTruststorePublicKeysGrouping publicKeys) throws UnsupportedConfigurationException {
+
+ if (publicKeys != null) {
+ // FIXME: implement this and advertize server-auth-raw-public-key from IetfTlsClientFeatureProvider
+ throw new UnsupportedConfigurationException("Public key authentication not implemented");
+ }
+ if (caCerts != null || eeCerts != null) {
+ // X.509 certificates
+ final KeyStore keyStore = newKeyStore();
+ setX509Certificates(keyStore, caCerts, eeCerts);
+ return buildTrustManagerFactory(keyStore);
+ }
+ return null;
+ }
+
+ private static KeyManagerFactory newKeyManager(
+ final @NonNull InlineOrKeystoreEndEntityCertWithKeyGrouping endEntityCert)
+ throws UnsupportedConfigurationException {
+ final var keyStore = newKeyStore();
+ setEndEntityCertificateWithKey(keyStore, endEntityCert);
+ return buildKeyManagerFactory(keyStore);
+ }
+
+ private static KeyManagerFactory newKeyManager(final @NonNull InlineOrKeystoreAsymmetricKeyGrouping rawPrivateKey)
+ throws UnsupportedConfigurationException {
+ final var keyStore = newKeyStore();
+ setAsymmetricKey(keyStore, rawPrivateKey);
+ return buildKeyManagerFactory(keyStore);
+ }
+
+ private static @NonNull SslContext buildSslContext(final SslContextBuilder builder,
+ final HelloParamsGrouping helloParams) throws UnsupportedConfigurationException {
+ if (helloParams != null) {
+ final var tlsVersions = helloParams.getTlsVersions();
+ if (tlsVersions != null) {
+ final var versions = tlsVersions.getTlsVersion();
+ if (versions != null && !versions.isEmpty()) {
+ builder.protocols(createTlsStrings(versions));
+ }
+ }
+ final var cipherSuites = helloParams.getCipherSuites();
+ if (cipherSuites != null) {
+ final var ciphers = cipherSuites.getCipherSuite();
+ if (ciphers != null && !ciphers.isEmpty()) {
+ builder.ciphers(createCipherStrings(ciphers));
+ }
+ }
+ }
+ try {
+ return builder.build();
+ } catch (SSLException e) {
+ throw new UnsupportedConfigurationException("Cannot instantiate TLS context", e);
+ }
+ }
+
+ private static String[] createTlsStrings(final List<TlsVersionBase> versions)
+ throws UnsupportedConfigurationException {
+ // FIXME: cache these
+ final var ret = new String[versions.size()];
+ int idx = 0;
+ for (var version : versions) {
+ final var str = IetfTlsCommonFeatureProvider.algorithmNameOf(version);
+ if (str == null) {
+ throw new UnsupportedConfigurationException("Unhandled TLS version " + version);
+ }
+ ret[idx++] = str;
+ }
+ return ret;
+ }
+
+ private static ImmutableList<String> createCipherStrings(final List<CipherSuiteAlgBase> ciphers)
+ throws UnsupportedConfigurationException {
+ // FIXME: cache these
+ final var builder = ImmutableList.<String>builderWithExpectedSize(ciphers.size());
+ for (var cipher : ciphers) {
+ final var str = CIPHER_SUITES.get(cipher);
+ if (str == null) {
+ throw new UnsupportedConfigurationException("Unhandled cipher suite " + cipher);
+ }
+ builder.add(str);
+ }
+ return builder.build();
+ }