4
4
*/
5
5
#include < aws/crt/Api.h>
6
6
#include < aws/crt/StlAllocator.h>
7
+ #include < aws/crt/auth/Credentials.h>
8
+ #include < aws/crt/io/TlsOptions.h>
7
9
8
10
#include < aws/iot/MqttClient.h>
9
11
@@ -22,7 +24,9 @@ static void s_printHelp()
22
24
stdout,
23
25
" basic-pub-sub --endpoint <endpoint> --cert <path to cert>"
24
26
" --key <path to key> --topic --ca_file <optional: path to custom ca>"
25
- " --use_websocket --signing_region <region> --proxy_host <host> --proxy_port <port>\n\n " );
27
+ " --use_websocket --signing_region <region> --proxy_host <host> --proxy_port <port>"
28
+ " --x509 --x509_role_alias <role_alias> --x509_endpoint <endpoint> --x509_thing <thing_name>"
29
+ " --x509_cert <path to cert> --x509_key <path to key> --x509_rootca <path to root ca>\n\n " );
26
30
fprintf (stdout, " endpoint: the endpoint of the mqtt server not including a port\n " );
27
31
fprintf (
28
32
stdout,
@@ -42,7 +46,21 @@ static void s_printHelp()
42
46
" websockets)\n " );
43
47
fprintf (stdout, " proxy_host: if you want to use a proxy with websockets, specify the host here (optional).\n " );
44
48
fprintf (
45
- stdout, " proxy_port: defaults to 8080 is proxy_host is set. Set this to any value you'd like (optional).\n\n " );
49
+ stdout, " proxy_port: defaults to 8080 is proxy_host is set. Set this to any value you'd like (optional).\n " );
50
+
51
+ fprintf (stdout, " x509: Use the x509 credentials provider while using websockets (optional)\n " );
52
+ fprintf (stdout, " x509_role_alias: Role alias to use with the x509 credentials provider (required for x509)\n " );
53
+ fprintf (stdout, " x509_endpoint: Endpoint to fetch x509 credentials from (required for x509)\n " );
54
+ fprintf (stdout, " x509_thing: Thing name to fetch x509 credentials on behalf of (required for x509)\n " );
55
+ fprintf (
56
+ stdout,
57
+ " x509_cert: Path to the IoT thing certificate used in fetching x509 credentials (required for x509)\n " );
58
+ fprintf (
59
+ stdout,
60
+ " x509_key: Path to the IoT thing private key used in fetching x509 credentials (required for x509)\n " );
61
+ fprintf (
62
+ stdout,
63
+ " x509_rootca: Path to the root certificate used in fetching x509 credentials (required for x509)\n\n " );
46
64
}
47
65
48
66
bool s_cmdOptionExists (char **begin, char **end, const String &option)
@@ -79,13 +97,21 @@ int main(int argc, char *argv[])
79
97
String proxyHost;
80
98
uint16_t proxyPort (8080 );
81
99
100
+ String x509Endpoint;
101
+ String x509ThingName;
102
+ String x509RoleAlias;
103
+ String x509CertificatePath;
104
+ String x509KeyPath;
105
+ String x509RootCAFile;
106
+
82
107
bool useWebSocket = false ;
108
+ bool useX509 = false ;
83
109
84
110
/* ********************** Parse Arguments ***************************/
85
111
if (!(s_cmdOptionExists (argv, argv + argc, " --endpoint" ) && s_cmdOptionExists (argv, argv + argc, " --topic" )))
86
112
{
87
113
s_printHelp ();
88
- return 0 ;
114
+ return 1 ;
89
115
}
90
116
91
117
endpoint = s_getCmdOption (argv, argv + argc, " --endpoint" );
@@ -100,6 +126,13 @@ int main(int argc, char *argv[])
100
126
certificatePath = s_getCmdOption (argv, argv + argc, " --cert" );
101
127
}
102
128
129
+ if (keyPath.empty () != certificatePath.empty ())
130
+ {
131
+ fprintf (stdout, " Using mtls (cert and key) requires both the certificate and the private key\n " );
132
+ s_printHelp ();
133
+ return 1 ;
134
+ }
135
+
103
136
topic = s_getCmdOption (argv, argv + argc, " --topic" );
104
137
if (s_cmdOptionExists (argv, argv + argc, " --ca_file" ))
105
138
{
@@ -109,11 +142,14 @@ int main(int argc, char *argv[])
109
142
{
110
143
clientId = s_getCmdOption (argv, argv + argc, " --client_id" );
111
144
}
145
+
112
146
if (s_cmdOptionExists (argv, argv + argc, " --use_websocket" ))
113
147
{
114
148
if (!s_cmdOptionExists (argv, argv + argc, " --signing_region" ))
115
149
{
150
+ fprintf (stdout, " Websockets require a signing region to be specified.\n " );
116
151
s_printHelp ();
152
+ return 1 ;
117
153
}
118
154
useWebSocket = true ;
119
155
signingRegion = s_getCmdOption (argv, argv + argc, " --signing_region" );
@@ -129,6 +165,82 @@ int main(int argc, char *argv[])
129
165
}
130
166
}
131
167
168
+ bool usingMtls = !certificatePath.empty () && !keyPath.empty ();
169
+
170
+ /* one or the other, but not both nor neither */
171
+ if (useWebSocket == usingMtls)
172
+ {
173
+ if (useWebSocket && usingMtls)
174
+ {
175
+ fprintf (stdout, " You must use either websockets or mtls for authentication, but not both.\n " );
176
+ }
177
+ else
178
+ {
179
+ fprintf (stdout, " You must use either websockets or mtls for authentication.\n " );
180
+ }
181
+
182
+ s_printHelp ();
183
+ return 1 ;
184
+ }
185
+
186
+ // x509 credentials provider configuration
187
+ if (s_cmdOptionExists (argv, argv + argc, " --x509" ))
188
+ {
189
+ if (!useWebSocket)
190
+ {
191
+ fprintf (stdout, " X509 credentials sourcing requires websockets to be enabled and configured.\n " );
192
+ s_printHelp ();
193
+ return 1 ;
194
+ }
195
+
196
+ if (!s_cmdOptionExists (argv, argv + argc, " --x509_role_alias" ))
197
+ {
198
+ fprintf (stdout, " X509 credentials sourcing requires an x509 role alias to be specified.\n " );
199
+ s_printHelp ();
200
+ return 1 ;
201
+ }
202
+ x509RoleAlias = s_getCmdOption (argv, argv + argc, " --x509_role_alias" );
203
+
204
+ if (!s_cmdOptionExists (argv, argv + argc, " --x509_endpoint" ))
205
+ {
206
+ fprintf (stdout, " X509 credentials sourcing requires an x509 endpoint to be specified.\n " );
207
+ s_printHelp ();
208
+ return 1 ;
209
+ }
210
+ x509Endpoint = s_getCmdOption (argv, argv + argc, " --x509_endpoint" );
211
+
212
+ if (!s_cmdOptionExists (argv, argv + argc, " --x509_thing" ))
213
+ {
214
+ fprintf (stdout, " X509 credentials sourcing requires an x509 thing name to be specified.\n " );
215
+ s_printHelp ();
216
+ return 1 ;
217
+ }
218
+ x509ThingName = s_getCmdOption (argv, argv + argc, " --x509_thing" );
219
+
220
+ if (!s_cmdOptionExists (argv, argv + argc, " --x509_cert" ))
221
+ {
222
+ fprintf (stdout, " X509 credentials sourcing requires an Iot thing certificate to be specified.\n " );
223
+ s_printHelp ();
224
+ return 1 ;
225
+ }
226
+ x509CertificatePath = s_getCmdOption (argv, argv + argc, " --x509_cert" );
227
+
228
+ if (!s_cmdOptionExists (argv, argv + argc, " --x509_key" ))
229
+ {
230
+ fprintf (stdout, " X509 credentials sourcing requires an Iot thing private key to be specified.\n " );
231
+ s_printHelp ();
232
+ return 1 ;
233
+ }
234
+ x509KeyPath = s_getCmdOption (argv, argv + argc, " --x509_key" );
235
+
236
+ if (s_cmdOptionExists (argv, argv + argc, " --x509_rootca" ))
237
+ {
238
+ x509RootCAFile = s_getCmdOption (argv, argv + argc, " --x509_rootca" );
239
+ }
240
+
241
+ useX509 = true ;
242
+ }
243
+
132
244
/* ********************* Now Setup an Mqtt Client ******************/
133
245
/*
134
246
* You need an event loop group to process IO events.
@@ -151,6 +263,7 @@ int main(int argc, char *argv[])
151
263
exit (-1 );
152
264
}
153
265
266
+ Aws::Crt::Io::TlsContext x509TlsCtx;
154
267
Aws::Iot::MqttClientConnectionConfigBuilder builder;
155
268
156
269
if (!certificatePath.empty () && !keyPath.empty ())
@@ -161,13 +274,71 @@ int main(int argc, char *argv[])
161
274
{
162
275
Aws::Iot::WebsocketConfig config (signingRegion, &bootstrap);
163
276
277
+ Aws::Crt::Http::HttpClientConnectionProxyOptions proxyOptions;
164
278
if (!proxyHost.empty ())
165
279
{
166
- Aws::Crt::Http::HttpClientConnectionProxyOptions proxyOptions;
167
280
proxyOptions.HostName = proxyHost;
168
281
proxyOptions.Port = proxyPort;
169
282
proxyOptions.AuthType = Aws::Crt::Http::AwsHttpProxyAuthenticationType::None;
170
- config.ProxyOptions = std::move (proxyOptions);
283
+ config.ProxyOptions = proxyOptions;
284
+ }
285
+
286
+ if (useX509)
287
+ {
288
+ Aws::Crt::Io::TlsContextOptions tlsCtxOptions =
289
+ Aws::Crt::Io::TlsContextOptions::InitClientWithMtls (x509CertificatePath.c_str (), x509KeyPath.c_str ());
290
+ if (!tlsCtxOptions)
291
+ {
292
+ fprintf (
293
+ stderr,
294
+ " Unable to initialize tls context options, error: %s!\n " ,
295
+ ErrorDebugString (tlsCtxOptions.LastError ()));
296
+ return -1 ;
297
+ }
298
+
299
+ if (!x509RootCAFile.empty ())
300
+ {
301
+ tlsCtxOptions.OverrideDefaultTrustStore (nullptr , x509RootCAFile.c_str ());
302
+ }
303
+
304
+ x509TlsCtx = Aws::Crt::Io::TlsContext (tlsCtxOptions, Aws::Crt::Io::TlsMode::CLIENT);
305
+ if (!x509TlsCtx)
306
+ {
307
+ fprintf (
308
+ stderr,
309
+ " Unable to create tls context, error: %s!\n " ,
310
+ ErrorDebugString (x509TlsCtx.GetInitializationError ()));
311
+ return -1 ;
312
+ }
313
+
314
+ Aws::Crt::Auth::CredentialsProviderX509Config x509Config;
315
+
316
+ x509Config.TlsOptions = x509TlsCtx.NewConnectionOptions ();
317
+ if (!x509Config.TlsOptions )
318
+ {
319
+ fprintf (
320
+ stderr,
321
+ " Unable to create tls options from tls context, error: %s!\n " ,
322
+ ErrorDebugString (x509Config.TlsOptions .LastError ()));
323
+ return -1 ;
324
+ }
325
+
326
+ x509Config.Bootstrap = &bootstrap;
327
+ x509Config.Endpoint = x509Endpoint;
328
+ x509Config.RoleAlias = x509RoleAlias;
329
+ x509Config.ThingName = x509ThingName;
330
+
331
+ if (!proxyHost.empty ())
332
+ {
333
+ x509Config.ProxyOptions = proxyOptions;
334
+ }
335
+
336
+ config.CredentialsProvider = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderX509 (x509Config);
337
+ if (!config.CredentialsProvider )
338
+ {
339
+ fprintf (stderr, " Failure to create X509 credentials provider!\n " );
340
+ return -1 ;
341
+ }
171
342
}
172
343
173
344
builder = Aws::Iot::MqttClientConnectionConfigBuilder (config);
0 commit comments