blob: 04572a53e7d8e1861fb06e38238a219d1f0d2065 [file] [log] [blame]
Radek Krejci9f03b482015-10-22 16:02:10 +02001/**
Michal Vasko95ea9ff2021-11-09 12:29:14 +01002 * @file session_client_tls.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief libnetconf2 - TLS specific session client transport functions
Radek Krejci9f03b482015-10-22 16:02:10 +02006 *
Michal Vasko11d4cdb2015-10-29 11:42:52 +01007 * This source is compiled only with libssl.
Radek Krejci9f03b482015-10-22 16:02:10 +02008 *
Michal Vasko95ea9ff2021-11-09 12:29:14 +01009 * @copyright
Radek Krejci9f03b482015-10-22 16:02:10 +020010 * Copyright (c) 2015 CESNET, z.s.p.o.
11 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010012 * This source code is licensed under BSD 3-Clause License (the "License").
13 * You may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
Michal Vaskoafd416b2016-02-25 14:51:46 +010015 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010016 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci9f03b482015-10-22 16:02:10 +020017 */
18
19#include <assert.h>
20#include <errno.h>
Radek Krejci9f03b482015-10-22 16:02:10 +020021#include <string.h>
22#include <unistd.h>
23
24#include <libyang/libyang.h>
Michal Vasko086311b2016-01-08 09:53:11 +010025#include <openssl/err.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020026#include <openssl/ossl_typ.h>
Michal Vaskodae48322016-02-25 14:49:48 +010027#include <openssl/x509.h>
Radek Krejci9f03b482015-10-22 16:02:10 +020028
Michal Vaskob83a3fa2021-05-26 09:53:42 +020029#include "libnetconf.h"
Michal Vaskoe22c6732016-01-29 11:03:02 +010030#include "session_client.h"
31#include "session_client_ch.h"
Michal Vasko11d4cdb2015-10-29 11:42:52 +010032
Rosen Penev4f552d62019-06-26 16:10:43 -070033#if OPENSSL_VERSION_NUMBER < 0x10100000L
34#define X509_STORE_CTX_get_by_subject X509_STORE_get_by_subject
35#endif
36
Radek Krejci62aa0642017-05-25 16:33:49 +020037struct nc_client_context *nc_client_context_location(void);
Michal Vaskob83a3fa2021-05-26 09:53:42 +020038int nc_session_new_ctx(struct nc_session *session, struct ly_ctx *ctx);
Radek Krejci62aa0642017-05-25 16:33:49 +020039
40#define client_opts nc_client_context_location()->opts
41#define tls_opts nc_client_context_location()->tls_opts
42#define tls_ch_opts nc_client_context_location()->tls_ch_opts
Michal Vasko3031aae2016-01-27 16:07:18 +010043
44static int tlsauth_ch;
Radek Krejci9f03b482015-10-22 16:02:10 +020045
Michal Vasko18aeb5d2017-02-17 09:23:56 +010046#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
47
48static int
49tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
50{
51 X509_STORE_CTX *store_ctx;
52 X509_OBJECT *obj;
53 X509_NAME *subject, *issuer;
54 X509 *cert;
55 X509_CRL *crl;
56 X509_REVOKED *revoked;
57 EVP_PKEY *pubkey;
58 int i, n, rc;
59 const ASN1_TIME *next_update = NULL;
60 struct nc_client_tls_opts *opts;
61
62 if (!preverify_ok) {
63 return 0;
64 }
65
66 opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts);
67
68 if (!opts->crl_store) {
69 /* nothing to check */
70 return 1;
71 }
72
73 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
74 subject = X509_get_subject_name(cert);
75 issuer = X509_get_issuer_name(cert);
76
77 /* try to retrieve a CRL corresponding to the _subject_ of
78 * the current certificate in order to verify it's integrity */
79 store_ctx = X509_STORE_CTX_new();
80 obj = X509_OBJECT_new();
81 X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL);
Rosen Penev4f552d62019-06-26 16:10:43 -070082 rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, subject, obj);
Michal Vasko18aeb5d2017-02-17 09:23:56 +010083 X509_STORE_CTX_free(store_ctx);
84 crl = X509_OBJECT_get0_X509_CRL(obj);
Michal Vaskob83a3fa2021-05-26 09:53:42 +020085 if ((rc > 0) && crl) {
Michal Vasko18aeb5d2017-02-17 09:23:56 +010086 next_update = X509_CRL_get0_nextUpdate(crl);
87
88 /* verify the signature on this CRL */
89 pubkey = X509_get_pubkey(cert);
90 if (X509_CRL_verify(crl, pubkey) <= 0) {
91 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
92 X509_OBJECT_free(obj);
93 if (pubkey) {
94 EVP_PKEY_free(pubkey);
95 }
96 return 0; /* fail */
97 }
98 if (pubkey) {
99 EVP_PKEY_free(pubkey);
100 }
101
102 /* check date of CRL to make sure it's not expired */
103 if (!next_update) {
104 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
105 X509_OBJECT_free(obj);
106 return 0; /* fail */
107 }
108 if (X509_cmp_current_time(next_update) < 0) {
109 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
110 X509_OBJECT_free(obj);
111 return 0; /* fail */
112 }
113 X509_OBJECT_free(obj);
114 }
115
116 /* try to retrieve a CRL corresponding to the _issuer_ of
117 * the current certificate in order to check for revocation */
118 store_ctx = X509_STORE_CTX_new();
119 obj = X509_OBJECT_new();
120 X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL);
Rosen Penev4f552d62019-06-26 16:10:43 -0700121 rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, issuer, obj);
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100122 X509_STORE_CTX_free(store_ctx);
123 crl = X509_OBJECT_get0_X509_CRL(obj);
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200124 if ((rc > 0) && crl) {
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100125 /* check if the current certificate is revoked by this CRL */
126 n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
127 for (i = 0; i < n; i++) {
128 revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
129 if (ASN1_INTEGER_cmp(X509_REVOKED_get0_serialNumber(revoked), X509_get_serialNumber(cert)) == 0) {
Michal Vasko05532772021-06-03 12:12:38 +0200130 ERR(NULL, "Certificate revoked!");
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100131 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
132 X509_OBJECT_free(obj);
133 return 0; /* fail */
134 }
135 }
136 X509_OBJECT_free(obj);
137 }
138
139 return 1; /* success */
140}
141
142#else
143
Radek Krejci9f03b482015-10-22 16:02:10 +0200144static int
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100145tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
Radek Krejci9f03b482015-10-22 16:02:10 +0200146{
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100147 X509_STORE_CTX store_ctx;
148 X509_OBJECT obj;
149 X509_NAME *subject, *issuer;
150 X509 *cert;
151 X509_CRL *crl;
152 X509_REVOKED *revoked;
153 EVP_PKEY *pubkey;
154 int i, n, rc;
155 ASN1_TIME *next_update = NULL;
Michal Vasko3031aae2016-01-27 16:07:18 +0100156 struct nc_client_tls_opts *opts;
Radek Krejci9f03b482015-10-22 16:02:10 +0200157
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100158 if (!preverify_ok) {
159 return 0;
160 }
Radek Krejci9f03b482015-10-22 16:02:10 +0200161
Michal Vasko3031aae2016-01-27 16:07:18 +0100162 opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts);
163
164 if (!opts->crl_store) {
165 /* nothing to check */
166 return 1;
167 }
168
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100169 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
170 subject = X509_get_subject_name(cert);
171 issuer = X509_get_issuer_name(cert);
172
173 /* try to retrieve a CRL corresponding to the _subject_ of
174 * the current certificate in order to verify it's integrity */
175 memset((char *)&obj, 0, sizeof obj);
Michal Vasko3031aae2016-01-27 16:07:18 +0100176 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Rosen Penev4f552d62019-06-26 16:10:43 -0700177 rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100178 X509_STORE_CTX_cleanup(&store_ctx);
179 crl = obj.data.crl;
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200180 if ((rc > 0) && crl) {
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100181 next_update = X509_CRL_get_nextUpdate(crl);
182
183 /* verify the signature on this CRL */
184 pubkey = X509_get_pubkey(cert);
185 if (X509_CRL_verify(crl, pubkey) <= 0) {
186 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
187 X509_OBJECT_free_contents(&obj);
188 if (pubkey) {
189 EVP_PKEY_free(pubkey);
190 }
191 return 0; /* fail */
192 }
193 if (pubkey) {
194 EVP_PKEY_free(pubkey);
195 }
196
197 /* check date of CRL to make sure it's not expired */
198 if (!next_update) {
199 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
200 X509_OBJECT_free_contents(&obj);
201 return 0; /* fail */
202 }
203 if (X509_cmp_current_time(next_update) < 0) {
204 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
205 X509_OBJECT_free_contents(&obj);
206 return 0; /* fail */
207 }
208 X509_OBJECT_free_contents(&obj);
209 }
210
211 /* try to retrieve a CRL corresponding to the _issuer_ of
212 * the current certificate in order to check for revocation */
213 memset((char *)&obj, 0, sizeof obj);
Michal Vasko3031aae2016-01-27 16:07:18 +0100214 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Rosen Penev4f552d62019-06-26 16:10:43 -0700215 rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100216 X509_STORE_CTX_cleanup(&store_ctx);
217 crl = obj.data.crl;
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200218 if ((rc > 0) && crl) {
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100219 /* check if the current certificate is revoked by this CRL */
220 n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
221 for (i = 0; i < n; i++) {
222 revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
223 if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
Michal Vasko05532772021-06-03 12:12:38 +0200224 ERR(NULL, "Certificate revoked!");
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100225 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
226 X509_OBJECT_free_contents(&obj);
227 return 0; /* fail */
228 }
229 }
230 X509_OBJECT_free_contents(&obj);
231 }
232
233 return 1; /* success */
234}
235
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100236#endif
237
Kevin Barrettd37d2fb2019-08-28 14:25:34 -0400238void
Michal Vaskoe22c6732016-01-29 11:03:02 +0100239_nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts)
240{
241 free(opts->cert_path);
242 free(opts->key_path);
243 free(opts->ca_file);
244 free(opts->ca_dir);
245 SSL_CTX_free(opts->tls_ctx);
246
247 free(opts->crl_file);
248 free(opts->crl_dir);
249 X509_STORE_free(opts->crl_store);
Radek Krejci5cebc6b2017-05-26 13:24:38 +0200250
251 memset(opts, 0, sizeof *opts);
Michal Vaskoe22c6732016-01-29 11:03:02 +0100252}
253
Michal Vaskob7558c52016-02-26 15:04:19 +0100254void
Michal Vaskoe22c6732016-01-29 11:03:02 +0100255nc_client_tls_destroy_opts(void)
256{
257 _nc_client_tls_destroy_opts(&tls_opts);
258 _nc_client_tls_destroy_opts(&tls_ch_opts);
259}
260
Michal Vasko3031aae2016-01-27 16:07:18 +0100261static int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100262_nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key, struct nc_client_tls_opts *opts)
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100263{
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100264 if (!client_cert) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200265 ERRARG("client_cert");
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100266 return -1;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100267 }
268
Michal Vasko3031aae2016-01-27 16:07:18 +0100269 free(opts->cert_path);
270 free(opts->key_path);
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100271
Michal Vasko9db2a6f2016-02-01 13:26:03 +0100272 opts->cert_path = strdup(client_cert);
273 if (!opts->cert_path) {
274 ERRMEM;
275 return -1;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100276 }
277
Michal Vasko3031aae2016-01-27 16:07:18 +0100278 if (client_key) {
279 opts->key_path = strdup(client_key);
Michal Vasko9db2a6f2016-02-01 13:26:03 +0100280 if (!opts->key_path) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100281 ERRMEM;
282 return -1;
283 }
284 } else {
285 opts->key_path = NULL;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100286 }
287
Michal Vasko3031aae2016-01-27 16:07:18 +0100288 opts->tls_ctx_change = 1;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100289
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100290 return 0;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100291}
292
Michal Vasko3031aae2016-01-27 16:07:18 +0100293API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100294nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key)
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100295{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100296 return _nc_client_tls_set_cert_key_paths(client_cert, client_key, &tls_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100297}
298
299API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100300nc_client_tls_ch_set_cert_key_paths(const char *client_cert, const char *client_key)
Michal Vasko3031aae2016-01-27 16:07:18 +0100301{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100302 return _nc_client_tls_set_cert_key_paths(client_cert, client_key, &tls_ch_opts);
303}
304
305static void
306_nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key, struct nc_client_tls_opts *opts)
307{
308 if (!client_cert && !client_key) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200309 ERRARG("client_cert and client_key");
Michal Vaskoe22c6732016-01-29 11:03:02 +0100310 return;
311 }
312
313 if (client_cert) {
314 *client_cert = opts->cert_path;
315 }
316 if (client_key) {
317 *client_key = opts->key_path;
318 }
319}
320
321API void
322nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key)
323{
324 _nc_client_tls_get_cert_key_paths(client_cert, client_key, &tls_opts);
325}
326
327API void
328nc_client_tls_ch_get_cert_key_paths(const char **client_cert, const char **client_key)
329{
330 _nc_client_tls_get_cert_key_paths(client_cert, client_key, &tls_ch_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100331}
332
333static int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100334_nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_client_tls_opts *opts)
Michal Vasko3031aae2016-01-27 16:07:18 +0100335{
Michal Vasko3031aae2016-01-27 16:07:18 +0100336 if (!ca_file && !ca_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200337 ERRARG("ca_file and ca_dir");
Michal Vasko3031aae2016-01-27 16:07:18 +0100338 return -1;
339 }
340
Michal Vasko3031aae2016-01-27 16:07:18 +0100341 free(opts->ca_file);
342 free(opts->ca_dir);
343
344 if (ca_file) {
345 opts->ca_file = strdup(ca_file);
346 if (!opts->ca_file) {
347 ERRMEM;
348 return -1;
349 }
350 } else {
351 opts->ca_file = NULL;
352 }
353
354 if (ca_dir) {
355 opts->ca_dir = strdup(ca_dir);
356 if (!opts->ca_dir) {
357 ERRMEM;
358 return -1;
359 }
360 } else {
361 opts->ca_dir = NULL;
362 }
363
364 opts->tls_ctx_change = 1;
365
366 return 0;
367}
368
369API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100370nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir)
Michal Vasko3031aae2016-01-27 16:07:18 +0100371{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100372 return _nc_client_tls_set_trusted_ca_paths(ca_file, ca_dir, &tls_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100373}
374
375API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100376nc_client_tls_ch_set_trusted_ca_paths(const char *ca_file, const char *ca_dir)
Michal Vasko3031aae2016-01-27 16:07:18 +0100377{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100378 return _nc_client_tls_set_trusted_ca_paths(ca_file, ca_dir, &tls_ch_opts);
379}
380
381static void
382_nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir, struct nc_client_tls_opts *opts)
383{
384 if (!ca_file && !ca_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200385 ERRARG("ca_file and ca_dir");
Michal Vaskoe22c6732016-01-29 11:03:02 +0100386 return;
387 }
388
389 if (ca_file) {
390 *ca_file = opts->ca_file;
391 }
392 if (ca_dir) {
393 *ca_dir = opts->ca_dir;
394 }
395}
396
397API void
398nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir)
399{
400 _nc_client_tls_get_trusted_ca_paths(ca_file, ca_dir, &tls_opts);
401}
402
403API void
404nc_client_tls_ch_get_trusted_ca_paths(const char **ca_file, const char **ca_dir)
405{
406 _nc_client_tls_get_trusted_ca_paths(ca_file, ca_dir, &tls_ch_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100407}
408
409static int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100410_nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc_client_tls_opts *opts)
Michal Vasko3031aae2016-01-27 16:07:18 +0100411{
Michal Vasko3031aae2016-01-27 16:07:18 +0100412 if (!crl_file && !crl_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200413 ERRARG("crl_file and crl_dir");
Michal Vasko3031aae2016-01-27 16:07:18 +0100414 return -1;
415 }
416
Michal Vasko3031aae2016-01-27 16:07:18 +0100417 free(opts->crl_file);
418 free(opts->crl_dir);
419
420 if (crl_file) {
421 opts->crl_file = strdup(crl_file);
422 if (!opts->crl_file) {
423 ERRMEM;
424 return -1;
425 }
426 } else {
427 opts->crl_file = NULL;
428 }
429
430 if (crl_dir) {
431 opts->crl_dir = strdup(crl_dir);
432 if (!opts->crl_dir) {
433 ERRMEM;
434 return -1;
435 }
436 } else {
437 opts->crl_dir = NULL;
438 }
439
440 opts->crl_store_change = 1;
441
442 return 0;
443}
444
445API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100446nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir)
Michal Vasko3031aae2016-01-27 16:07:18 +0100447{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100448 return _nc_client_tls_set_crl_paths(crl_file, crl_dir, &tls_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100449}
450
451API int
Michal Vaskoe22c6732016-01-29 11:03:02 +0100452nc_client_tls_ch_set_crl_paths(const char *crl_file, const char *crl_dir)
Michal Vasko3031aae2016-01-27 16:07:18 +0100453{
Michal Vaskoe22c6732016-01-29 11:03:02 +0100454 return _nc_client_tls_set_crl_paths(crl_file, crl_dir, &tls_ch_opts);
455}
456
457static void
458_nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir, struct nc_client_tls_opts *opts)
459{
460 if (!crl_file && !crl_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200461 ERRARG("crl_file and crl_dir");
Michal Vaskoe22c6732016-01-29 11:03:02 +0100462 return;
463 }
464
465 if (crl_file) {
466 *crl_file = opts->crl_file;
467 }
468 if (crl_dir) {
469 *crl_dir = opts->crl_dir;
470 }
471}
472
473API void
474nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir)
475{
476 _nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_opts);
477}
478
479API void
480nc_client_tls_ch_get_crl_paths(const char **crl_file, const char **crl_dir)
481{
482 _nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_ch_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +0100483}
484
485API int
486nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port)
487{
Michal Vasko9d4cca52022-09-07 11:19:57 +0200488 return nc_client_ch_add_bind_listen(address, port, NULL, NC_TI_OPENSSL);
489}
490
491API int
492nc_client_tls_ch_add_bind_hostname_listen(const char *address, uint16_t port, const char *hostname)
493{
494 return nc_client_ch_add_bind_listen(address, port, hostname, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100495}
496
497API int
498nc_client_tls_ch_del_bind(const char *address, uint16_t port)
499{
500 return nc_client_ch_del_bind(address, port, NC_TI_OPENSSL);
501}
502
Michal Vasko3031aae2016-01-27 16:07:18 +0100503static int
Michal Vasko55ce24a2022-09-07 09:24:43 +0200504nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername)
Michal Vasko3031aae2016-01-27 16:07:18 +0100505{
Michal Vasko9af52322022-07-25 14:39:30 +0200506 int rc = 0;
Michal Vasko3031aae2016-01-27 16:07:18 +0100507 char *key;
508 X509_LOOKUP *lookup;
Michal Vasko9af52322022-07-25 14:39:30 +0200509 X509_VERIFY_PARAM *vpm = NULL;
Michal Vasko3031aae2016-01-27 16:07:18 +0100510
511 if (!opts->tls_ctx || opts->tls_ctx_change) {
Michal Vaskoe22c6732016-01-29 11:03:02 +0100512 SSL_CTX_free(opts->tls_ctx);
Michal Vasko3031aae2016-01-27 16:07:18 +0100513
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100514#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
515 /* prepare global SSL context, highest available method is negotiated autmatically */
516 if (!(opts->tls_ctx = SSL_CTX_new(TLS_client_method())))
517#else
Michal Vasko3031aae2016-01-27 16:07:18 +0100518 /* prepare global SSL context, allow only mandatory TLS 1.2 */
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100519 if (!(opts->tls_ctx = SSL_CTX_new(TLSv1_2_client_method())))
520#endif
521 {
Michal Vasko05532772021-06-03 12:12:38 +0200522 ERR(NULL, "Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200523 rc = -1;
524 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100525 }
526 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER, tlsauth_verify_callback);
527
528 /* get peer certificate */
529 if (SSL_CTX_use_certificate_file(opts->tls_ctx, opts->cert_path, SSL_FILETYPE_PEM) != 1) {
Michal Vasko05532772021-06-03 12:12:38 +0200530 ERR(NULL, "Loading the client certificate from \'%s\' failed (%s).", opts->cert_path,
531 ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200532 rc = -1;
533 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100534 }
535
536 /* if the file with private key not specified, expect that the private key is stored with the certificate */
537 if (!opts->key_path) {
538 key = opts->cert_path;
539 } else {
540 key = opts->key_path;
541 }
542 if (SSL_CTX_use_PrivateKey_file(opts->tls_ctx, key, SSL_FILETYPE_PEM) != 1) {
Michal Vasko9af52322022-07-25 14:39:30 +0200543 ERR(NULL, "Loading the client private key from \'%s\' failed (%s).", key,
Michal Vasko05532772021-06-03 12:12:38 +0200544 ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200545 rc = -1;
546 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100547 }
548
549 if (!SSL_CTX_load_verify_locations(opts->tls_ctx, opts->ca_file, opts->ca_dir)) {
Michal Vasko05532772021-06-03 12:12:38 +0200550 ERR(NULL, "Failed to load the locations of trusted CA certificates (%s).",
551 ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200552 rc = -1;
553 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100554 }
Michal Vasko9af52322022-07-25 14:39:30 +0200555
556#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
Michal Vasko55ce24a2022-09-07 09:24:43 +0200557 if (peername) {
558 /* server identity (hostname) verification */
559 vpm = X509_VERIFY_PARAM_new();
560 if (!X509_VERIFY_PARAM_set1_host(vpm, peername, 0)) {
561 ERR(NULL, "Failed to set expected server hostname (%s).", ERR_reason_error_string(ERR_get_error()));
562 rc = -1;
563 goto cleanup;
564 }
565 if (!SSL_CTX_set1_param(opts->tls_ctx, vpm)) {
566 ERR(NULL, "Failed to set verify params (%s).", ERR_reason_error_string(ERR_get_error()));
567 rc = -1;
568 goto cleanup;
569 }
Michal Vasko9af52322022-07-25 14:39:30 +0200570 }
571#endif
Michal Vasko3031aae2016-01-27 16:07:18 +0100572 }
573
574 if (opts->crl_store_change || (!opts->crl_store && (opts->crl_file || opts->crl_dir))) {
575 /* set the revocation store with the correct paths for the callback */
576 X509_STORE_free(opts->crl_store);
577
578 opts->crl_store = X509_STORE_new();
579 if (!opts->crl_store) {
Michal Vasko05532772021-06-03 12:12:38 +0200580 ERR(NULL, "Unable to create a certificate store (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200581 rc = -1;
582 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100583 }
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100584
585#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0
586 /* whaveter this does... */
Michal Vasko3031aae2016-01-27 16:07:18 +0100587 opts->crl_store->cache = 0;
Michal Vasko18aeb5d2017-02-17 09:23:56 +0100588#endif
Michal Vasko3031aae2016-01-27 16:07:18 +0100589
590 if (opts->crl_file) {
591 if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file()))) {
Michal Vasko05532772021-06-03 12:12:38 +0200592 ERR(NULL, "Failed to add lookup method to CRL checking.");
Michal Vasko9af52322022-07-25 14:39:30 +0200593 rc = -1;
594 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100595 }
596 if (X509_LOOKUP_add_dir(lookup, opts->crl_file, X509_FILETYPE_PEM) != 1) {
Michal Vasko05532772021-06-03 12:12:38 +0200597 ERR(NULL, "Failed to add the revocation lookup file \"%s\".", opts->crl_file);
Michal Vasko9af52322022-07-25 14:39:30 +0200598 rc = -1;
599 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100600 }
601 }
602
603 if (opts->crl_dir) {
604 if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir()))) {
Michal Vasko05532772021-06-03 12:12:38 +0200605 ERR(NULL, "Failed to add lookup method to CRL checking.");
Michal Vasko9af52322022-07-25 14:39:30 +0200606 rc = -1;
607 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100608 }
609 if (X509_LOOKUP_add_dir(lookup, opts->crl_dir, X509_FILETYPE_PEM) != 1) {
Michal Vasko05532772021-06-03 12:12:38 +0200610 ERR(NULL, "Failed to add the revocation lookup directory \"%s\".", opts->crl_dir);
Michal Vasko9af52322022-07-25 14:39:30 +0200611 rc = -1;
612 goto cleanup;
Michal Vasko3031aae2016-01-27 16:07:18 +0100613 }
614 }
615 }
616
Michal Vasko9af52322022-07-25 14:39:30 +0200617cleanup:
618 X509_VERIFY_PARAM_free(vpm);
619 return rc;
620}
621
622static int
623nc_client_tls_connect_check(int connect_ret, SSL *tls)
624{
625 int verify;
Michal Vasko7ffcd142022-09-07 09:24:22 +0200626 const char *peername = "<unknown>";
627
628#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
629 /* get peer name (hostname of the server end) */
630 if (SSL_get0_peername(tls)) {
631 peername = SSL_get0_peername(tls);
632 }
633#endif
Michal Vasko9af52322022-07-25 14:39:30 +0200634
635 /* check certificate verification result */
636 verify = SSL_get_verify_result(tls);
637 switch (verify) {
638 case X509_V_OK:
639 if (connect_ret == 1) {
Michal Vasko7ffcd142022-09-07 09:24:22 +0200640 VRB(NULL, "Server certificate verified (domain \"%s\").", peername);
Michal Vasko9af52322022-07-25 14:39:30 +0200641 }
642 break;
643 default:
644 ERR(NULL, "Server certificate error (%s).", X509_verify_cert_error_string(verify));
645 }
646
647 /* check TLS connection result */
648 if (connect_ret != 1) {
649 switch (SSL_get_error(tls, connect_ret)) {
650 case SSL_ERROR_SYSCALL:
Michal Vasko7ffcd142022-09-07 09:24:22 +0200651 ERR(NULL, "SSL connect to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
Michal Vasko9af52322022-07-25 14:39:30 +0200652 break;
653 case SSL_ERROR_SSL:
Michal Vasko7ffcd142022-09-07 09:24:22 +0200654 ERR(NULL, "SSL connect to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
Michal Vasko9af52322022-07-25 14:39:30 +0200655 break;
656 default:
Michal Vasko7ffcd142022-09-07 09:24:22 +0200657 ERR(NULL, "SSL connect to \"%s\" failed.", peername);
Michal Vasko9af52322022-07-25 14:39:30 +0200658 break;
659 }
660 }
661
662 return connect_ret;
Radek Krejci9f03b482015-10-22 16:02:10 +0200663}
664
665API struct nc_session *
Michal Vasko9bee18d2015-12-08 14:41:42 +0100666nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx)
Radek Krejci9f03b482015-10-22 16:02:10 +0200667{
Radek Krejci9f03b482015-10-22 16:02:10 +0200668 struct nc_session *session = NULL;
Michal Vasko9af52322022-07-25 14:39:30 +0200669 int sock, ret;
roman6ece9c52022-06-22 09:29:17 +0200670 struct timespec ts_timeout;
Michal Vasko66032bc2019-01-22 15:03:12 +0100671 char *ip_host = NULL;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100672
Michal Vasko3031aae2016-01-27 16:07:18 +0100673 if (!tls_opts.cert_path || (!tls_opts.ca_file && !tls_opts.ca_dir)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200674 ERRINIT;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100675 return NULL;
676 }
Radek Krejci9f03b482015-10-22 16:02:10 +0200677
678 /* process parameters */
679 if (!host || strisempty(host)) {
680 host = "localhost";
681 }
682
683 if (!port) {
684 port = NC_PORT_TLS;
685 }
686
Michal Vasko3031aae2016-01-27 16:07:18 +0100687 /* create/update TLS structures */
Michal Vasko9af52322022-07-25 14:39:30 +0200688 if (nc_client_tls_update_opts(&tls_opts, host)) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100689 return NULL;
690 }
691
Radek Krejci9f03b482015-10-22 16:02:10 +0200692 /* prepare session structure */
Michal Vasko131120a2018-05-29 15:44:02 +0200693 session = nc_new_session(NC_CLIENT, 0);
Radek Krejci9f03b482015-10-22 16:02:10 +0200694 if (!session) {
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100695 ERRMEM;
Radek Krejci9f03b482015-10-22 16:02:10 +0200696 return NULL;
697 }
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100698 session->status = NC_STATUS_STARTING;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100699
700 /* fill the session */
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100701 session->ti_type = NC_TI_OPENSSL;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100702 if (!(session->ti.tls = SSL_new(tls_opts.tls_ctx))) {
Michal Vasko05532772021-06-03 12:12:38 +0200703 ERR(NULL, "Failed to create a new TLS session structure (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100704 goto fail;
705 }
Radek Krejci9f03b482015-10-22 16:02:10 +0200706
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100707 /* create and assign socket */
Michal Vaskoe49a15f2019-05-27 14:18:36 +0200708 sock = nc_sock_connect(host, port, -1, &client_opts.ka, NULL, &ip_host);
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100709 if (sock == -1) {
Michal Vasko05532772021-06-03 12:12:38 +0200710 ERR(NULL, "Unable to connect to %s:%u (%s).", host, port, strerror(errno));
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100711 goto fail;
712 }
713 SSL_set_fd(session->ti.tls, sock);
714
715 /* set the SSL_MODE_AUTO_RETRY flag to allow OpenSSL perform re-handshake automatically */
716 SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
717
718 /* connect and perform the handshake */
roman6ece9c52022-06-22 09:29:17 +0200719 nc_gettimespec_mono_add(&ts_timeout, NC_TRANSPORT_TIMEOUT);
Michal Vasko3031aae2016-01-27 16:07:18 +0100720 tlsauth_ch = 0;
Michal Vaskod51a2642021-09-03 13:03:24 +0200721 while (((ret = SSL_connect(session->ti.tls)) != 1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
Michal Vasko0190bc32016-03-02 15:47:49 +0100722 usleep(NC_TIMEOUT_STEP);
Michal Vasko60d8ffb2022-07-21 11:08:34 +0200723 if (nc_difftimespec_mono_cur(&ts_timeout) < 1) {
Michal Vasko7ffcd142022-09-07 09:24:22 +0200724 ERR(NULL, "SSL connect timeout.");
Michal Vasko0190bc32016-03-02 15:47:49 +0100725 goto fail;
726 }
727 }
Michal Vasko3cd55a72022-09-06 15:52:39 +0200728
729 /* check for errors */
Michal Vasko9af52322022-07-25 14:39:30 +0200730 if (nc_client_tls_connect_check(ret, session->ti.tls) != 1) {
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100731 goto fail;
732 }
733
Radek Krejcifd5b6682017-06-13 15:52:53 +0200734 if (nc_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
735 goto fail;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100736 }
Radek Krejcifd5b6682017-06-13 15:52:53 +0200737 ctx = session->ctx;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100738
Radek Krejci9f03b482015-10-22 16:02:10 +0200739 /* NETCONF handshake */
Michal Vasko131120a2018-05-29 15:44:02 +0200740 if (nc_handshake_io(session) != NC_MSG_HELLO) {
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100741 goto fail;
Radek Krejci9f03b482015-10-22 16:02:10 +0200742 }
Michal Vaskoad611702015-12-03 13:41:51 +0100743 session->status = NC_STATUS_RUNNING;
Radek Krejci9f03b482015-10-22 16:02:10 +0200744
Michal Vaskoef578332016-01-25 13:20:09 +0100745 if (nc_ctx_check_and_fill(session) == -1) {
Michal Vasko57eb9402015-12-08 14:38:12 +0100746 goto fail;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100747 }
748
749 /* store information into session and the dictionary */
Michal Vasko93224072021-11-09 12:14:28 +0100750 session->host = ip_host;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100751 session->port = port;
Michal Vasko93224072021-11-09 12:14:28 +0100752 session->username = strdup("certificate-based");
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100753
Radek Krejci9f03b482015-10-22 16:02:10 +0200754 return session;
755
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100756fail:
Michal Vasko66032bc2019-01-22 15:03:12 +0100757 free(ip_host);
Michal Vaskoe1a64ec2016-03-01 12:21:58 +0100758 nc_session_free(session, NULL);
Radek Krejci9f03b482015-10-22 16:02:10 +0200759 return NULL;
760}
761
762API struct nc_session *
763nc_connect_libssl(SSL *tls, struct ly_ctx *ctx)
764{
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100765 struct nc_session *session;
Radek Krejci9f03b482015-10-22 16:02:10 +0200766
Michal Vasko45e53ae2016-04-07 11:46:03 +0200767 if (!tls) {
768 ERRARG("tls");
769 return NULL;
770 } else if (!SSL_is_init_finished(tls)) {
Michal Vasko05532772021-06-03 12:12:38 +0200771 ERR(NULL, "Supplied TLS session is not fully connected!");
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100772 return NULL;
773 }
774
775 /* prepare session structure */
Michal Vasko131120a2018-05-29 15:44:02 +0200776 session = nc_new_session(NC_CLIENT, 0);
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100777 if (!session) {
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100778 ERRMEM;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100779 return NULL;
780 }
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100781 session->status = NC_STATUS_STARTING;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100782 session->ti_type = NC_TI_OPENSSL;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100783 session->ti.tls = tls;
784
Radek Krejcifd5b6682017-06-13 15:52:53 +0200785 if (nc_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
786 goto fail;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100787 }
Radek Krejcifd5b6682017-06-13 15:52:53 +0200788 ctx = session->ctx;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100789
790 /* NETCONF handshake */
Michal Vasko131120a2018-05-29 15:44:02 +0200791 if (nc_handshake_io(session) != NC_MSG_HELLO) {
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100792 goto fail;
793 }
Michal Vaskoad611702015-12-03 13:41:51 +0100794 session->status = NC_STATUS_RUNNING;
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100795
Michal Vaskoef578332016-01-25 13:20:09 +0100796 if (nc_ctx_check_and_fill(session) == -1) {
Michal Vasko57eb9402015-12-08 14:38:12 +0100797 goto fail;
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100798 }
799
Michal Vasko11d4cdb2015-10-29 11:42:52 +0100800 return session;
801
802fail:
Michal Vaskob604ed52022-01-24 09:56:14 +0100803 session->ti_type = NC_TI_NONE;
Michal Vaskoa42a7f02021-07-02 08:43:12 +0200804 session->ti.tls = NULL;
Michal Vaskoe1a64ec2016-03-01 12:21:58 +0100805 nc_session_free(session, NULL);
Radek Krejci9f03b482015-10-22 16:02:10 +0200806 return NULL;
807}
808
Michal Vasko3031aae2016-01-27 16:07:18 +0100809struct nc_session *
Michal Vasko9d4cca52022-09-07 11:19:57 +0200810nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout, const char *peername)
Michal Vasko80cad7f2015-12-08 14:42:27 +0100811{
Michal Vasko3cd55a72022-09-06 15:52:39 +0200812 int ret;
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200813 SSL *tls = NULL;
814 struct nc_session *session = NULL;
roman6ece9c52022-06-22 09:29:17 +0200815 struct timespec ts_timeout;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100816
Michal Vasko9d4cca52022-09-07 11:19:57 +0200817 /* create/update TLS structures with explicit expected peername, if any set, the host is just the IP */
818 if (nc_client_tls_update_opts(&tls_ch_opts, peername)) {
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200819 goto cleanup;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100820 }
821
Michal Vasko3031aae2016-01-27 16:07:18 +0100822 if (!(tls = SSL_new(tls_ch_opts.tls_ctx))) {
Michal Vasko05532772021-06-03 12:12:38 +0200823 ERR(NULL, "Failed to create new TLS session structure (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200824 goto cleanup;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100825 }
826
827 SSL_set_fd(tls, sock);
828
829 /* set the SSL_MODE_AUTO_RETRY flag to allow OpenSSL perform re-handshake automatically */
830 SSL_set_mode(tls, SSL_MODE_AUTO_RETRY);
831
832 /* connect and perform the handshake */
Michal Vasko36c7be82017-02-22 13:37:59 +0100833 if (timeout > -1) {
roman6ece9c52022-06-22 09:29:17 +0200834 nc_gettimespec_mono_add(&ts_timeout, timeout);
Michal Vasko36c7be82017-02-22 13:37:59 +0100835 }
Michal Vasko3031aae2016-01-27 16:07:18 +0100836 tlsauth_ch = 1;
Michal Vasko0190bc32016-03-02 15:47:49 +0100837 while (((ret = SSL_connect(tls)) == -1) && (SSL_get_error(tls, ret) == SSL_ERROR_WANT_READ)) {
838 usleep(NC_TIMEOUT_STEP);
Michal Vasko60d8ffb2022-07-21 11:08:34 +0200839 if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
Michal Vasko7ffcd142022-09-07 09:24:22 +0200840 ERR(NULL, "SSL connect timeout.");
roman6ece9c52022-06-22 09:29:17 +0200841 goto cleanup;
Michal Vasko0190bc32016-03-02 15:47:49 +0100842 }
843 }
Michal Vasko80cad7f2015-12-08 14:42:27 +0100844
Michal Vasko3cd55a72022-09-06 15:52:39 +0200845 /* check for errors */
846 if (nc_client_tls_connect_check(ret, tls) != 1) {
847 goto cleanup;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100848 }
849
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200850 /* connect */
Michal Vasko80cad7f2015-12-08 14:42:27 +0100851 session = nc_connect_libssl(tls, ctx);
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200852 if (!session) {
853 goto cleanup;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100854 }
855
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200856 session->flags |= NC_SESSION_CALLHOME;
857
858 /* store information into session and the dictionary */
Michal Vasko93224072021-11-09 12:14:28 +0100859 session->host = strdup(host);
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200860 session->port = port;
Michal Vasko93224072021-11-09 12:14:28 +0100861 session->username = strdup("certificate-based");
Michal Vaskoc64c38c2021-07-02 08:43:53 +0200862
863cleanup:
864 if (!session) {
865 SSL_free(tls);
866 close(sock);
867 }
Michal Vasko80cad7f2015-12-08 14:42:27 +0100868 return session;
869}