VLink  2.0.0
A high-performance communication middleware
ssl_options.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file ssl_options.h
26  * @brief Backend-neutral SSL / TLS settings shared by all VLink transports that support encryption.
27  *
28  * @details
29  * This is an internal implementation header used by @c NodeImpl and by every
30  * transport backend that supports TLS; user code typically interacts with
31  * @c SslOptions through @c Node::set_ssl_options(). The struct is a thin
32  * aggregate that the transport factory translates into the @c ssl.* property
33  * convention used during connection setup.
34  *
35  * @par Native mechanism per backend
36  * | Backend | Underlying TLS mechanism |
37  * | ----------- | ----------------------------------------------------------------------- |
38  * | MQTT | @c MQTTClient_SSLOptions (Paho C); auto promotes @c tcp:// to @c ssl:// |
39  * | DDS | @c TCPv4TransportDescriptor::tls_config (Fast-DDS) |
40  * | CycloneDDS | @c ddsi_config SSL fields (requires @c DDS_HAS_SSL) |
41  * | Zenoh | @c transport/link/tls config keys (zenoh-c, not zenoh-pico) |
42  *
43  * @par SSL options table
44  * | Field | Property key | Description |
45  * | ---------------- | -------------------- | -------------------------------------------- |
46  * | @c ca_file | @c ssl.ca | CA certificate file path (PEM). |
47  * | @c cert_file | @c ssl.cert | Client certificate file path (PEM). |
48  * | @c key_file | @c ssl.key | Client private key file path (PEM). |
49  * | @c key_password | @c ssl.key_password | Passphrase for an encrypted private key. |
50  * | @c verify_peer | @c ssl.verify | @c "0" to skip server verification. |
51  * | @c server_name | @c ssl.server_name | SNI override. |
52  * | @c ciphers | @c ssl.ciphers | Cipher suite string (OpenSSL format). |
53  *
54  * @par Environment variable defaults
55  * The factory consults these variables when the matching property is not set;
56  * explicit properties always win.
57  *
58  * | Environment variable | Property key |
59  * | ----------------------- | -------------------- |
60  * | @c VLINK_SSL_CA | @c ssl.ca |
61  * | @c VLINK_SSL_CERT | @c ssl.cert |
62  * | @c VLINK_SSL_KEY | @c ssl.key |
63  * | @c VLINK_SSL_KEY_PASS | @c ssl.key_password |
64  * | @c VLINK_SSL_VERIFY | @c ssl.verify |
65  * | @c VLINK_SSL_SNI | @c ssl.server_name |
66  * | @c VLINK_SSL_CIPHERS | @c ssl.ciphers |
67  *
68  * @par Auto-detection
69  * TLS is considered active when @c ca_file or @c cert_file is non-empty; there
70  * is no separate enable flag. On DDS / CycloneDDS, activating TLS also forces
71  * the TCP transport because TLS rides over TCP.
72  *
73  * @par Example
74  * @code
75  * // --- Through the public Node API ---
76  * vlink::Publisher<MyMsg> pub("mqtt://sensor/data");
77  * vlink::SslOptions ssl;
78  * ssl.ca_file = "/etc/certs/ca.pem";
79  * ssl.cert_file = "/etc/certs/client.pem";
80  * ssl.key_file = "/etc/certs/client-key.pem";
81  * pub.set_ssl_options(ssl);
82  *
83  * // --- Through set_property ---
84  * pub.set_property("ssl.ca", "/etc/certs/ca.pem");
85  *
86  * // --- Through global property ---
87  * vlink::MqttConf::set_global_property("ssl.ca", "/etc/certs/ca.pem");
88  *
89  * // --- Through environment ---
90  * // export VLINK_SSL_CA=/etc/certs/ca.pem
91  * @endcode
92  *
93  * @note
94  * - Zenoh-pico (@c VLINK_ENABLE_ZENOH_PICO) does not support TLS; SSL
95  * properties trigger a warning.
96  * - CycloneDDS requires @c DDS_HAS_SSL at compile time; if the feature was
97  * not compiled in, SSL properties also trigger a warning.
98  */
99 
100 #pragma once
101 
102 #include <string>
103 
104 #include "../base/macros.h"
105 #include "./conf.h"
106 
107 namespace vlink {
108 
109 /**
110  * @struct SslOptions
111  * @brief Aggregate of SSL / TLS settings for transport-layer encryption.
112  *
113  * @details
114  * The struct can be either populated by hand and passed to
115  * @c Node::set_ssl_options(), or constructed from a @c Conf::PropertiesMap via
116  * @c parse_from() / written back via @c parse_to(). An instance is considered
117  * to enable TLS when @c ca_file or @c cert_file is non-empty.
118  */
119 struct VLINK_EXPORT SslOptions final {
120  /**
121  * @brief Whether the server certificate must be validated.
122  *
123  * @details
124  * Defaults to @c true. Setting it to @c false maps to @c ssl.verify = @c "0"
125  * and disables peer verification, which is convenient for development with
126  * self-signed certificates but should never ship to production.
127  */
128  bool verify_peer{true};
129 
130  /**
131  * @brief Path to the CA certificate (PEM) used to validate the peer.
132  *
133  * @details
134  * Setting this field (or its corresponding @c ssl.ca property) is one of the
135  * two conditions that makes @c is_valid() report @c true.
136  */
137  std::string ca_file;
138 
139  /**
140  * @brief Path to the client certificate (PEM) used for mutual TLS.
141  *
142  * @details
143  * Setting this field is the second condition that makes @c is_valid() report
144  * @c true. Pair with @c key_file for true mTLS.
145  */
146  std::string cert_file;
147 
148  /**
149  * @brief Path to the client private key (PEM) accompanying @c cert_file.
150  *
151  * @details
152  * If the key is encrypted, provide its passphrase via @c key_password.
153  */
154  std::string key_file;
155 
156  /**
157  * @brief Passphrase for an encrypted private key.
158  *
159  * @details
160  * Mirrored to the @c ssl.key_password property and the
161  * @c VLINK_SSL_KEY_PASS environment variable.
162  */
163  std::string key_password;
164 
165  /**
166  * @brief Server Name Indication (SNI) override.
167  *
168  * @details
169  * When non-empty the handshake announces this name to the server instead of
170  * the host derived from the URL. Honoured by MQTT, DDS and Zenoh.
171  */
172  std::string server_name;
173 
174  /**
175  * @brief Cipher suite string passed verbatim to the TLS implementation.
176  *
177  * @details
178  * Format depends on the underlying TLS library (OpenSSL by default). Leave
179  * empty to inherit the backend's default cipher choice.
180  */
181  std::string ciphers;
182 
183  /**
184  * @brief Default-constructs an empty options aggregate.
185  */
186  SslOptions() noexcept = default;
187 
188  /**
189  * @brief Default destructor.
190  */
191  ~SslOptions() noexcept = default;
192 
193  /**
194  * @brief Reports whether the configuration is sufficient to enable TLS.
195  *
196  * @details
197  * Returns @c true as soon as @c ca_file or @c cert_file is non-empty. An
198  * otherwise empty @c SslOptions yields @c false and the transport backend
199  * skips the TLS handshake entirely.
200  *
201  * @return @c true when TLS should be activated.
202  */
203  bool is_valid() const noexcept;
204 
205  /**
206  * @brief Reads @c ssl.* entries from @p properties (and the environment) into a new instance.
207  *
208  * @details
209  * Resolution order, highest priority first:
210  * -# Explicit @c ssl.* entries in @p properties.
211  * -# Matching @c VLINK_SSL_* environment variables.
212  *
213  * Fields absent from both sources keep their default values.
214  *
215  * @param properties Property map to read.
216  * @return Fully-resolved @c SslOptions aggregate.
217  */
218  static SslOptions parse_from(const Conf::PropertiesMap& properties) noexcept;
219 
220  /**
221  * @brief Writes non-default fields back into @p properties as @c ssl.* entries.
222  *
223  * @details
224  * Only non-empty string fields and a @c false @c verify_peer are emitted.
225  * Used internally by @c Node::set_ssl_options() to merge the aggregate into
226  * the node property map.
227  *
228  * @param properties Property map updated in place.
229  */
230  void parse_to(Conf::PropertiesMap& properties) const noexcept;
231 };
232 
233 } // namespace vlink
Transport-configuration base contract and the supporting boilerplate macros.
#define VLINK_EXPORT
Definition: macros.h:81