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.rev231228.TcpClientGrouping;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev231228.TcpServerGrouping;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev231228.TlsServerGrouping;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev231228.tls.server.grouping.server.identity.auth.type.Certificate;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev231228.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> connect(final TransportChannelListener listener,
48 final Bootstrap bootstrap, final TcpClientGrouping connectParams, final SslHandlerFactory factory)
49 throws UnsupportedConfigurationException {
50 final var server = new TLSServer(listener, factory);
51 return transformUnderlay(server, TCPClient.connect(server.asListener(), bootstrap, connectParams));
54 public static @NonNull ListenableFuture<TLSServer> listen(final TransportChannelListener listener,
55 final ServerBootstrap bootstrap, final TcpServerGrouping listenParams, final TlsServerGrouping serverParams)
56 throws UnsupportedConfigurationException {
57 final var server = newServer(listener, serverParams);
58 return transformUnderlay(server, TCPServer.listen(server.asListener(), bootstrap, listenParams));
61 public static @NonNull ListenableFuture<TLSServer> listen(final TransportChannelListener listener,
62 final ServerBootstrap bootstrap, final TcpServerGrouping listenParams, final SslHandlerFactory factory)
63 throws UnsupportedConfigurationException {
64 final var server = new TLSServer(listener, factory);
65 return transformUnderlay(server, TCPServer.listen(server.asListener(), bootstrap, listenParams));
68 private static TLSServer newServer(final TransportChannelListener listener, final TlsServerGrouping serverParams)
69 throws UnsupportedConfigurationException {
70 final var serverIdentity = serverParams.getServerIdentity();
71 if (serverIdentity == null) {
72 throw new UnsupportedConfigurationException("Missing server identity");
74 final SslContextBuilder builder;
75 final var authType = serverIdentity.getAuthType();
76 if (authType instanceof Certificate cert) {
77 // if-feature "server-ident-x509-cert"
78 final var certificate = cert.getCertificate();
79 if (certificate == null) {
80 throw new UnsupportedConfigurationException("Missing certificate in " + cert);
82 builder = SslContextBuilder.forServer(newKeyManager(certificate));
83 } else if (authType instanceof RawPrivateKey rawKey) {
84 // if-feature "server-ident-raw-public-key"
85 final var rawPrivateKey = rawKey.getRawPrivateKey();
86 if (rawPrivateKey == null) {
87 throw new UnsupportedConfigurationException("Missing key in " + rawKey);
89 builder = SslContextBuilder.forServer(newKeyManager(rawPrivateKey));
90 } else if (authType != null) {
91 throw new UnsupportedConfigurationException("Unsupported server authentication type " + authType);
93 throw new UnsupportedConfigurationException("Missing server authentication type");
96 final var clientAuth = serverParams.getClientAuthentication();
97 if (clientAuth != null) {
98 // CA && EE Certs : if-feature "client-ident-x509-cert"
99 // Raw public keys : if-feature "client-ident-raw-public-key"
100 final var trustManager = newTrustManager(clientAuth.getCaCerts(), clientAuth.getEeCerts(),
101 clientAuth.getRawPublicKeys());
102 if (trustManager == null) {
103 throw new UnsupportedOperationException("No client authentication methods in " + clientAuth);
105 builder.clientAuth(ClientAuth.REQUIRE).trustManager(trustManager);
107 builder.clientAuth(ClientAuth.NONE);
109 return new TLSServer(listener, buildSslContext(builder, serverParams.getHelloParams()));