blob: a7517c1d032e6f0ba6790f68c9a196305004ab97 [file] [log] [blame]
Radek Krejci5da708a2015-09-01 17:33:23 +02001/**
Michal Vasko086311b2016-01-08 09:53:11 +01002 * \file session_server_tls.c
3 * \author Michal Vasko <mvasko@cesnet.cz>
4 * \brief libnetconf2 TLS server session manipulation functions
Radek Krejci5da708a2015-09-01 17:33:23 +02005 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vaskoafd416b2016-02-25 14:51:46 +010011 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci5da708a2015-09-01 17:33:23 +020013 */
14
Michal Vaskoc14e3c82016-01-11 16:14:30 +010015#define _GNU_SOURCE
16
17#include <string.h>
18#include <poll.h>
Michal Vaskof0537d82016-01-29 14:42:38 +010019#include <unistd.h>
Michal Vaskoc14e3c82016-01-11 16:14:30 +010020
21#include <openssl/ssl.h>
22#include <openssl/evp.h>
23#include <openssl/err.h>
24#include <openssl/x509v3.h>
Michal Vaskoe2713da2016-08-22 16:06:40 +020025#include <openssl/x509.h>
Michal Vaskoc14e3c82016-01-11 16:14:30 +010026
Michal Vasko11d142a2016-01-19 15:58:24 +010027#include "session_server.h"
Michal Vaskoe22c6732016-01-29 11:03:02 +010028#include "session_server_ch.h"
29#include "libnetconf.h"
Radek Krejci5da708a2015-09-01 17:33:23 +020030
Michal Vasko3031aae2016-01-27 16:07:18 +010031struct nc_server_tls_opts tls_ch_opts;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010032pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER;
Michal Vaskoc14e3c82016-01-11 16:14:30 +010033extern struct nc_server_opts server_opts;
Michal Vaskoc61c4492016-01-25 11:13:34 +010034
Michal Vasko5c2f7952016-01-22 13:16:31 +010035static pthread_key_t verify_key;
36static pthread_once_t verify_once = PTHREAD_ONCE_INIT;
37
Michal Vaskoc14e3c82016-01-11 16:14:30 +010038static char *
39asn1time_to_str(ASN1_TIME *t)
Michal Vasko086311b2016-01-08 09:53:11 +010040{
Michal Vaskoc14e3c82016-01-11 16:14:30 +010041 char *cp;
42 BIO *bio;
43 int n;
Radek Krejci5da708a2015-09-01 17:33:23 +020044
Michal Vaskoc14e3c82016-01-11 16:14:30 +010045 if (!t) {
46 return NULL;
47 }
48 bio = BIO_new(BIO_s_mem());
49 if (!bio) {
50 return NULL;
51 }
52 ASN1_TIME_print(bio, t);
53 n = BIO_pending(bio);
54 cp = malloc(n + 1);
Michal Vasko4eb3c312016-03-01 14:09:37 +010055 if (!cp) {
56 ERRMEM;
57 BIO_free(bio);
58 return NULL;
59 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +010060 n = BIO_read(bio, cp, n);
61 if (n < 0) {
62 BIO_free(bio);
63 free(cp);
64 return NULL;
65 }
66 cp[n] = '\0';
67 BIO_free(bio);
68 return cp;
69}
70
71static void
72digest_to_str(const unsigned char *digest, unsigned int dig_len, char **str)
73{
74 unsigned int i;
75
76 *str = malloc(dig_len * 3);
Michal Vasko4eb3c312016-03-01 14:09:37 +010077 if (!*str) {
78 ERRMEM;
79 return;
80 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +010081 for (i = 0; i < dig_len - 1; ++i) {
82 sprintf((*str) + (i * 3), "%02x:", digest[i]);
83 }
84 sprintf((*str) + (i * 3), "%02x", digest[i]);
85}
86
87/* return NULL - SSL error can be retrieved */
88static X509 *
89base64der_to_cert(const char *in)
90{
91 X509 *out;
92 char *buf;
93 BIO *bio;
94
95 if (in == NULL) {
96 return NULL;
97 }
98
99 if (asprintf(&buf, "%s%s%s", "-----BEGIN CERTIFICATE-----\n", in, "\n-----END CERTIFICATE-----") == -1) {
100 return NULL;
101 }
102 bio = BIO_new_mem_buf(buf, strlen(buf));
103 if (!bio) {
104 free(buf);
105 return NULL;
106 }
107
108 out = PEM_read_bio_X509(bio, NULL, NULL, NULL);
109 if (!out) {
110 free(buf);
111 BIO_free(bio);
112 return NULL;
113 }
114
115 free(buf);
116 BIO_free(bio);
117 return out;
118}
119
120/* return NULL - either errno or SSL error */
121static X509 *
122pem_to_cert(const char *path)
123{
124 FILE *fp;
125 X509 *out;
126
127 fp = fopen(path, "r");
128 if (!fp) {
129 return NULL;
130 }
131
132 out = PEM_read_X509(fp, NULL, NULL, NULL);
133 fclose(fp);
134 return out;
135}
136
Michal Vasko6e08cb72017-02-02 11:15:29 +0100137static EVP_PKEY *
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100138base64der_to_privatekey(const char *in, int rsa)
139{
140 EVP_PKEY *out;
141 char *buf;
142 BIO *bio;
143
144 if (in == NULL) {
145 return NULL;
146 }
147
148 if (asprintf(&buf, "%s%s%s%s%s%s%s", "-----BEGIN ", (rsa ? "RSA" : "DSA"), " PRIVATE KEY-----\n", in, "\n-----END ", (rsa ? "RSA" : "DSA"), " PRIVATE KEY-----") == -1) {
149 return NULL;
150 }
151 bio = BIO_new_mem_buf(buf, strlen(buf));
152 if (!bio) {
153 free(buf);
154 return NULL;
155 }
156
157 out = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
158 if (!out) {
159 free(buf);
160 BIO_free(bio);
161 return NULL;
162 }
163
164 free(buf);
165 BIO_free(bio);
166 return out;
Michal Vasko6e08cb72017-02-02 11:15:29 +0100167}
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100168
169static int
170cert_pubkey_match(X509 *cert1, X509 *cert2)
171{
172 ASN1_BIT_STRING *bitstr1, *bitstr2;
173
174 bitstr1 = X509_get0_pubkey_bitstr(cert1);
175 bitstr2 = X509_get0_pubkey_bitstr(cert2);
176
177 if (!bitstr1 || !bitstr2 || (bitstr1->length != bitstr2->length) ||
178 memcmp(bitstr1->data, bitstr2->data, bitstr1->length)) {
179 return 0;
180 }
181
182 return 1;
183}
184
185static int
186nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type, char **username)
187{
188 STACK_OF(GENERAL_NAME) *san_names;
189 GENERAL_NAME *san_name;
190 ASN1_OCTET_STRING *ip;
191 int i, san_count;
192 char *subject, *common_name;
193
194 if (map_type == NC_TLS_CTN_COMMON_NAME) {
195 subject = X509_NAME_oneline(X509_get_subject_name(client_cert), NULL, 0);
196 common_name = strstr(subject, "CN=");
197 if (!common_name) {
Michal Vaskod083db62016-01-19 10:31:29 +0100198 WRN("Certificate does not include the commonName field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100199 free(subject);
200 return 1;
201 }
202 common_name += 3;
203 if (strchr(common_name, '/')) {
204 *strchr(common_name, '/') = '\0';
205 }
206 *username = strdup(common_name);
Michal Vasko4eb3c312016-03-01 14:09:37 +0100207 if (!*username) {
208 ERRMEM;
209 return 1;
210 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100211 free(subject);
212 } else {
213 /* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */
214 san_names = X509_get_ext_d2i(client_cert, NID_subject_alt_name, NULL, NULL);
215 if (!san_names) {
Michal Vaskod083db62016-01-19 10:31:29 +0100216 WRN("Certificate has no SANs or failed to retrieve them.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100217 return 1;
218 }
219
220 san_count = sk_GENERAL_NAME_num(san_names);
221 for (i = 0; i < san_count; ++i) {
222 san_name = sk_GENERAL_NAME_value(san_names, i);
223
224 /* rfc822Name (email) */
225 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_RFC822_NAME) &&
226 san_name->type == GEN_EMAIL) {
227 *username = strdup((char *)ASN1_STRING_data(san_name->d.rfc822Name));
Michal Vasko4eb3c312016-03-01 14:09:37 +0100228 if (!*username) {
229 ERRMEM;
230 return 1;
231 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100232 break;
233 }
234
235 /* dNSName */
236 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_DNS_NAME) &&
237 san_name->type == GEN_DNS) {
238 *username = strdup((char *)ASN1_STRING_data(san_name->d.dNSName));
Michal Vasko4eb3c312016-03-01 14:09:37 +0100239 if (!*username) {
240 ERRMEM;
241 return 1;
242 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100243 break;
244 }
245
246 /* iPAddress */
247 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_IP_ADDRESS) &&
248 san_name->type == GEN_IPADD) {
249 ip = san_name->d.iPAddress;
250 if (ip->length == 4) {
251 if (asprintf(username, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100252 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100253 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
254 return -1;
255 }
256 break;
257 } else if (ip->length == 16) {
258 if (asprintf(username, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
259 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
260 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
261 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100262 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100263 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
264 return -1;
265 }
266 break;
267 } else {
Michal Vaskod083db62016-01-19 10:31:29 +0100268 WRN("SAN IP address in an unknown format (length is %d).", ip->length);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100269 }
270 }
271 }
272 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
273
274 if (i < san_count) {
275 switch (map_type) {
276 case NC_TLS_CTN_SAN_RFC822_NAME:
Michal Vaskod083db62016-01-19 10:31:29 +0100277 WRN("Certificate does not include the SAN rfc822Name field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100278 break;
279 case NC_TLS_CTN_SAN_DNS_NAME:
Michal Vaskod083db62016-01-19 10:31:29 +0100280 WRN("Certificate does not include the SAN dNSName field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100281 break;
282 case NC_TLS_CTN_SAN_IP_ADDRESS:
Michal Vaskod083db62016-01-19 10:31:29 +0100283 WRN("Certificate does not include the SAN iPAddress field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100284 break;
285 case NC_TLS_CTN_SAN_ANY:
Michal Vaskod083db62016-01-19 10:31:29 +0100286 WRN("Certificate does not include any relevant SAN fields.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100287 break;
288 default:
289 break;
290 }
291 return 1;
292 }
293 }
294
295 return 0;
296}
297
298/* return: 0 - OK, 1 - no match, -1 - error */
299static int
Michal Vaskoc61c4492016-01-25 11:13:34 +0100300nc_tls_cert_to_name(struct nc_ctn *ctn_first, X509 *cert, NC_TLS_CTN_MAPTYPE *map_type, const char **name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100301{
302 char *digest_md5 = NULL, *digest_sha1 = NULL, *digest_sha224 = NULL;
303 char *digest_sha256 = NULL, *digest_sha384 = NULL, *digest_sha512 = NULL;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100304 unsigned char *buf = malloc(64);
305 unsigned int buf_len = 64;
306 int ret = 0;
Michal Vasko5e3f3392016-01-20 11:13:01 +0100307 struct nc_ctn *ctn;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100308
Michal Vasko4eb3c312016-03-01 14:09:37 +0100309 if (!buf) {
310 ERRMEM;
311 return -1;
312 }
313
Michal Vaskoc61c4492016-01-25 11:13:34 +0100314 if (!ctn_first || !cert || !map_type || !name) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100315 free(buf);
316 return -1;
317 }
318
Michal Vaskoc61c4492016-01-25 11:13:34 +0100319 for (ctn = ctn_first; ctn; ctn = ctn->next) {
Michal Vasko3cf4aaa2017-02-01 15:03:36 +0100320 /* first make sure the entry is valid */
321 if (!ctn->fingerprint || !ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) {
322 VRB("Cert verify CTN: entry with id %u not valid, skipping.", ctn->id);
323 continue;
324 }
325
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100326 /* MD5 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100327 if (!strncmp(ctn->fingerprint, "01", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100328 if (!digest_md5) {
329 if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100330 ERR("Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100331 ret = -1;
332 goto cleanup;
333 }
334 digest_to_str(buf, buf_len, &digest_md5);
335 }
336
Michal Vasko5e3f3392016-01-20 11:13:01 +0100337 if (!strcasecmp(ctn->fingerprint + 3, digest_md5)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100338 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100339 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100340 *map_type = ctn->map_type;
341 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
342 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100343 }
344 break;
345 }
346
347 /* SHA-1 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100348 } else if (!strncmp(ctn->fingerprint, "02", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100349 if (!digest_sha1) {
350 if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100351 ERR("Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100352 ret = -1;
353 goto cleanup;
354 }
355 digest_to_str(buf, buf_len, &digest_sha1);
356 }
357
Michal Vasko5e3f3392016-01-20 11:13:01 +0100358 if (!strcasecmp(ctn->fingerprint + 3, digest_sha1)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100359 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100360 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100361 *map_type = ctn->map_type;
362 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
363 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100364 }
365 break;
366 }
367
368 /* SHA-224 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100369 } else if (!strncmp(ctn->fingerprint, "03", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100370 if (!digest_sha224) {
371 if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100372 ERR("Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100373 ret = -1;
374 goto cleanup;
375 }
376 digest_to_str(buf, buf_len, &digest_sha224);
377 }
378
Michal Vasko5e3f3392016-01-20 11:13:01 +0100379 if (!strcasecmp(ctn->fingerprint + 3, digest_sha224)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100380 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100381 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100382 *map_type = ctn->map_type;
383 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
384 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100385 }
386 break;
387 }
388
389 /* SHA-256 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100390 } else if (!strncmp(ctn->fingerprint, "04", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100391 if (!digest_sha256) {
392 if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100393 ERR("Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100394 ret = -1;
395 goto cleanup;
396 }
397 digest_to_str(buf, buf_len, &digest_sha256);
398 }
399
Michal Vasko5e3f3392016-01-20 11:13:01 +0100400 if (!strcasecmp(ctn->fingerprint + 3, digest_sha256)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100401 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100402 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100403 *map_type = ctn->map_type;
404 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
405 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100406 }
407 break;
408 }
409
410 /* SHA-384 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100411 } else if (!strncmp(ctn->fingerprint, "05", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100412 if (!digest_sha384) {
413 if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100414 ERR("Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100415 ret = -1;
416 goto cleanup;
417 }
418 digest_to_str(buf, buf_len, &digest_sha384);
419 }
420
Michal Vasko5e3f3392016-01-20 11:13:01 +0100421 if (!strcasecmp(ctn->fingerprint + 3, digest_sha384)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100422 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100423 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100424 *map_type = ctn->map_type;
425 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
426 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100427 }
428 break;
429 }
430
431 /* SHA-512 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100432 } else if (!strncmp(ctn->fingerprint, "06", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100433 if (!digest_sha512) {
434 if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100435 ERR("Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100436 ret = -1;
437 goto cleanup;
438 }
439 digest_to_str(buf, buf_len, &digest_sha512);
440 }
441
Michal Vasko5e3f3392016-01-20 11:13:01 +0100442 if (!strcasecmp(ctn->fingerprint + 3, digest_sha512)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100443 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100444 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100445 *map_type = ctn->map_type;
446 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
447 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100448 }
449 break;
450 }
451
452 /* unknown */
453 } else {
Michal Vasko5e3f3392016-01-20 11:13:01 +0100454 WRN("Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100455 }
456 }
457
Michal Vasko5e3f3392016-01-20 11:13:01 +0100458 if (!ctn) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100459 ret = 1;
460 }
461
462cleanup:
463 free(digest_md5);
464 free(digest_sha1);
465 free(digest_sha224);
466 free(digest_sha256);
467 free(digest_sha384);
468 free(digest_sha512);
469 free(buf);
470 return ret;
471}
472
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100473static int
474nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
475{
476 X509_STORE_CTX store_ctx;
477 X509_OBJECT obj;
478 X509_NAME *subject;
479 X509_NAME *issuer;
480 X509 *cert;
481 X509_CRL *crl;
482 X509_REVOKED *revoked;
483 STACK_OF(X509) *cert_stack;
484 EVP_PKEY *pubkey;
485 struct nc_session* session;
Michal Vasko3031aae2016-01-27 16:07:18 +0100486 struct nc_server_tls_opts *opts;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100487 long serial;
488 int i, n, rc, depth;
489 char *cp;
490 const char *username = NULL;
491 NC_TLS_CTN_MAPTYPE map_type = 0;
492 ASN1_TIME *last_update = NULL, *next_update = NULL;
493
Michal Vasko6d292992016-01-18 09:42:38 +0100494 /* get the thread session */
Michal Vasko5c2f7952016-01-22 13:16:31 +0100495 session = pthread_getspecific(verify_key);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100496 if (!session) {
497 ERRINT;
498 return 0;
499 }
500
Michal Vasko2cc4c682016-03-01 09:16:48 +0100501 opts = session->data;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100502
503 /* get the last certificate, that is the peer (client) certificate */
Michal Vasko2e6defd2016-10-07 15:48:15 +0200504 if (!session->opts.server.client_cert) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100505 cert_stack = X509_STORE_CTX_get1_chain(x509_ctx);
506 /* TODO all that is needed, but function X509_up_ref not present in older OpenSSL versions
507 session->cert = sk_X509_value(cert_stack, sk_X509_num(cert_stack) - 1);
508 X509_up_ref(session->cert);
509 sk_X509_pop_free(cert_stack, X509_free); */
510 while ((cert = sk_X509_pop(cert_stack))) {
Michal Vasko2e6defd2016-10-07 15:48:15 +0200511 X509_free(session->opts.server.client_cert);
512 session->opts.server.client_cert = cert;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100513 }
514 sk_X509_pop_free(cert_stack, X509_free);
515 }
516
517 /* standard certificate verification failed, so a trusted client cert must match to continue */
518 if (!preverify_ok) {
Michal Vasko2e6defd2016-10-07 15:48:15 +0200519 subject = X509_get_subject_name(session->opts.server.client_cert);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100520 cert_stack = X509_STORE_get1_certs(x509_ctx, subject);
521 if (cert_stack) {
522 for (i = 0; i < sk_X509_num(cert_stack); ++i) {
Michal Vasko2e6defd2016-10-07 15:48:15 +0200523 if (cert_pubkey_match(session->opts.server.client_cert, sk_X509_value(cert_stack, i))) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100524 /* we are just overriding the failed standard certificate verification (preverify_ok == 0),
525 * this callback will be called again with the same current certificate and preverify_ok == 1 */
Michal Vasko05ba9df2016-01-13 14:40:27 +0100526 VRB("Cert verify: fail (%s), but the client certificate is trusted, continuing.",
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100527 X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
528 X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
529 sk_X509_pop_free(cert_stack, X509_free);
530 return 1;
531 }
532 }
533 sk_X509_pop_free(cert_stack, X509_free);
534 }
535
536 ERR("Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
537 return 0;
538 }
539
540 /* print cert verify info */
541 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
Michal Vaskod083db62016-01-19 10:31:29 +0100542 VRB("Cert verify: depth %d.", depth);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100543
544 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
545 subject = X509_get_subject_name(cert);
546 issuer = X509_get_issuer_name(cert);
547
548 cp = X509_NAME_oneline(subject, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100549 VRB("Cert verify: subject: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100550 OPENSSL_free(cp);
551 cp = X509_NAME_oneline(issuer, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100552 VRB("Cert verify: issuer: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100553 OPENSSL_free(cp);
554
555 /* check for revocation if set */
Michal Vaskoc61c4492016-01-25 11:13:34 +0100556 if (opts->crl_store) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100557 /* try to retrieve a CRL corresponding to the _subject_ of
558 * the current certificate in order to verify it's integrity */
559 memset((char *)&obj, 0, sizeof(obj));
Michal Vaskoc61c4492016-01-25 11:13:34 +0100560 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100561 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
562 X509_STORE_CTX_cleanup(&store_ctx);
563 crl = obj.data.crl;
564 if (rc > 0 && crl) {
565 cp = X509_NAME_oneline(subject, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100566 VRB("Cert verify CRL: issuer: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100567 OPENSSL_free(cp);
568
569 last_update = X509_CRL_get_lastUpdate(crl);
570 next_update = X509_CRL_get_nextUpdate(crl);
571 cp = asn1time_to_str(last_update);
Michal Vaskod083db62016-01-19 10:31:29 +0100572 VRB("Cert verify CRL: last update: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100573 free(cp);
574 cp = asn1time_to_str(next_update);
Michal Vaskod083db62016-01-19 10:31:29 +0100575 VRB("Cert verify CRL: next update: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100576 free(cp);
577
578 /* verify the signature on this CRL */
579 pubkey = X509_get_pubkey(cert);
580 if (X509_CRL_verify(crl, pubkey) <= 0) {
581 ERR("Cert verify CRL: invalid signature.");
582 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
583 X509_OBJECT_free_contents(&obj);
584 if (pubkey) {
585 EVP_PKEY_free(pubkey);
586 }
587 return 0;
588 }
589 if (pubkey) {
590 EVP_PKEY_free(pubkey);
591 }
592
593 /* check date of CRL to make sure it's not expired */
594 if (!next_update) {
595 ERR("Cert verify CRL: invalid nextUpdate field.");
596 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
597 X509_OBJECT_free_contents(&obj);
598 return 0;
599 }
600 if (X509_cmp_current_time(next_update) < 0) {
601 ERR("Cert verify CRL: expired - revoking all certificates.");
602 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
603 X509_OBJECT_free_contents(&obj);
604 return 0;
605 }
606 X509_OBJECT_free_contents(&obj);
607 }
608
609 /* try to retrieve a CRL corresponding to the _issuer_ of
Michal Vaskob48aa812016-01-18 14:13:09 +0100610 * the current certificate in order to check for revocation */
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100611 memset((char *)&obj, 0, sizeof(obj));
Michal Vaskoc61c4492016-01-25 11:13:34 +0100612 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100613 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
614 X509_STORE_CTX_cleanup(&store_ctx);
615 crl = obj.data.crl;
616 if (rc > 0 && crl) {
617 /* check if the current certificate is revoked by this CRL */
618 n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
619 for (i = 0; i < n; i++) {
620 revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
621 if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
622 serial = ASN1_INTEGER_get(revoked->serialNumber);
623 cp = X509_NAME_oneline(issuer, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100624 ERR("Cert verify CRL: certificate with serial %ld (0x%lX) revoked per CRL from issuer %s.", serial, serial, cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100625 OPENSSL_free(cp);
626 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
627 X509_OBJECT_free_contents(&obj);
628 return 0;
629 }
630 }
631 X509_OBJECT_free_contents(&obj);
632 }
633 }
634
635 /* cert-to-name already successful */
636 if (session->username) {
637 return 1;
638 }
639
640 /* cert-to-name */
Michal Vaskoc61c4492016-01-25 11:13:34 +0100641 rc = nc_tls_cert_to_name(opts->ctn, cert, &map_type, &username);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100642
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100643 if (rc) {
644 if (rc == -1) {
645 /* fatal error */
646 depth = 0;
647 }
648 /* rc == 1 is a normal CTN fail (no match found) */
649 goto fail;
650 }
651
652 /* cert-to-name match, now to extract the specific field from the peer cert */
653 if (map_type == NC_TLS_CTN_SPECIFIED) {
654 session->username = lydict_insert(server_opts.ctx, username, 0);
655 } else {
Michal Vasko2e6defd2016-10-07 15:48:15 +0200656 rc = nc_tls_ctn_get_username_from_cert(session->opts.server.client_cert, map_type, &cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100657 if (rc) {
658 if (rc == -1) {
659 depth = 0;
660 }
661 goto fail;
662 }
663 session->username = lydict_insert_zc(server_opts.ctx, cp);
664 }
665
666 VRB("Cert verify CTN: new client username recognized as \"%s\".", session->username);
Michal Vasko7060bcf2016-11-28 14:48:11 +0100667
668 if (server_opts.user_verify_clb && !server_opts.user_verify_clb(session)) {
669 VRB("Cert verify: user verify callback revoked authorization.");
670 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
671 return 0;
672 }
673
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100674 return 1;
675
676fail:
677 if (depth > 0) {
678 VRB("Cert verify CTN: cert fail, cert-to-name will continue on the next cert in chain.");
679 return 1;
680 }
681
682 VRB("Cert-to-name unsuccessful, dropping the new client.");
683 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
684 return 0;
685}
686
Michal Vasko3031aae2016-01-27 16:07:18 +0100687static int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100688nc_server_tls_set_server_cert(const char *name, struct nc_server_tls_opts *opts)
Michal Vasko3031aae2016-01-27 16:07:18 +0100689{
Michal Vasko4c1fb492017-01-30 14:31:07 +0100690 if (!name) {
Michal Vaskoa8748792016-11-22 14:34:26 +0100691 if (opts->server_cert) {
Michal Vasko4c1fb492017-01-30 14:31:07 +0100692 lydict_remove(server_opts.ctx, opts->server_cert);
Michal Vaskoa8748792016-11-22 14:34:26 +0100693 }
694 opts->server_cert = NULL;
695 return 0;
696 }
697
Michal Vaskoe2713da2016-08-22 16:06:40 +0200698 if (opts->server_cert) {
Michal Vasko4c1fb492017-01-30 14:31:07 +0100699 lydict_remove(server_opts.ctx, opts->server_cert);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100700 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100701 opts->server_cert = lydict_insert(server_opts.ctx, name, 0);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100702
703 return 0;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100704}
705
706API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100707nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100708{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100709 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100710 struct nc_endpt *endpt;
711
Michal Vasko2e6defd2016-10-07 15:48:15 +0200712 if (!endpt_name) {
713 ERRARG("endpt_name");
714 return -1;
715 }
716
Michal Vasko51e514d2016-02-02 15:51:52 +0100717 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +0200718 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100719 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100720 return -1;
721 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100722 ret = nc_server_tls_set_server_cert(name, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +0100723 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100724 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100725
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100726 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100727}
728
729API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100730nc_server_tls_ch_client_set_server_cert(const char *client_name, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100731{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100732 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +0200733 struct nc_ch_client *client;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100734
Michal Vasko2e6defd2016-10-07 15:48:15 +0200735 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +0100736 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +0200737 return -1;
738 }
739
740 /* LOCK */
741 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
742 if (!client) {
743 return -1;
744 }
745
Michal Vasko4c1fb492017-01-30 14:31:07 +0100746 ret = nc_server_tls_set_server_cert(name, client->opts.tls);
Michal Vasko2e6defd2016-10-07 15:48:15 +0200747
748 /* UNLOCK */
749 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100750
751 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100752}
753
Michal Vasko4c1fb492017-01-30 14:31:07 +0100754API void
755nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data,
756 char **privkey_path, char **privkey_data, int *privkey_data_rsa),
757 void *user_data, void (*free_user_data)(void *user_data))
Michal Vaskoc61c4492016-01-25 11:13:34 +0100758{
Michal Vasko4c1fb492017-01-30 14:31:07 +0100759 if (!cert_clb) {
760 ERRARG("cert_clb");
761 return;
Michal Vaskoa8748792016-11-22 14:34:26 +0100762 }
763
Michal Vasko4c1fb492017-01-30 14:31:07 +0100764 server_opts.server_cert_clb = cert_clb;
765 server_opts.server_cert_data = user_data;
766 server_opts.server_cert_data_free = free_user_data;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100767}
768
769static int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100770nc_server_tls_add_trusted_cert_list(const char *name, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100771{
Michal Vasko4c1fb492017-01-30 14:31:07 +0100772 if (!name) {
773 ERRARG("name");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100774 return -1;
775 }
776
Michal Vasko4c1fb492017-01-30 14:31:07 +0100777 ++opts->trusted_cert_list_count;
778 opts->trusted_cert_lists = nc_realloc(opts->trusted_cert_lists, opts->trusted_cert_list_count * sizeof *opts->trusted_cert_lists);
779 if (!opts->trusted_cert_lists) {
Michal Vaskoe2713da2016-08-22 16:06:40 +0200780 ERRMEM;
Michal Vaskoe2713da2016-08-22 16:06:40 +0200781 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100782 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100783 opts->trusted_cert_lists[opts->trusted_cert_list_count - 1] = lydict_insert(server_opts.ctx, name, 0);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100784
785 return 0;
786}
787
788API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100789nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100790{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100791 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100792 struct nc_endpt *endpt;
793
Michal Vasko2e6defd2016-10-07 15:48:15 +0200794 if (!endpt_name) {
795 ERRARG("endpt_name");
796 return -1;
797 }
798
Michal Vasko51e514d2016-02-02 15:51:52 +0100799 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +0200800 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100801 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100802 return -1;
803 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100804 ret = nc_server_tls_add_trusted_cert_list(name, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +0100805 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100806 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100807
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100808 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100809}
810
811API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100812nc_server_tls_ch_client_add_trusted_cert_list(const char *client_name, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100813{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100814 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +0200815 struct nc_ch_client *client;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100816
Michal Vasko2e6defd2016-10-07 15:48:15 +0200817 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +0100818 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +0200819 return -1;
820 }
821
822 /* LOCK */
823 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
824 if (!client) {
825 return -1;
826 }
827
Michal Vasko4c1fb492017-01-30 14:31:07 +0100828 ret = nc_server_tls_add_trusted_cert_list(name, client->opts.tls);
Michal Vasko2e6defd2016-10-07 15:48:15 +0200829
830 /* UNLOCK */
831 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100832
833 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100834}
835
Michal Vasko4c1fb492017-01-30 14:31:07 +0100836API void
837nc_server_tls_set_trusted_cert_list_clb(int (*cert_list_clb)(const char *name, void *user_data, char ***cert_paths,
838 int *cert_path_count, char ***cert_data, int *cert_data_count),
839 void *user_data, void (*free_user_data)(void *user_data))
Michal Vaskoc61c4492016-01-25 11:13:34 +0100840{
Michal Vasko4c1fb492017-01-30 14:31:07 +0100841 if (!cert_list_clb) {
842 ERRARG("cert_list_clb");
843 return;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100844 }
845
Michal Vasko4c1fb492017-01-30 14:31:07 +0100846 server_opts.trusted_cert_list_clb = cert_list_clb;
847 server_opts.trusted_cert_list_data = user_data;
848 server_opts.trusted_cert_list_data_free = free_user_data;
Michal Vaskoe2713da2016-08-22 16:06:40 +0200849}
850
851static int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100852nc_server_tls_del_trusted_cert_list(const char *name, struct nc_server_tls_opts *opts)
Michal Vaskoe2713da2016-08-22 16:06:40 +0200853{
854 uint16_t i;
855
856 if (!name) {
Michal Vasko4c1fb492017-01-30 14:31:07 +0100857 for (i = 0; i < opts->trusted_cert_list_count; ++i) {
858 lydict_remove(server_opts.ctx, opts->trusted_cert_lists[i]);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200859 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100860 free(opts->trusted_cert_lists);
861 opts->trusted_cert_lists = NULL;
862 opts->trusted_cert_list_count = 0;
Michal Vaskoe2713da2016-08-22 16:06:40 +0200863 return 0;
864 } else {
Michal Vasko4c1fb492017-01-30 14:31:07 +0100865 for (i = 0; i < opts->trusted_cert_list_count; ++i) {
866 if (!strcmp(opts->trusted_cert_lists[i], name)) {
867 lydict_remove(server_opts.ctx, opts->trusted_cert_lists[i]);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200868
Michal Vasko4c1fb492017-01-30 14:31:07 +0100869 --opts->trusted_cert_list_count;
870 if (i < opts->trusted_cert_list_count - 1) {
871 memmove(opts->trusted_cert_lists + i, opts->trusted_cert_lists + i + 1,
872 (opts->trusted_cert_list_count - i) * sizeof *opts->trusted_cert_lists);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200873 }
874 return 0;
875 }
876 }
877 }
878
Michal Vasko4c1fb492017-01-30 14:31:07 +0100879 ERR("Certificate list \"%s\" not found.", name);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200880 return -1;
881}
882
883API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100884nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *name)
Michal Vaskoe2713da2016-08-22 16:06:40 +0200885{
886 int ret;
887 struct nc_endpt *endpt;
888
Michal Vasko2e6defd2016-10-07 15:48:15 +0200889 if (!endpt_name) {
890 ERRARG("endpt_name");
891 return -1;
892 }
893
Michal Vaskoe2713da2016-08-22 16:06:40 +0200894 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +0200895 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200896 if (!endpt) {
897 return -1;
898 }
Michal Vasko4c1fb492017-01-30 14:31:07 +0100899 ret = nc_server_tls_del_trusted_cert_list(name, endpt->opts.tls);
Michal Vaskoe2713da2016-08-22 16:06:40 +0200900 /* UNLOCK */
901 nc_server_endpt_unlock(endpt);
902
903 return ret;
904}
905
906API int
Michal Vasko4c1fb492017-01-30 14:31:07 +0100907nc_server_tls_ch_client_del_trusted_cert_list(const char *client_name, const char *name)
Michal Vaskoe2713da2016-08-22 16:06:40 +0200908{
909 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +0200910 struct nc_ch_client *client;
Michal Vaskoe2713da2016-08-22 16:06:40 +0200911
Michal Vasko2e6defd2016-10-07 15:48:15 +0200912 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +0100913 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +0200914 return -1;
915 }
916
917 /* LOCK */
918 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
919 if (!client) {
920 return -1;
921 }
922
Michal Vasko4c1fb492017-01-30 14:31:07 +0100923 ret = nc_server_tls_del_trusted_cert_list(name, client->opts.tls);
Michal Vasko2e6defd2016-10-07 15:48:15 +0200924
925 /* UNLOCK */
926 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100927
928 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100929}
930
931static int
Michal Vasko96830e32016-02-01 10:54:18 +0100932nc_server_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100933{
Michal Vasko96830e32016-02-01 10:54:18 +0100934 if (!ca_file && !ca_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200935 ERRARG("ca_file and ca_dir");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100936 return -1;
937 }
938
Michal Vasko96830e32016-02-01 10:54:18 +0100939 if (ca_file) {
Michal Vaskoe2713da2016-08-22 16:06:40 +0200940 if (opts->trusted_ca_file) {
941 lydict_remove(server_opts.ctx, opts->trusted_ca_file);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100942 }
Michal Vaskoe2713da2016-08-22 16:06:40 +0200943 opts->trusted_ca_file = lydict_insert(server_opts.ctx, ca_file, 0);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100944 }
945
Michal Vasko96830e32016-02-01 10:54:18 +0100946 if (ca_dir) {
Michal Vaskoe2713da2016-08-22 16:06:40 +0200947 if (opts->trusted_ca_dir) {
948 lydict_remove(server_opts.ctx, opts->trusted_ca_dir);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100949 }
Michal Vaskoe2713da2016-08-22 16:06:40 +0200950 opts->trusted_ca_dir = lydict_insert(server_opts.ctx, ca_dir, 0);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100951 }
952
953 return 0;
Michal Vasko086311b2016-01-08 09:53:11 +0100954}
955
Michal Vaskoc61c4492016-01-25 11:13:34 +0100956API int
Michal Vasko96830e32016-02-01 10:54:18 +0100957nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_file, const char *ca_dir)
Michal Vasko086311b2016-01-08 09:53:11 +0100958{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100959 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100960 struct nc_endpt *endpt;
961
Michal Vasko2e6defd2016-10-07 15:48:15 +0200962 if (!endpt_name) {
963 ERRARG("endpt_name");
964 return -1;
965 }
966
Michal Vasko51e514d2016-02-02 15:51:52 +0100967 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +0200968 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100969 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100970 return -1;
971 }
Michal Vasko2e6defd2016-10-07 15:48:15 +0200972 ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +0100973 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100974 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100975
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100976 return ret;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100977}
978
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100979API int
Michal Vasko2e6defd2016-10-07 15:48:15 +0200980nc_server_tls_ch_client_set_trusted_ca_paths(const char *client_name, const char *ca_file, const char *ca_dir)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100981{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100982 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +0200983 struct nc_ch_client *client;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100984
Michal Vasko2e6defd2016-10-07 15:48:15 +0200985 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +0100986 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +0200987 return -1;
988 }
989
990 /* LOCK */
991 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
992 if (!client) {
993 return -1;
994 }
995
996 ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, client->opts.tls);
997
998 /* UNLOCK */
999 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001000
1001 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001002}
1003
Michal Vaskoc61c4492016-01-25 11:13:34 +01001004static int
Michal Vasko96830e32016-02-01 10:54:18 +01001005nc_server_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001006{
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001007 X509_LOOKUP *lookup;
1008
Michal Vasko96830e32016-02-01 10:54:18 +01001009 if (!crl_file && !crl_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +02001010 ERRARG("crl_file and crl_dir");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001011 return -1;
1012 }
1013
Michal Vaskoc61c4492016-01-25 11:13:34 +01001014 if (!opts->crl_store) {
1015 opts->crl_store = X509_STORE_new();
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001016 }
1017
Michal Vasko96830e32016-02-01 10:54:18 +01001018 if (crl_file) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001019 lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001020 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001021 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001022 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001023 }
1024
Michal Vasko96830e32016-02-01 10:54:18 +01001025 if (X509_LOOKUP_load_file(lookup, crl_file, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001026 ERR("Failed to add a revocation lookup file (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001027 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001028 }
1029 }
1030
Michal Vasko96830e32016-02-01 10:54:18 +01001031 if (crl_dir) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001032 lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001033 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001034 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001035 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001036 }
1037
Michal Vasko96830e32016-02-01 10:54:18 +01001038 if (X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001039 ERR("Failed to add a revocation lookup directory (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001040 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001041 }
1042 }
1043
1044 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +01001045
1046fail:
Michal Vaskob48aa812016-01-18 14:13:09 +01001047 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001048}
1049
Michal Vaskoc61c4492016-01-25 11:13:34 +01001050API int
Michal Vasko96830e32016-02-01 10:54:18 +01001051nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, const char *crl_dir)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001052{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001053 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001054 struct nc_endpt *endpt;
1055
Michal Vasko2e6defd2016-10-07 15:48:15 +02001056 if (!endpt_name) {
1057 ERRARG("endpt_name");
1058 return -1;
1059 }
1060
Michal Vasko51e514d2016-02-02 15:51:52 +01001061 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +02001062 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001063 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001064 return -1;
1065 }
Michal Vasko2e6defd2016-10-07 15:48:15 +02001066 ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +01001067 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001068 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001069
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001070 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001071}
1072
1073API int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001074nc_server_tls_ch_client_set_crl_paths(const char *client_name, const char *crl_file, const char *crl_dir)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001075{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001076 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +02001077 struct nc_ch_client *client;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001078
Michal Vasko2e6defd2016-10-07 15:48:15 +02001079 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +01001080 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +02001081 return -1;
1082 }
1083
1084 /* LOCK */
1085 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
1086 if (!client) {
1087 return -1;
1088 }
1089
1090 ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, client->opts.tls);
1091
1092 /* UNLOCK */
1093 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001094
1095 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001096}
1097
1098static void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001099nc_server_tls_clear_crls(struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001100{
Michal Vaskoc61c4492016-01-25 11:13:34 +01001101 if (!opts->crl_store) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001102 return;
1103 }
1104
1105 X509_STORE_free(opts->crl_store);
1106 opts->crl_store = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001107}
1108
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001109API void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001110nc_server_tls_endpt_clear_crls(const char *endpt_name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001111{
Michal Vasko3031aae2016-01-27 16:07:18 +01001112 struct nc_endpt *endpt;
1113
Michal Vasko2e6defd2016-10-07 15:48:15 +02001114 if (!endpt_name) {
1115 ERRARG("endpt_name");
1116 return;
1117 }
1118
Michal Vasko51e514d2016-02-02 15:51:52 +01001119 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +02001120 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001121 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001122 return;
1123 }
Michal Vasko2e6defd2016-10-07 15:48:15 +02001124 nc_server_tls_clear_crls(endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +01001125 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001126 nc_server_endpt_unlock(endpt);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001127}
1128
Michal Vaskoc61c4492016-01-25 11:13:34 +01001129API void
Michal Vasko2e6defd2016-10-07 15:48:15 +02001130nc_server_tls_ch_client_clear_crls(const char *client_name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001131{
Michal Vasko2e6defd2016-10-07 15:48:15 +02001132 struct nc_ch_client *client;
1133
1134 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +01001135 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +02001136 return;
1137 }
1138
1139 /* LOCK */
1140 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
1141 if (!client) {
1142 return;
1143 }
1144
1145 nc_server_tls_clear_crls(client->opts.tls);
1146
1147 /* UNLOCK */
1148 nc_server_ch_client_unlock(client);
Michal Vaskoc61c4492016-01-25 11:13:34 +01001149}
1150
1151static int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001152nc_server_tls_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name,
1153 struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001154{
Michal Vasko5e3f3392016-01-20 11:13:01 +01001155 struct nc_ctn *ctn, *new;
1156
Michal Vaskoc61c4492016-01-25 11:13:34 +01001157 if (!opts->ctn) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001158 /* the first item */
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001159 opts->ctn = new = calloc(1, sizeof *new);
1160 if (!new) {
1161 ERRMEM;
1162 return -1;
1163 }
Michal Vaskoc61c4492016-01-25 11:13:34 +01001164 } else if (opts->ctn->id > id) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001165 /* insert at the beginning */
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001166 new = calloc(1, sizeof *new);
1167 if (!new) {
1168 ERRMEM;
1169 return -1;
1170 }
Michal Vaskoc61c4492016-01-25 11:13:34 +01001171 new->next = opts->ctn;
1172 opts->ctn = new;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001173 } else {
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001174 for (ctn = opts->ctn; ctn->next && ctn->next->id < id; ctn = ctn->next);
Michal Vasko276f9d92017-02-02 11:15:55 +01001175 if (ctn->id == id) {
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001176 /* it exists already */
Michal Vasko276f9d92017-02-02 11:15:55 +01001177 new = ctn;
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001178 } else {
1179 /* insert after ctn */
1180 new = calloc(1, sizeof *new);
1181 if (!new) {
1182 ERRMEM;
1183 return -1;
1184 }
1185 new->next = ctn->next;
1186 ctn->next = new;
1187 }
1188 }
1189
1190 new->id = id;
1191 if (fingerprint) {
1192 if (new->fingerprint) {
1193 lydict_remove(server_opts.ctx, new->fingerprint);
1194 }
1195 new->fingerprint = lydict_insert(server_opts.ctx, fingerprint, 0);
1196 }
1197 if (map_type) {
1198 new->map_type = map_type;
1199 }
1200 if (name) {
1201 if (new->name) {
1202 lydict_remove(server_opts.ctx, new->name);
1203 }
1204 new->name = lydict_insert(server_opts.ctx, name, 0);
Michal Vasko5e3f3392016-01-20 11:13:01 +01001205 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001206
1207 return 0;
1208}
1209
1210API int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001211nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type,
1212 const char *name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001213{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001214 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001215 struct nc_endpt *endpt;
1216
Michal Vasko2e6defd2016-10-07 15:48:15 +02001217 if (!endpt_name) {
1218 ERRARG("endpt_name");
1219 return -1;
1220 }
1221
Michal Vasko51e514d2016-02-02 15:51:52 +01001222 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +02001223 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001224 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001225 return -1;
1226 }
Michal Vasko2e6defd2016-10-07 15:48:15 +02001227 ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +01001228 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001229 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001230
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001231 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001232}
1233
1234API int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001235nc_server_tls_ch_client_add_ctn(const char *client_name, uint32_t id, const char *fingerprint,
1236 NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001237{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001238 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +02001239 struct nc_ch_client *client;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001240
Michal Vasko2e6defd2016-10-07 15:48:15 +02001241 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +01001242 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +02001243 return -1;
1244 }
1245
1246 /* LOCK */
1247 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
1248 if (!client) {
1249 return -1;
1250 }
1251
1252 ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, client->opts.tls);
1253
1254 /* UNLOCK */
1255 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001256
1257 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001258}
1259
1260static int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001261nc_server_tls_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name,
1262 struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001263{
Michal Vasko5e3f3392016-01-20 11:13:01 +01001264 struct nc_ctn *ctn, *next, *prev;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001265 int ret = -1;
1266
Michal Vasko1a38c862016-01-15 15:50:07 +01001267 if ((id < 0) && !fingerprint && !map_type && !name) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001268 ctn = opts->ctn;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001269 while (ctn) {
1270 lydict_remove(server_opts.ctx, ctn->fingerprint);
1271 lydict_remove(server_opts.ctx, ctn->name);
1272
1273 next = ctn->next;
1274 free(ctn);
1275 ctn = next;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001276
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001277 ret = 0;
1278 }
Michal Vasko3031aae2016-01-27 16:07:18 +01001279 opts->ctn = NULL;
Michal Vasko1a38c862016-01-15 15:50:07 +01001280 } else {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001281 prev = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001282 ctn = opts->ctn;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001283 while (ctn) {
1284 if (((id < 0) || (ctn->id == id))
1285 && (!fingerprint || !strcmp(ctn->fingerprint, fingerprint))
1286 && (!map_type || (ctn->map_type == map_type))
1287 && (!name || (ctn->name && !strcmp(ctn->name, name)))) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001288 lydict_remove(server_opts.ctx, ctn->fingerprint);
1289 lydict_remove(server_opts.ctx, ctn->name);
Michal Vasko1a38c862016-01-15 15:50:07 +01001290
Michal Vasko5e3f3392016-01-20 11:13:01 +01001291 if (prev) {
1292 prev->next = ctn->next;
1293 next = ctn->next;
1294 } else {
Michal Vasko3031aae2016-01-27 16:07:18 +01001295 opts->ctn = ctn->next;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001296 next = ctn->next;
1297 }
1298 free(ctn);
1299 ctn = next;
Michal Vasko1a38c862016-01-15 15:50:07 +01001300
1301 ret = 0;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001302 } else {
1303 prev = ctn;
1304 ctn = ctn->next;
Michal Vasko1a38c862016-01-15 15:50:07 +01001305 }
1306 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001307 }
1308
1309 return ret;
1310}
1311
Michal Vaskoc61c4492016-01-25 11:13:34 +01001312API int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001313nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type,
1314 const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001315{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001316 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001317 struct nc_endpt *endpt;
1318
Michal Vasko2e6defd2016-10-07 15:48:15 +02001319 if (!endpt_name) {
1320 ERRARG("endpt_name");
1321 return -1;
1322 }
1323
Michal Vasko51e514d2016-02-02 15:51:52 +01001324 /* LOCK */
Michal Vasko2e6defd2016-10-07 15:48:15 +02001325 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001326 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001327 return -1;
1328 }
Michal Vasko2e6defd2016-10-07 15:48:15 +02001329 ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->opts.tls);
Michal Vasko51e514d2016-02-02 15:51:52 +01001330 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001331 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001332
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001333 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001334}
1335
1336API int
Michal Vasko2e6defd2016-10-07 15:48:15 +02001337nc_server_tls_ch_client_del_ctn(const char *client_name, int64_t id, const char *fingerprint,
1338 NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001339{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001340 int ret;
Michal Vasko2e6defd2016-10-07 15:48:15 +02001341 struct nc_ch_client *client;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001342
Michal Vasko2e6defd2016-10-07 15:48:15 +02001343 if (!client_name) {
Michal Vasko9bf49542016-11-23 13:50:15 +01001344 ERRARG("client_name");
Michal Vasko2e6defd2016-10-07 15:48:15 +02001345 return -1;
1346 }
1347
1348 /* LOCK */
1349 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
1350 if (!client) {
1351 return -1;
1352 }
1353
1354 ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, client->opts.tls);
1355
1356 /* UNLOCK */
1357 nc_server_ch_client_unlock(client);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001358
1359 return ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001360}
Michal Vaskoc61c4492016-01-25 11:13:34 +01001361
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001362static int
Michal Vaskof585ac72016-11-25 15:16:38 +01001363nc_server_tls_get_ctn(uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, char **name,
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001364 struct nc_server_tls_opts *opts)
1365{
1366 struct nc_ctn *ctn;
1367 int ret = -1;
1368
1369 for (ctn = opts->ctn; ctn; ctn = ctn->next) {
1370 if (id && *id && (*id != ctn->id)) {
1371 continue;
1372 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001373 if (fingerprint && *fingerprint && (!ctn->fingerprint || strcmp(*fingerprint, ctn->fingerprint))) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001374 continue;
1375 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001376 if (map_type && *map_type && (!ctn->map_type || (*map_type != ctn->map_type))) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001377 continue;
1378 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001379 if (name && *name && (!ctn->name || strcmp(*name, ctn->name))) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001380 continue;
1381 }
1382
1383 /* first match, good enough */
1384 if (id && !(*id)) {
1385 *id = ctn->id;
1386 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001387 if (fingerprint && !(*fingerprint) && ctn->fingerprint) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001388 *fingerprint = strdup(ctn->fingerprint);
1389 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001390 if (map_type && !(*map_type) && ctn->map_type) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001391 *map_type = ctn->map_type;
1392 }
Michal Vasko3cf4aaa2017-02-01 15:03:36 +01001393 if (name && !(*name) && ctn->name && ctn->name) {
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001394 *name = strdup(ctn->name);
1395 }
1396
1397 ret = 0;
1398 break;
1399 }
1400
1401 return ret;
1402}
1403
1404API int
Michal Vaskof585ac72016-11-25 15:16:38 +01001405nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type,
1406 char **name)
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001407{
1408 int ret;
1409 struct nc_endpt *endpt;
1410
1411 if (!endpt_name) {
1412 ERRARG("endpt_name");
1413 return -1;
1414 }
1415
1416 /* LOCK */
1417 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL, NULL);
1418 if (!endpt) {
1419 return -1;
1420 }
1421 ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls);
1422 /* UNLOCK */
1423 nc_server_endpt_unlock(endpt);
1424
1425 return ret;
1426}
1427
1428API int
Michal Vaskof585ac72016-11-25 15:16:38 +01001429nc_server_tls_ch_client_get_ctn(const char *client_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type,
1430 char **name)
Michal Vaskodf5e6af2016-11-23 13:50:56 +01001431{
1432 int ret;
1433 struct nc_ch_client *client;
1434
1435 if (!client_name) {
1436 ERRARG("client_name");
1437 return -1;
1438 }
1439
1440 /* LOCK */
1441 client = nc_server_ch_client_lock(client_name, NC_TI_OPENSSL, NULL);
1442 if (!client) {
1443 return -1;
1444 }
1445
1446 ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, client->opts.tls);
1447
1448 /* UNLOCK */
1449 nc_server_ch_client_unlock(client);
1450
1451 return ret;
1452}
1453
Michal Vasko709598e2016-11-28 14:48:32 +01001454API const X509 *
1455nc_session_get_client_cert(const struct nc_session *session)
1456{
1457 if (!session || (session->side != NC_SERVER)) {
1458 ERRARG("session");
1459 return NULL;
1460 }
1461
1462 return session->opts.server.client_cert;
1463}
1464
Michal Vasko7060bcf2016-11-28 14:48:11 +01001465API void
1466nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session))
1467{
1468 server_opts.user_verify_clb = verify_clb;
1469}
1470
Michal Vasko3031aae2016-01-27 16:07:18 +01001471void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001472nc_server_tls_clear_opts(struct nc_server_tls_opts *opts)
Michal Vasko3031aae2016-01-27 16:07:18 +01001473{
Michal Vasko4c1fb492017-01-30 14:31:07 +01001474 lydict_remove(server_opts.ctx, opts->server_cert);
1475 nc_server_tls_del_trusted_cert_list(NULL, opts);
Michal Vaskoe2713da2016-08-22 16:06:40 +02001476 lydict_remove(server_opts.ctx, opts->trusted_ca_file);
1477 lydict_remove(server_opts.ctx, opts->trusted_ca_dir);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001478 nc_server_tls_clear_crls(opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001479 nc_server_tls_del_ctn(-1, NULL, 0, NULL, opts);
Michal Vasko086311b2016-01-08 09:53:11 +01001480}
Michal Vasko9e036d52016-01-08 10:49:26 +01001481
Michal Vasko6d292992016-01-18 09:42:38 +01001482static void
1483nc_tls_make_verify_key(void)
1484{
Michal Vasko5c2f7952016-01-22 13:16:31 +01001485 pthread_key_create(&verify_key, NULL);
Michal Vasko6d292992016-01-18 09:42:38 +01001486}
1487
Michal Vasko4c1fb492017-01-30 14:31:07 +01001488static int
1489nc_tls_ctx_set_server_cert_key(SSL_CTX *tls_ctx, const char *cert_name)
1490{
1491 char *cert_path = NULL, *cert_data = NULL, *privkey_path = NULL, *privkey_data = NULL;
1492 int privkey_data_rsa = 1, ret = 0;
Michal Vasko6e08cb72017-02-02 11:15:29 +01001493 X509 *cert = NULL;
1494 EVP_PKEY *pkey = NULL;
Michal Vasko4c1fb492017-01-30 14:31:07 +01001495
1496 if (!cert_name) {
1497 ERR("Server certificate not set.");
1498 return -1;
1499 } else if (!server_opts.server_cert_clb) {
1500 ERR("Callback for retrieving the server certificate is not set.");
1501 return -1;
1502 }
1503
1504 if (server_opts.server_cert_clb(cert_name, server_opts.server_cert_data, &cert_path, &cert_data, &privkey_path,
1505 &privkey_data, &privkey_data_rsa)) {
1506 ERR("Server certificate callback failed.");
1507 return -1;
1508 }
1509
1510 /* load the certificate */
1511 if (cert_path) {
1512 if (SSL_CTX_use_certificate_file(tls_ctx, cert_path, SSL_FILETYPE_PEM) != 1) {
1513 ERR("Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1514 ret = -1;
1515 goto cleanup;
1516 }
1517 } else {
Michal Vasko6e08cb72017-02-02 11:15:29 +01001518 cert = base64der_to_cert(cert_data);
Michal Vasko4c1fb492017-01-30 14:31:07 +01001519 if (!cert || (SSL_CTX_use_certificate(tls_ctx, cert) != 1)) {
1520 ERR("Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1521 ret = -1;
1522 goto cleanup;
Michal Vasko4c1fb492017-01-30 14:31:07 +01001523 }
1524 }
1525
1526 /* load the private key */
1527 if (privkey_path) {
1528 if (SSL_CTX_use_PrivateKey_file(tls_ctx, privkey_path, SSL_FILETYPE_PEM) != 1) {
1529 ERR("Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1530 ret = -1;
1531 goto cleanup;
1532 }
1533 } else {
Michal Vasko6e08cb72017-02-02 11:15:29 +01001534 pkey = base64der_to_privatekey(privkey_data, privkey_data_rsa);
Michal Vasko4c1fb492017-01-30 14:31:07 +01001535 if (!pkey || (SSL_CTX_use_PrivateKey(tls_ctx, pkey) != 1)) {
1536 ERR("Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1537 ret = -1;
1538 goto cleanup;
Michal Vasko4c1fb492017-01-30 14:31:07 +01001539 }
1540 }
1541
1542cleanup:
Michal Vasko6e08cb72017-02-02 11:15:29 +01001543 X509_free(cert);
1544 EVP_PKEY_free(pkey);
Michal Vasko4c1fb492017-01-30 14:31:07 +01001545 free(cert_path);
1546 free(cert_data);
1547 free(privkey_path);
1548 free(privkey_data);
1549 return ret;
1550}
1551
1552static void
1553tls_store_add_trusted_cert(X509_STORE *cert_store, const char *cert_path, const char *cert_data)
1554{
1555 X509 *cert;
1556
1557 if (cert_path) {
1558 cert = pem_to_cert(cert_path);
1559 } else {
1560 cert = base64der_to_cert(cert_data);
1561 }
1562
1563 if (!cert) {
1564 if (cert_path) {
1565 ERR("Loading a trusted certificate (path \"%s\") failed (%s).", cert_path,
1566 ERR_reason_error_string(ERR_get_error()));
1567 } else {
1568 ERR("Loading a trusted certificate (data \"%s\") failed (%s).", cert_data,
1569 ERR_reason_error_string(ERR_get_error()));
1570 }
1571 return;
1572 }
1573
1574 /* add the trusted certificate */
1575 if (X509_STORE_add_cert(cert_store, cert) != 1) {
1576 ERR("Adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1577 X509_free(cert);
1578 return;
1579 }
1580 X509_free(cert);
1581}
1582
1583static int
1584nc_tls_store_set_trusted_certs(X509_STORE *cert_store, const char **trusted_cert_lists, uint16_t trusted_cert_list_count)
1585{
1586 uint16_t i;
1587 int j;
1588 char **cert_paths, **cert_data;
1589 int cert_path_count, cert_data_count;
1590
1591 if (!server_opts.trusted_cert_list_clb) {
1592 ERR("Callback for retrieving trusted certificate lists is not set.");
1593 return -1;
1594 }
1595
1596 for (i = 0; i < trusted_cert_list_count; ++i) {
1597 cert_paths = cert_data = NULL;
1598 cert_path_count = cert_data_count = 0;
1599 if (server_opts.trusted_cert_list_clb(trusted_cert_lists[i], server_opts.trusted_cert_list_data,
1600 &cert_paths, &cert_path_count, &cert_data, &cert_data_count)) {
1601 ERR("Trusted certificate list callback for \"%s\" failed.", trusted_cert_lists[i]);
1602 return -1;
1603 }
1604
1605 for (j = 0; j < cert_path_count; ++j) {
1606 tls_store_add_trusted_cert(cert_store, cert_paths[j], NULL);
1607 free(cert_paths[j]);
1608 }
1609 free(cert_paths);
1610
1611 for (j = 0; j < cert_data_count; ++j) {
1612 tls_store_add_trusted_cert(cert_store, NULL, cert_data[j]);
1613 free(cert_data[j]);
1614 }
1615 free(cert_data);
1616 }
1617
1618 return 0;
1619}
1620
Michal Vasko3031aae2016-01-27 16:07:18 +01001621int
Michal Vasko0190bc32016-03-02 15:47:49 +01001622nc_accept_tls_session(struct nc_session *session, int sock, int timeout)
Michal Vasko3031aae2016-01-27 16:07:18 +01001623{
Michal Vaskoe2713da2016-08-22 16:06:40 +02001624 X509_STORE *cert_store;
1625 SSL_CTX *tls_ctx;
1626 X509_LOOKUP *lookup;
Michal Vasko3031aae2016-01-27 16:07:18 +01001627 struct nc_server_tls_opts *opts;
Michal Vasko0190bc32016-03-02 15:47:49 +01001628 int ret, elapsed_usec = 0;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001629
Michal Vasko2cc4c682016-03-01 09:16:48 +01001630 opts = session->data;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001631
Michal Vaskoe2713da2016-08-22 16:06:40 +02001632 /* SSL_CTX */
1633 tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
1634 if (!tls_ctx) {
1635 ERR("Failed to create TLS context.");
1636 goto error;
1637 }
1638 SSL_CTX_set_verify(tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vasko4c1fb492017-01-30 14:31:07 +01001639 if (nc_tls_ctx_set_server_cert_key(tls_ctx, opts->server_cert)) {
Michal Vaskoe2713da2016-08-22 16:06:40 +02001640 goto error;
1641 }
1642
1643 /* X509_STORE, managed (freed) with the context */
1644 cert_store = X509_STORE_new();
1645 SSL_CTX_set_cert_store(tls_ctx, cert_store);
1646
Michal Vasko4c1fb492017-01-30 14:31:07 +01001647 if (nc_tls_store_set_trusted_certs(cert_store, opts->trusted_cert_lists, opts->trusted_cert_list_count)) {
1648 goto error;
Michal Vaskoe2713da2016-08-22 16:06:40 +02001649 }
1650
1651 if (opts->trusted_ca_file) {
1652 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
1653 if (!lookup) {
1654 ERR("Failed to add a lookup method.");
1655 goto error;
1656 }
1657
1658 if (X509_LOOKUP_load_file(lookup, opts->trusted_ca_file, X509_FILETYPE_PEM) != 1) {
1659 ERR("Failed to add a trusted cert file (%s).", ERR_reason_error_string(ERR_get_error()));
1660 goto error;
1661 }
1662 }
1663
1664 if (opts->trusted_ca_dir) {
1665 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
1666 if (!lookup) {
1667 ERR("Failed to add a lookup method.");
1668 goto error;
1669 }
1670
1671 if (X509_LOOKUP_add_dir(lookup, opts->trusted_ca_dir, X509_FILETYPE_PEM) != 1) {
1672 ERR("Failed to add a trusted cert directory (%s).", ERR_reason_error_string(ERR_get_error()));
1673 goto error;
1674 }
1675 }
1676
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001677 session->ti_type = NC_TI_OPENSSL;
Michal Vaskoe2713da2016-08-22 16:06:40 +02001678 session->ti.tls = SSL_new(tls_ctx);
1679
Michal Vasko4c1fb492017-01-30 14:31:07 +01001680 /* context can be freed already, trusted certs must be freed manually */
Michal Vaskoe2713da2016-08-22 16:06:40 +02001681 SSL_CTX_free(tls_ctx);
1682 tls_ctx = NULL;
Michal Vasko7f1c78b2016-01-19 09:52:14 +01001683
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001684 if (!session->ti.tls) {
Michal Vaskod083db62016-01-19 10:31:29 +01001685 ERR("Failed to create TLS structure from context.");
Michal Vaskoe2713da2016-08-22 16:06:40 +02001686 goto error;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001687 }
1688
1689 SSL_set_fd(session->ti.tls, sock);
Michal Vaskoe2713da2016-08-22 16:06:40 +02001690 sock = -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001691 SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
1692
Michal Vasko6d292992016-01-18 09:42:38 +01001693 /* store session on per-thread basis */
Michal Vasko5c2f7952016-01-22 13:16:31 +01001694 pthread_once(&verify_once, nc_tls_make_verify_key);
1695 pthread_setspecific(verify_key, session);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001696
Michal Vasko0190bc32016-03-02 15:47:49 +01001697 while (((ret = SSL_accept(session->ti.tls)) == -1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
1698 usleep(NC_TIMEOUT_STEP);
1699 elapsed_usec += NC_TIMEOUT_STEP;
1700 if ((timeout > -1) && (elapsed_usec / 1000 >= timeout)) {
1701 ERR("SSL_accept timeout.");
1702 return 0;
1703 }
1704 }
Michal Vaskob48aa812016-01-18 14:13:09 +01001705
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001706 if (ret != 1) {
1707 switch (SSL_get_error(session->ti.tls, ret)) {
1708 case SSL_ERROR_SYSCALL:
Michal Vaskod083db62016-01-19 10:31:29 +01001709 ERR("SSL_accept failed (%s).", strerror(errno));
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001710 break;
1711 case SSL_ERROR_SSL:
Michal Vaskod083db62016-01-19 10:31:29 +01001712 ERR("SSL_accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001713 break;
1714 default:
Michal Vaskod083db62016-01-19 10:31:29 +01001715 ERR("SSL_accept failed.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001716 break;
1717 }
1718 return -1;
1719 }
1720
Michal Vasko1a38c862016-01-15 15:50:07 +01001721 return 1;
Michal Vaskoe2713da2016-08-22 16:06:40 +02001722
1723error:
1724 if (sock > -1) {
1725 close(sock);
1726 }
1727 SSL_CTX_free(tls_ctx);
1728 return -1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001729}