2 * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.transport.tls;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import io.netty.bootstrap.Bootstrap;
12 import io.netty.bootstrap.ServerBootstrap;
13 import io.netty.handler.ssl.ClientAuth;
14 import io.netty.handler.ssl.SslContext;
15 import io.netty.handler.ssl.SslContextBuilder;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.netconf.transport.api.TransportChannelListener;
18 import org.opendaylight.netconf.transport.api.TransportStack;
19 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
20 import org.opendaylight.netconf.transport.tcp.TCPClient;
21 import org.opendaylight.netconf.transport.tcp.TCPServer;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev230417.TcpServerGrouping;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev230417.TlsServerGrouping;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev230417.tls.server.grouping.server.identity.auth.type.Certificate;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev230417.tls.server.grouping.server.identity.auth.type.RawPrivateKey;
29 * A {@link TransportStack} acting as a TLS server.
31 public final class TLSServer extends TLSTransportStack {
32 private TLSServer(final TransportChannelListener listener, final SslContext sslContext) {
33 super(listener, sslContext);
36 private TLSServer(final TransportChannelListener listener, final SslHandlerFactory factory) {
37 super(listener, factory);
40 public static @NonNull ListenableFuture<TLSServer> connect(final TransportChannelListener listener,
41 final Bootstrap bootstrap, final TcpClientGrouping connectParams, final TlsServerGrouping serverParams)
42 throws UnsupportedConfigurationException {
43 final var server = newServer(listener, serverParams);
44 return transformUnderlay(server, TCPClient.connect(server.asListener(), bootstrap, connectParams));
47 public static @NonNull ListenableFuture<TLSServer> listen(final TransportChannelListener listener,
48 final ServerBootstrap bootstrap, final TcpServerGrouping listenParams, final TlsServerGrouping serverParams)
49 throws UnsupportedConfigurationException {
50 final var server = newServer(listener, serverParams);
51 return transformUnderlay(server, TCPServer.listen(server.asListener(), bootstrap, listenParams));
54 public static @NonNull ListenableFuture<TLSServer> listen(final TransportChannelListener listener,
55 final ServerBootstrap bootstrap, final TcpServerGrouping listenParams, final SslHandlerFactory factory)
56 throws UnsupportedConfigurationException {
57 final var server = new TLSServer(listener, factory);
58 return transformUnderlay(server, TCPServer.listen(server.asListener(), bootstrap, listenParams));
61 private static TLSServer newServer(final TransportChannelListener listener, final TlsServerGrouping serverParams)
62 throws UnsupportedConfigurationException {
63 final var serverIdentity = serverParams.getServerIdentity();
64 if (serverIdentity == null) {
65 throw new UnsupportedConfigurationException("Missing server identity");
67 final SslContextBuilder builder;
68 final var authType = serverIdentity.getAuthType();
69 if (authType instanceof Certificate cert) {
70 // if-feature "server-ident-x509-cert"
71 final var certificate = cert.getCertificate();
72 if (certificate == null) {
73 throw new UnsupportedConfigurationException("Missing certificate in " + cert);
75 builder = SslContextBuilder.forServer(newKeyManager(certificate));
76 } else if (authType instanceof RawPrivateKey rawKey) {
77 // if-feature "server-ident-raw-public-key"
78 final var rawPrivateKey = rawKey.getRawPrivateKey();
79 if (rawPrivateKey == null) {
80 throw new UnsupportedConfigurationException("Missing key in " + rawKey);
82 builder = SslContextBuilder.forServer(newKeyManager(rawPrivateKey));
83 } else if (authType != null) {
84 throw new UnsupportedConfigurationException("Unsupported server authentication type " + authType);
86 throw new UnsupportedConfigurationException("Missing server authentication type");
89 final var clientAuth = serverParams.getClientAuthentication();
90 if (clientAuth != null) {
91 // CA && EE Certs : if-feature "client-ident-x509-cert"
92 // Raw public keys : if-feature "client-ident-raw-public-key"
93 final var trustManager = newTrustManager(clientAuth.getCaCerts(), clientAuth.getEeCerts(),
94 clientAuth.getRawPublicKeys());
95 if (trustManager == null) {
96 throw new UnsupportedOperationException("No client authentication methods in " + clientAuth);
98 builder.clientAuth(ClientAuth.REQUIRE).trustManager(trustManager);
100 builder.clientAuth(ClientAuth.NONE);
102 return new TLSServer(listener, buildSslContext(builder, serverParams.getHelloParams()));