b436289dca38a669df6ac5cdc4dae411ad0d7ba6
[netconf.git] / transport / transport-tls / src / main / java / org / opendaylight / netconf / transport / tls / TLSServer.java
1 /*
2  * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.transport.tls;
9
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;
27
28 /**
29  * A {@link TransportStack} acting as a TLS server.
30  */
31 public final class TLSServer extends TLSTransportStack {
32     private TLSServer(final TransportChannelListener listener, final SslContext sslContext) {
33         super(listener, sslContext);
34     }
35
36     private TLSServer(final TransportChannelListener listener, final SslHandlerFactory factory) {
37         super(listener, factory);
38     }
39
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));
45     }
46
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));
52     }
53
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));
59     }
60
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));
66     }
67
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");
73         }
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);
81             }
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);
88             }
89             builder = SslContextBuilder.forServer(newKeyManager(rawPrivateKey));
90         } else if (authType != null) {
91             throw new UnsupportedConfigurationException("Unsupported server authentication type " + authType);
92         } else {
93             throw new UnsupportedConfigurationException("Missing server authentication type");
94         }
95
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);
104             }
105             builder.clientAuth(ClientAuth.REQUIRE).trustManager(trustManager);
106         } else {
107             builder.clientAuth(ClientAuth.NONE);
108         }
109         return new TLSServer(listener, buildSslContext(builder, serverParams.getHelloParams()));
110     }
111 }