blob: cbcd3d529d6c322c2a45367895c63fb78fb06a48 [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>
25
Michal Vasko11d142a2016-01-19 15:58:24 +010026#include "session_server.h"
Michal Vaskoe22c6732016-01-29 11:03:02 +010027#include "session_server_ch.h"
28#include "libnetconf.h"
Radek Krejci5da708a2015-09-01 17:33:23 +020029
Michal Vasko3031aae2016-01-27 16:07:18 +010030struct nc_server_tls_opts tls_ch_opts;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010031pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER;
Michal Vaskoc14e3c82016-01-11 16:14:30 +010032extern struct nc_server_opts server_opts;
Michal Vaskoc61c4492016-01-25 11:13:34 +010033
Michal Vasko5c2f7952016-01-22 13:16:31 +010034static pthread_key_t verify_key;
35static pthread_once_t verify_once = PTHREAD_ONCE_INIT;
36
Michal Vaskoc14e3c82016-01-11 16:14:30 +010037static char *
38asn1time_to_str(ASN1_TIME *t)
Michal Vasko086311b2016-01-08 09:53:11 +010039{
Michal Vaskoc14e3c82016-01-11 16:14:30 +010040 char *cp;
41 BIO *bio;
42 int n;
Radek Krejci5da708a2015-09-01 17:33:23 +020043
Michal Vaskoc14e3c82016-01-11 16:14:30 +010044 if (!t) {
45 return NULL;
46 }
47 bio = BIO_new(BIO_s_mem());
48 if (!bio) {
49 return NULL;
50 }
51 ASN1_TIME_print(bio, t);
52 n = BIO_pending(bio);
53 cp = malloc(n + 1);
Michal Vasko4eb3c312016-03-01 14:09:37 +010054 if (!cp) {
55 ERRMEM;
56 BIO_free(bio);
57 return NULL;
58 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +010059 n = BIO_read(bio, cp, n);
60 if (n < 0) {
61 BIO_free(bio);
62 free(cp);
63 return NULL;
64 }
65 cp[n] = '\0';
66 BIO_free(bio);
67 return cp;
68}
69
70static void
71digest_to_str(const unsigned char *digest, unsigned int dig_len, char **str)
72{
73 unsigned int i;
74
75 *str = malloc(dig_len * 3);
Michal Vasko4eb3c312016-03-01 14:09:37 +010076 if (!*str) {
77 ERRMEM;
78 return;
79 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +010080 for (i = 0; i < dig_len - 1; ++i) {
81 sprintf((*str) + (i * 3), "%02x:", digest[i]);
82 }
83 sprintf((*str) + (i * 3), "%02x", digest[i]);
84}
85
86/* return NULL - SSL error can be retrieved */
87static X509 *
88base64der_to_cert(const char *in)
89{
90 X509 *out;
91 char *buf;
92 BIO *bio;
93
94 if (in == NULL) {
95 return NULL;
96 }
97
98 if (asprintf(&buf, "%s%s%s", "-----BEGIN CERTIFICATE-----\n", in, "\n-----END CERTIFICATE-----") == -1) {
99 return NULL;
100 }
101 bio = BIO_new_mem_buf(buf, strlen(buf));
102 if (!bio) {
103 free(buf);
104 return NULL;
105 }
106
107 out = PEM_read_bio_X509(bio, NULL, NULL, NULL);
108 if (!out) {
109 free(buf);
110 BIO_free(bio);
111 return NULL;
112 }
113
114 free(buf);
115 BIO_free(bio);
116 return out;
117}
118
119/* return NULL - either errno or SSL error */
120static X509 *
121pem_to_cert(const char *path)
122{
123 FILE *fp;
124 X509 *out;
125
126 fp = fopen(path, "r");
127 if (!fp) {
128 return NULL;
129 }
130
131 out = PEM_read_X509(fp, NULL, NULL, NULL);
132 fclose(fp);
133 return out;
134}
135
136static EVP_PKEY *
137base64der_to_privatekey(const char *in, int rsa)
138{
139 EVP_PKEY *out;
140 char *buf;
141 BIO *bio;
142
143 if (in == NULL) {
144 return NULL;
145 }
146
147 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) {
148 return NULL;
149 }
150 bio = BIO_new_mem_buf(buf, strlen(buf));
151 if (!bio) {
152 free(buf);
153 return NULL;
154 }
155
156 out = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
157 if (!out) {
158 free(buf);
159 BIO_free(bio);
160 return NULL;
161 }
162
163 free(buf);
164 BIO_free(bio);
165 return out;
166}
167
168static int
169cert_pubkey_match(X509 *cert1, X509 *cert2)
170{
171 ASN1_BIT_STRING *bitstr1, *bitstr2;
172
173 bitstr1 = X509_get0_pubkey_bitstr(cert1);
174 bitstr2 = X509_get0_pubkey_bitstr(cert2);
175
176 if (!bitstr1 || !bitstr2 || (bitstr1->length != bitstr2->length) ||
177 memcmp(bitstr1->data, bitstr2->data, bitstr1->length)) {
178 return 0;
179 }
180
181 return 1;
182}
183
184static int
185nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type, char **username)
186{
187 STACK_OF(GENERAL_NAME) *san_names;
188 GENERAL_NAME *san_name;
189 ASN1_OCTET_STRING *ip;
190 int i, san_count;
191 char *subject, *common_name;
192
193 if (map_type == NC_TLS_CTN_COMMON_NAME) {
194 subject = X509_NAME_oneline(X509_get_subject_name(client_cert), NULL, 0);
195 common_name = strstr(subject, "CN=");
196 if (!common_name) {
Michal Vaskod083db62016-01-19 10:31:29 +0100197 WRN("Certificate does not include the commonName field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100198 free(subject);
199 return 1;
200 }
201 common_name += 3;
202 if (strchr(common_name, '/')) {
203 *strchr(common_name, '/') = '\0';
204 }
205 *username = strdup(common_name);
Michal Vasko4eb3c312016-03-01 14:09:37 +0100206 if (!*username) {
207 ERRMEM;
208 return 1;
209 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100210 free(subject);
211 } else {
212 /* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */
213 san_names = X509_get_ext_d2i(client_cert, NID_subject_alt_name, NULL, NULL);
214 if (!san_names) {
Michal Vaskod083db62016-01-19 10:31:29 +0100215 WRN("Certificate has no SANs or failed to retrieve them.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100216 return 1;
217 }
218
219 san_count = sk_GENERAL_NAME_num(san_names);
220 for (i = 0; i < san_count; ++i) {
221 san_name = sk_GENERAL_NAME_value(san_names, i);
222
223 /* rfc822Name (email) */
224 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_RFC822_NAME) &&
225 san_name->type == GEN_EMAIL) {
226 *username = strdup((char *)ASN1_STRING_data(san_name->d.rfc822Name));
Michal Vasko4eb3c312016-03-01 14:09:37 +0100227 if (!*username) {
228 ERRMEM;
229 return 1;
230 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100231 break;
232 }
233
234 /* dNSName */
235 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_DNS_NAME) &&
236 san_name->type == GEN_DNS) {
237 *username = strdup((char *)ASN1_STRING_data(san_name->d.dNSName));
Michal Vasko4eb3c312016-03-01 14:09:37 +0100238 if (!*username) {
239 ERRMEM;
240 return 1;
241 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100242 break;
243 }
244
245 /* iPAddress */
246 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_IP_ADDRESS) &&
247 san_name->type == GEN_IPADD) {
248 ip = san_name->d.iPAddress;
249 if (ip->length == 4) {
250 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 +0100251 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100252 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
253 return -1;
254 }
255 break;
256 } else if (ip->length == 16) {
257 if (asprintf(username, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
258 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
259 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
260 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100261 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100262 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
263 return -1;
264 }
265 break;
266 } else {
Michal Vaskod083db62016-01-19 10:31:29 +0100267 WRN("SAN IP address in an unknown format (length is %d).", ip->length);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100268 }
269 }
270 }
271 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
272
273 if (i < san_count) {
274 switch (map_type) {
275 case NC_TLS_CTN_SAN_RFC822_NAME:
Michal Vaskod083db62016-01-19 10:31:29 +0100276 WRN("Certificate does not include the SAN rfc822Name field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100277 break;
278 case NC_TLS_CTN_SAN_DNS_NAME:
Michal Vaskod083db62016-01-19 10:31:29 +0100279 WRN("Certificate does not include the SAN dNSName field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100280 break;
281 case NC_TLS_CTN_SAN_IP_ADDRESS:
Michal Vaskod083db62016-01-19 10:31:29 +0100282 WRN("Certificate does not include the SAN iPAddress field.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100283 break;
284 case NC_TLS_CTN_SAN_ANY:
Michal Vaskod083db62016-01-19 10:31:29 +0100285 WRN("Certificate does not include any relevant SAN fields.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100286 break;
287 default:
288 break;
289 }
290 return 1;
291 }
292 }
293
294 return 0;
295}
296
297/* return: 0 - OK, 1 - no match, -1 - error */
298static int
Michal Vaskoc61c4492016-01-25 11:13:34 +0100299nc_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 +0100300{
301 char *digest_md5 = NULL, *digest_sha1 = NULL, *digest_sha224 = NULL;
302 char *digest_sha256 = NULL, *digest_sha384 = NULL, *digest_sha512 = NULL;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100303 unsigned char *buf = malloc(64);
304 unsigned int buf_len = 64;
305 int ret = 0;
Michal Vasko5e3f3392016-01-20 11:13:01 +0100306 struct nc_ctn *ctn;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100307
Michal Vasko4eb3c312016-03-01 14:09:37 +0100308 if (!buf) {
309 ERRMEM;
310 return -1;
311 }
312
Michal Vaskoc61c4492016-01-25 11:13:34 +0100313 if (!ctn_first || !cert || !map_type || !name) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100314 free(buf);
315 return -1;
316 }
317
Michal Vaskoc61c4492016-01-25 11:13:34 +0100318 for (ctn = ctn_first; ctn; ctn = ctn->next) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100319 /* MD5 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100320 if (!strncmp(ctn->fingerprint, "01", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100321 if (!digest_md5) {
322 if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100323 ERR("Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100324 ret = -1;
325 goto cleanup;
326 }
327 digest_to_str(buf, buf_len, &digest_md5);
328 }
329
Michal Vasko5e3f3392016-01-20 11:13:01 +0100330 if (!strcasecmp(ctn->fingerprint + 3, digest_md5)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100331 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100332 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100333 *map_type = ctn->map_type;
334 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
335 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100336 }
337 break;
338 }
339
340 /* SHA-1 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100341 } else if (!strncmp(ctn->fingerprint, "02", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100342 if (!digest_sha1) {
343 if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100344 ERR("Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100345 ret = -1;
346 goto cleanup;
347 }
348 digest_to_str(buf, buf_len, &digest_sha1);
349 }
350
Michal Vasko5e3f3392016-01-20 11:13:01 +0100351 if (!strcasecmp(ctn->fingerprint + 3, digest_sha1)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100352 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100353 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100354 *map_type = ctn->map_type;
355 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
356 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100357 }
358 break;
359 }
360
361 /* SHA-224 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100362 } else if (!strncmp(ctn->fingerprint, "03", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100363 if (!digest_sha224) {
364 if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100365 ERR("Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100366 ret = -1;
367 goto cleanup;
368 }
369 digest_to_str(buf, buf_len, &digest_sha224);
370 }
371
Michal Vasko5e3f3392016-01-20 11:13:01 +0100372 if (!strcasecmp(ctn->fingerprint + 3, digest_sha224)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100373 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100374 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100375 *map_type = ctn->map_type;
376 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
377 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100378 }
379 break;
380 }
381
382 /* SHA-256 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100383 } else if (!strncmp(ctn->fingerprint, "04", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100384 if (!digest_sha256) {
385 if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100386 ERR("Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100387 ret = -1;
388 goto cleanup;
389 }
390 digest_to_str(buf, buf_len, &digest_sha256);
391 }
392
Michal Vasko5e3f3392016-01-20 11:13:01 +0100393 if (!strcasecmp(ctn->fingerprint + 3, digest_sha256)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100394 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100395 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100396 *map_type = ctn->map_type;
397 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
398 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100399 }
400 break;
401 }
402
403 /* SHA-384 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100404 } else if (!strncmp(ctn->fingerprint, "05", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100405 if (!digest_sha384) {
406 if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100407 ERR("Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100408 ret = -1;
409 goto cleanup;
410 }
411 digest_to_str(buf, buf_len, &digest_sha384);
412 }
413
Michal Vasko5e3f3392016-01-20 11:13:01 +0100414 if (!strcasecmp(ctn->fingerprint + 3, digest_sha384)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100415 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100416 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100417 *map_type = ctn->map_type;
418 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
419 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100420 }
421 break;
422 }
423
424 /* SHA-512 */
Michal Vasko5e3f3392016-01-20 11:13:01 +0100425 } else if (!strncmp(ctn->fingerprint, "06", 2)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100426 if (!digest_sha512) {
427 if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100428 ERR("Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100429 ret = -1;
430 goto cleanup;
431 }
432 digest_to_str(buf, buf_len, &digest_sha512);
433 }
434
Michal Vasko5e3f3392016-01-20 11:13:01 +0100435 if (!strcasecmp(ctn->fingerprint + 3, digest_sha512)) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100436 /* we got ourselves a winner! */
Michal Vaskod083db62016-01-19 10:31:29 +0100437 VRB("Cert verify CTN: entry with a matching fingerprint found.");
Michal Vasko5e3f3392016-01-20 11:13:01 +0100438 *map_type = ctn->map_type;
439 if (ctn->map_type == NC_TLS_CTN_SPECIFIED) {
440 *name = ctn->name;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100441 }
442 break;
443 }
444
445 /* unknown */
446 } else {
Michal Vasko5e3f3392016-01-20 11:13:01 +0100447 WRN("Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100448 }
449 }
450
Michal Vasko5e3f3392016-01-20 11:13:01 +0100451 if (!ctn) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100452 ret = 1;
453 }
454
455cleanup:
456 free(digest_md5);
457 free(digest_sha1);
458 free(digest_sha224);
459 free(digest_sha256);
460 free(digest_sha384);
461 free(digest_sha512);
462 free(buf);
463 return ret;
464}
465
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100466static int
467nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
468{
469 X509_STORE_CTX store_ctx;
470 X509_OBJECT obj;
471 X509_NAME *subject;
472 X509_NAME *issuer;
473 X509 *cert;
474 X509_CRL *crl;
475 X509_REVOKED *revoked;
476 STACK_OF(X509) *cert_stack;
477 EVP_PKEY *pubkey;
478 struct nc_session* session;
Michal Vasko3031aae2016-01-27 16:07:18 +0100479 struct nc_server_tls_opts *opts;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100480 long serial;
481 int i, n, rc, depth;
482 char *cp;
483 const char *username = NULL;
484 NC_TLS_CTN_MAPTYPE map_type = 0;
485 ASN1_TIME *last_update = NULL, *next_update = NULL;
486
Michal Vasko6d292992016-01-18 09:42:38 +0100487 /* get the thread session */
Michal Vasko5c2f7952016-01-22 13:16:31 +0100488 session = pthread_getspecific(verify_key);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100489 if (!session) {
490 ERRINT;
491 return 0;
492 }
493
Michal Vasko2cc4c682016-03-01 09:16:48 +0100494 opts = session->data;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100495
496 /* get the last certificate, that is the peer (client) certificate */
Michal Vasko06e22432016-01-15 10:30:06 +0100497 if (!session->tls_cert) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100498 cert_stack = X509_STORE_CTX_get1_chain(x509_ctx);
499 /* TODO all that is needed, but function X509_up_ref not present in older OpenSSL versions
500 session->cert = sk_X509_value(cert_stack, sk_X509_num(cert_stack) - 1);
501 X509_up_ref(session->cert);
502 sk_X509_pop_free(cert_stack, X509_free); */
503 while ((cert = sk_X509_pop(cert_stack))) {
Michal Vasko06e22432016-01-15 10:30:06 +0100504 X509_free(session->tls_cert);
505 session->tls_cert = cert;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100506 }
507 sk_X509_pop_free(cert_stack, X509_free);
508 }
509
510 /* standard certificate verification failed, so a trusted client cert must match to continue */
511 if (!preverify_ok) {
Michal Vasko06e22432016-01-15 10:30:06 +0100512 subject = X509_get_subject_name(session->tls_cert);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100513 cert_stack = X509_STORE_get1_certs(x509_ctx, subject);
514 if (cert_stack) {
515 for (i = 0; i < sk_X509_num(cert_stack); ++i) {
Michal Vasko06e22432016-01-15 10:30:06 +0100516 if (cert_pubkey_match(session->tls_cert, sk_X509_value(cert_stack, i))) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100517 /* we are just overriding the failed standard certificate verification (preverify_ok == 0),
518 * this callback will be called again with the same current certificate and preverify_ok == 1 */
Michal Vasko05ba9df2016-01-13 14:40:27 +0100519 VRB("Cert verify: fail (%s), but the client certificate is trusted, continuing.",
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100520 X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
521 X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
522 sk_X509_pop_free(cert_stack, X509_free);
523 return 1;
524 }
525 }
526 sk_X509_pop_free(cert_stack, X509_free);
527 }
528
529 ERR("Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
530 return 0;
531 }
532
533 /* print cert verify info */
534 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
Michal Vaskod083db62016-01-19 10:31:29 +0100535 VRB("Cert verify: depth %d.", depth);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100536
537 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
538 subject = X509_get_subject_name(cert);
539 issuer = X509_get_issuer_name(cert);
540
541 cp = X509_NAME_oneline(subject, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100542 VRB("Cert verify: subject: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100543 OPENSSL_free(cp);
544 cp = X509_NAME_oneline(issuer, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100545 VRB("Cert verify: issuer: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100546 OPENSSL_free(cp);
547
548 /* check for revocation if set */
Michal Vaskoc61c4492016-01-25 11:13:34 +0100549 if (opts->crl_store) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100550 /* try to retrieve a CRL corresponding to the _subject_ of
551 * the current certificate in order to verify it's integrity */
552 memset((char *)&obj, 0, sizeof(obj));
Michal Vaskoc61c4492016-01-25 11:13:34 +0100553 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100554 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
555 X509_STORE_CTX_cleanup(&store_ctx);
556 crl = obj.data.crl;
557 if (rc > 0 && crl) {
558 cp = X509_NAME_oneline(subject, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100559 VRB("Cert verify CRL: issuer: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100560 OPENSSL_free(cp);
561
562 last_update = X509_CRL_get_lastUpdate(crl);
563 next_update = X509_CRL_get_nextUpdate(crl);
564 cp = asn1time_to_str(last_update);
Michal Vaskod083db62016-01-19 10:31:29 +0100565 VRB("Cert verify CRL: last update: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100566 free(cp);
567 cp = asn1time_to_str(next_update);
Michal Vaskod083db62016-01-19 10:31:29 +0100568 VRB("Cert verify CRL: next update: %s.", cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100569 free(cp);
570
571 /* verify the signature on this CRL */
572 pubkey = X509_get_pubkey(cert);
573 if (X509_CRL_verify(crl, pubkey) <= 0) {
574 ERR("Cert verify CRL: invalid signature.");
575 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
576 X509_OBJECT_free_contents(&obj);
577 if (pubkey) {
578 EVP_PKEY_free(pubkey);
579 }
580 return 0;
581 }
582 if (pubkey) {
583 EVP_PKEY_free(pubkey);
584 }
585
586 /* check date of CRL to make sure it's not expired */
587 if (!next_update) {
588 ERR("Cert verify CRL: invalid nextUpdate field.");
589 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
590 X509_OBJECT_free_contents(&obj);
591 return 0;
592 }
593 if (X509_cmp_current_time(next_update) < 0) {
594 ERR("Cert verify CRL: expired - revoking all certificates.");
595 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
596 X509_OBJECT_free_contents(&obj);
597 return 0;
598 }
599 X509_OBJECT_free_contents(&obj);
600 }
601
602 /* try to retrieve a CRL corresponding to the _issuer_ of
Michal Vaskob48aa812016-01-18 14:13:09 +0100603 * the current certificate in order to check for revocation */
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100604 memset((char *)&obj, 0, sizeof(obj));
Michal Vaskoc61c4492016-01-25 11:13:34 +0100605 X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100606 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
607 X509_STORE_CTX_cleanup(&store_ctx);
608 crl = obj.data.crl;
609 if (rc > 0 && crl) {
610 /* check if the current certificate is revoked by this CRL */
611 n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
612 for (i = 0; i < n; i++) {
613 revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
614 if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
615 serial = ASN1_INTEGER_get(revoked->serialNumber);
616 cp = X509_NAME_oneline(issuer, NULL, 0);
Michal Vaskod083db62016-01-19 10:31:29 +0100617 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 +0100618 OPENSSL_free(cp);
619 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
620 X509_OBJECT_free_contents(&obj);
621 return 0;
622 }
623 }
624 X509_OBJECT_free_contents(&obj);
625 }
626 }
627
628 /* cert-to-name already successful */
629 if (session->username) {
630 return 1;
631 }
632
633 /* cert-to-name */
Michal Vaskoc61c4492016-01-25 11:13:34 +0100634 rc = nc_tls_cert_to_name(opts->ctn, cert, &map_type, &username);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100635
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100636 if (rc) {
637 if (rc == -1) {
638 /* fatal error */
639 depth = 0;
640 }
641 /* rc == 1 is a normal CTN fail (no match found) */
642 goto fail;
643 }
644
645 /* cert-to-name match, now to extract the specific field from the peer cert */
646 if (map_type == NC_TLS_CTN_SPECIFIED) {
647 session->username = lydict_insert(server_opts.ctx, username, 0);
648 } else {
Michal Vasko06e22432016-01-15 10:30:06 +0100649 rc = nc_tls_ctn_get_username_from_cert(session->tls_cert, map_type, &cp);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100650 if (rc) {
651 if (rc == -1) {
652 depth = 0;
653 }
654 goto fail;
655 }
656 session->username = lydict_insert_zc(server_opts.ctx, cp);
657 }
658
659 VRB("Cert verify CTN: new client username recognized as \"%s\".", session->username);
660 return 1;
661
662fail:
663 if (depth > 0) {
664 VRB("Cert verify CTN: cert fail, cert-to-name will continue on the next cert in chain.");
665 return 1;
666 }
667
668 VRB("Cert-to-name unsuccessful, dropping the new client.");
669 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
670 return 0;
671}
672
Michal Vasko3031aae2016-01-27 16:07:18 +0100673API int
674nc_server_tls_add_endpt_listen(const char *name, const char *address, uint16_t port)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100675{
Michal Vasko3031aae2016-01-27 16:07:18 +0100676 return nc_server_add_endpt_listen(name, address, port, NC_TI_OPENSSL);
677}
678
679API int
Michal Vaskoda514772016-02-01 11:32:01 +0100680nc_server_tls_endpt_set_address(const char *endpt_name, const char *address)
681{
682 return nc_server_endpt_set_address_port(endpt_name, address, 0, NC_TI_OPENSSL);
683}
684
685API int
686nc_server_tls_endpt_set_port(const char *endpt_name, uint16_t port)
687{
688 return nc_server_endpt_set_address_port(endpt_name, NULL, port, NC_TI_OPENSSL);
689}
690
691API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100692nc_server_tls_del_endpt(const char *name)
693{
694 return nc_server_del_endpt(name, NC_TI_OPENSSL);
695}
696
697static int
698nc_server_tls_set_cert(const char *cert, struct nc_server_tls_opts *opts)
699{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100700 X509 *x509_cert;
701
702 if (!cert) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200703 ERRARG("cert");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100704 return -1;
705 }
706
Michal Vaskoc61c4492016-01-25 11:13:34 +0100707 if (!opts->tls_ctx) {
708 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
709 if (!opts->tls_ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +0100710 ERR("Failed to create TLS context.");
Michal Vaskob48aa812016-01-18 14:13:09 +0100711 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100712 }
Michal Vaskoc61c4492016-01-25 11:13:34 +0100713 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100714 }
715
716 x509_cert = base64der_to_cert(cert);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100717 if (!x509_cert || (SSL_CTX_use_certificate(opts->tls_ctx, x509_cert) != 1)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100718 ERR("Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100719 X509_free(x509_cert);
Michal Vaskob48aa812016-01-18 14:13:09 +0100720 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100721 }
722 X509_free(x509_cert);
723
724 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +0100725
726fail:
Michal Vaskoc61c4492016-01-25 11:13:34 +0100727 return -1;
728}
729
730API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100731nc_server_tls_endpt_set_cert(const char *endpt_name, const char *cert)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100732{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100733 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100734 struct nc_endpt *endpt;
735
Michal Vasko51e514d2016-02-02 15:51:52 +0100736 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100737 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100738 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100739 return -1;
740 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100741 ret = nc_server_tls_set_cert(cert, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +0100742 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100743 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100744
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100745 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100746}
747
748API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100749nc_server_tls_ch_set_cert(const char *cert)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100750{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100751 int ret;
752
753 /* OPTS LOCK */
754 pthread_mutex_lock(&tls_ch_opts_lock);
755 ret = nc_server_tls_set_cert(cert, &tls_ch_opts);
756 /* OPTS UNLOCK */
757 pthread_mutex_unlock(&tls_ch_opts_lock);
758
759 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100760}
761
762static int
Michal Vasko3031aae2016-01-27 16:07:18 +0100763nc_server_tls_set_cert_path(const char *cert_path, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100764{
Michal Vaskoc61c4492016-01-25 11:13:34 +0100765 if (!cert_path) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200766 ERRARG("cert_path");
Michal Vaskoc61c4492016-01-25 11:13:34 +0100767 return -1;
768 }
769
Michal Vaskoc61c4492016-01-25 11:13:34 +0100770 if (!opts->tls_ctx) {
771 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
772 if (!opts->tls_ctx) {
773 ERR("Failed to create TLS context.");
774 goto fail;
775 }
776 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
777 }
778
779 if (SSL_CTX_use_certificate_file(opts->tls_ctx, cert_path, SSL_FILETYPE_PEM) != 1) {
780 ERR("Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
781 goto fail;
782 }
783
Michal Vaskoc61c4492016-01-25 11:13:34 +0100784 return 0;
785
786fail:
Michal Vaskob48aa812016-01-18 14:13:09 +0100787 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100788}
789
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100790API int
Michal Vaskoda514772016-02-01 11:32:01 +0100791nc_server_tls_endpt_set_cert_path(const char *endpt_name, const char *cert_path)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100792{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100793 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100794 struct nc_endpt *endpt;
795
Michal Vasko51e514d2016-02-02 15:51:52 +0100796 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100797 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100798 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100799 return -1;
800 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100801 ret = nc_server_tls_set_cert_path(cert_path, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +0100802 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100803 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100804
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100805 return ret;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100806}
807
808API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100809nc_server_tls_ch_set_cert_path(const char *cert_path)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100810{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100811 int ret;
812
813 /* OPTS LOCK */
814 pthread_mutex_lock(&tls_ch_opts_lock);
815 ret = nc_server_tls_set_cert_path(cert_path, &tls_ch_opts);
816 /* OPTS UNLOCK */
817 pthread_mutex_unlock(&tls_ch_opts_lock);
818
819 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100820}
821
822static int
Michal Vasko3031aae2016-01-27 16:07:18 +0100823nc_server_tls_set_key(const char *privkey, int is_rsa, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100824{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100825 EVP_PKEY *key;;
826
827 if (!privkey) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200828 ERRARG("privkey");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100829 return -1;
830 }
831
Michal Vaskoc61c4492016-01-25 11:13:34 +0100832 if (!opts->tls_ctx) {
833 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
834 if (!opts->tls_ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +0100835 ERR("Failed to create TLS context.");
Michal Vaskob48aa812016-01-18 14:13:09 +0100836 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100837 }
Michal Vaskoc61c4492016-01-25 11:13:34 +0100838 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100839 }
840
841 key = base64der_to_privatekey(privkey, is_rsa);
Michal Vaskoc61c4492016-01-25 11:13:34 +0100842 if (!key || (SSL_CTX_use_PrivateKey(opts->tls_ctx, key) != 1)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100843 ERR("Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100844 EVP_PKEY_free(key);
Michal Vaskob48aa812016-01-18 14:13:09 +0100845 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100846 }
847 EVP_PKEY_free(key);
848
849 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +0100850
851fail:
Michal Vaskoc61c4492016-01-25 11:13:34 +0100852 return -1;
853}
854
855API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100856nc_server_tls_endpt_set_key(const char *endpt_name, const char *privkey, int is_rsa)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100857{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100858 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100859 struct nc_endpt *endpt;
860
Michal Vasko51e514d2016-02-02 15:51:52 +0100861 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100862 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100863 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100864 return -1;
865 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100866 ret = nc_server_tls_set_key(privkey, is_rsa, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +0100867 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100868 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100869
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100870 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100871}
872
873API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100874nc_server_tls_ch_set_key(const char *privkey, int is_rsa)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100875{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100876 int ret;
877
878 /* OPTS LOCK */
879 pthread_mutex_lock(&tls_ch_opts_lock);
880 ret = nc_server_tls_set_key(privkey, is_rsa, &tls_ch_opts);
881 /* OPTS UNLOCK */
882 pthread_mutex_unlock(&tls_ch_opts_lock);
883
884 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100885}
886
887static int
Michal Vasko3031aae2016-01-27 16:07:18 +0100888nc_server_tls_set_key_path(const char *privkey_path, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100889{
Michal Vaskoc61c4492016-01-25 11:13:34 +0100890 if (!privkey_path) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200891 ERRARG("privkey_path");
Michal Vaskoc61c4492016-01-25 11:13:34 +0100892 return -1;
893 }
894
Michal Vaskoc61c4492016-01-25 11:13:34 +0100895 if (!opts->tls_ctx) {
896 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
897 if (!opts->tls_ctx) {
898 ERR("Failed to create TLS context.");
899 goto fail;
900 }
901 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
902 }
903
904 if (SSL_CTX_use_PrivateKey_file(opts->tls_ctx, privkey_path, SSL_FILETYPE_PEM) != 1) {
905 ERR("Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
906 goto fail;
907 }
908
Michal Vaskoc61c4492016-01-25 11:13:34 +0100909 return 0;
910
911fail:
Michal Vaskob48aa812016-01-18 14:13:09 +0100912 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100913}
914
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100915API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100916nc_server_tls_endpt_set_key_path(const char *endpt_name, const char *privkey_path)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100917{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100918 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100919 struct nc_endpt *endpt;
920
Michal Vasko51e514d2016-02-02 15:51:52 +0100921 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100922 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100923 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100924 return -1;
925 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100926 ret = nc_server_tls_set_key_path(privkey_path, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +0100927 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100928 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +0100929
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100930 return ret;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100931}
932
933API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100934nc_server_tls_ch_set_key_path(const char *privkey_path)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100935{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100936 int ret;
937
938 /* OPTS LOCK */
939 pthread_mutex_lock(&tls_ch_opts_lock);
940 ret = nc_server_tls_set_key_path(privkey_path, &tls_ch_opts);
941 /* OPTS UNLOCK */
942 pthread_mutex_unlock(&tls_ch_opts_lock);
943
944 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +0100945}
946
947static int
Michal Vasko3031aae2016-01-27 16:07:18 +0100948nc_server_tls_add_trusted_cert(const char *cert, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +0100949{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100950 X509_STORE *cert_store;
951 X509 *x509_cert;
952
953 if (!cert) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200954 ERRARG("cert");
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100955 return -1;
956 }
957
Michal Vaskoc61c4492016-01-25 11:13:34 +0100958 if (!opts->tls_ctx) {
959 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
960 if (!opts->tls_ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +0100961 ERR("Failed to create TLS context.");
Michal Vaskob48aa812016-01-18 14:13:09 +0100962 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100963 }
Michal Vaskoc61c4492016-01-25 11:13:34 +0100964 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100965 }
966
Michal Vaskoc61c4492016-01-25 11:13:34 +0100967 cert_store = SSL_CTX_get_cert_store(opts->tls_ctx);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100968 if (!cert_store) {
969 cert_store = X509_STORE_new();
Michal Vaskoc61c4492016-01-25 11:13:34 +0100970 SSL_CTX_set_cert_store(opts->tls_ctx, cert_store);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100971 }
972
973 x509_cert = base64der_to_cert(cert);
974 if (!x509_cert || (X509_STORE_add_cert(cert_store, x509_cert) != 1)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100975 ERR("Adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100976 X509_free(x509_cert);
Michal Vaskob48aa812016-01-18 14:13:09 +0100977 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100978 }
979 X509_free(x509_cert);
980
981 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +0100982
983fail:
Michal Vaskob48aa812016-01-18 14:13:09 +0100984 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100985}
986
987API int
Michal Vasko3031aae2016-01-27 16:07:18 +0100988nc_server_tls_endpt_add_trusted_cert(const char *endpt_name, const char *cert)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100989{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100990 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +0100991 struct nc_endpt *endpt;
992
Michal Vasko51e514d2016-02-02 15:51:52 +0100993 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100994 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +0100995 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100996 return -1;
997 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +0100998 ret = nc_server_tls_add_trusted_cert(cert, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +0100999 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001000 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001001
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001002 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001003}
1004
1005API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001006nc_server_tls_ch_add_trusted_cert(const char *cert)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001007{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001008 int ret;
1009
1010 /* OPTS LOCK */
1011 pthread_mutex_lock(&tls_ch_opts_lock);
1012 ret = nc_server_tls_add_trusted_cert(cert, &tls_ch_opts);
1013 /* OPTS UNLOCK */
1014 pthread_mutex_unlock(&tls_ch_opts_lock);
1015
1016 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001017}
1018
1019static int
Michal Vasko3031aae2016-01-27 16:07:18 +01001020nc_server_tls_add_trusted_cert_path(const char *cert_path, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001021{
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001022 X509_STORE *cert_store;
1023 X509 *x509_cert;
1024
1025 if (!cert_path) {
Michal Vasko45e53ae2016-04-07 11:46:03 +02001026 ERRARG("cert_path");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001027 return -1;
1028 }
1029
Michal Vaskoc61c4492016-01-25 11:13:34 +01001030 if (!opts->tls_ctx) {
1031 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
1032 if (!opts->tls_ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +01001033 ERR("Failed to create TLS context.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001034 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001035 }
Michal Vaskoc61c4492016-01-25 11:13:34 +01001036 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001037 }
1038
Michal Vaskoc61c4492016-01-25 11:13:34 +01001039 cert_store = SSL_CTX_get_cert_store(opts->tls_ctx);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001040 if (!cert_store) {
1041 cert_store = X509_STORE_new();
Michal Vaskoc61c4492016-01-25 11:13:34 +01001042 SSL_CTX_set_cert_store(opts->tls_ctx, cert_store);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001043 }
1044
1045 errno = 0;
1046 x509_cert = pem_to_cert(cert_path);
1047 if (!x509_cert || (X509_STORE_add_cert(cert_store, x509_cert) != 1)) {
Michal Vaskod083db62016-01-19 10:31:29 +01001048 ERR("Adding a trusted certificate failed (%s).",
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001049 (errno ? strerror(errno) : ERR_reason_error_string(ERR_get_error())));
1050 X509_free(x509_cert);
Michal Vaskob48aa812016-01-18 14:13:09 +01001051 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001052 }
1053 X509_free(x509_cert);
1054
1055 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +01001056
1057fail:
Michal Vaskob48aa812016-01-18 14:13:09 +01001058 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001059}
1060
1061API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001062nc_server_tls_endpt_add_trusted_cert_path(const char *endpt_name, const char *cert_path)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001063{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001064 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001065 struct nc_endpt *endpt;
1066
Michal Vasko51e514d2016-02-02 15:51:52 +01001067 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001068 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001069 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001070 return -1;
1071 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001072 ret = nc_server_tls_add_trusted_cert_path(cert_path, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001073 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001074 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001075
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001076 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001077}
1078
1079API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001080nc_server_tls_ch_add_trusted_cert_path(const char *cert_path)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001081{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001082 int ret;
1083
1084 /* OPTS LOCK */
1085 pthread_mutex_lock(&tls_ch_opts_lock);
1086 ret = nc_server_tls_add_trusted_cert_path(cert_path, &tls_ch_opts);
1087 /* OPTS UNLOCK */
1088 pthread_mutex_unlock(&tls_ch_opts_lock);
1089
1090 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001091}
1092
1093static int
Michal Vasko96830e32016-02-01 10:54:18 +01001094nc_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 +01001095{
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001096 X509_STORE *cert_store;
1097 X509_LOOKUP *lookup;
1098
Michal Vasko96830e32016-02-01 10:54:18 +01001099 if (!ca_file && !ca_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +02001100 ERRARG("ca_file and ca_dir");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001101 return -1;
1102 }
1103
Michal Vaskoc61c4492016-01-25 11:13:34 +01001104 if (!opts->tls_ctx) {
1105 opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
1106 if (!opts->tls_ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +01001107 ERR("Failed to create TLS context.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001108 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001109 }
Michal Vaskoc61c4492016-01-25 11:13:34 +01001110 SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001111 }
1112
Michal Vaskoc61c4492016-01-25 11:13:34 +01001113 cert_store = SSL_CTX_get_cert_store(opts->tls_ctx);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001114 if (!cert_store) {
1115 cert_store = X509_STORE_new();
Michal Vaskoc61c4492016-01-25 11:13:34 +01001116 SSL_CTX_set_cert_store(opts->tls_ctx, cert_store);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001117 }
1118
Michal Vasko96830e32016-02-01 10:54:18 +01001119 if (ca_file) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001120 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
1121 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001122 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001123 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001124 }
1125
Michal Vasko96830e32016-02-01 10:54:18 +01001126 if (X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001127 ERR("Failed to add a trusted cert file (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001128 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001129 }
1130 }
1131
Michal Vasko96830e32016-02-01 10:54:18 +01001132 if (ca_dir) {
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001133 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
1134 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001135 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001136 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001137 }
1138
Michal Vasko96830e32016-02-01 10:54:18 +01001139 if (X509_LOOKUP_add_dir(lookup, ca_dir, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001140 ERR("Failed to add a trusted cert directory (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001141 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001142 }
1143 }
1144
1145 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +01001146
1147fail:
Michal Vaskob48aa812016-01-18 14:13:09 +01001148 return -1;
Michal Vasko086311b2016-01-08 09:53:11 +01001149}
1150
Michal Vaskoc61c4492016-01-25 11:13:34 +01001151API int
Michal Vasko96830e32016-02-01 10:54:18 +01001152nc_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 +01001153{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001154 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001155 struct nc_endpt *endpt;
1156
Michal Vasko51e514d2016-02-02 15:51:52 +01001157 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001158 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001159 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001160 return -1;
1161 }
Michal Vasko96830e32016-02-01 10:54:18 +01001162 ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001163 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001164 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001165
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001166 return ret;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001167}
1168
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001169API int
Michal Vasko96830e32016-02-01 10:54:18 +01001170nc_server_tls_ch_set_trusted_ca_paths(const char *ca_file, const char *ca_dir)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001171{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001172 int ret;
1173
1174 /* OPTS LOCK */
1175 pthread_mutex_lock(&tls_ch_opts_lock);
Michal Vasko96830e32016-02-01 10:54:18 +01001176 ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, &tls_ch_opts);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001177 /* OPTS UNLOCK */
1178 pthread_mutex_unlock(&tls_ch_opts_lock);
1179
1180 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001181}
1182
1183static void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001184nc_server_tls_clear_certs(struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001185{
Michal Vaskoc61c4492016-01-25 11:13:34 +01001186 if (!opts->tls_ctx) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001187 return;
1188 }
1189
1190 SSL_CTX_free(opts->tls_ctx);
1191 opts->tls_ctx = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001192}
1193
1194API void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001195nc_server_tls_endpt_clear_certs(const char *endpt_name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001196{
Michal Vasko3031aae2016-01-27 16:07:18 +01001197 struct nc_endpt *endpt;
1198
Michal Vasko51e514d2016-02-02 15:51:52 +01001199 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001200 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001201 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001202 return;
1203 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001204 nc_server_tls_clear_certs(endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001205 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001206 nc_server_endpt_unlock(endpt);
Michal Vaskoc61c4492016-01-25 11:13:34 +01001207}
1208
1209API void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001210nc_server_tls_ch_clear_certs(void)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001211{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001212 /* OPTS LOCK */
1213 pthread_mutex_lock(&tls_ch_opts_lock);
1214 nc_server_tls_clear_certs(&tls_ch_opts);
1215 /* OPTS UNLOCK */
1216 pthread_mutex_unlock(&tls_ch_opts_lock);
Michal Vaskoc61c4492016-01-25 11:13:34 +01001217}
1218
1219static int
Michal Vasko96830e32016-02-01 10:54:18 +01001220nc_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 +01001221{
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001222 X509_LOOKUP *lookup;
1223
Michal Vasko96830e32016-02-01 10:54:18 +01001224 if (!crl_file && !crl_dir) {
Michal Vasko45e53ae2016-04-07 11:46:03 +02001225 ERRARG("crl_file and crl_dir");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001226 return -1;
1227 }
1228
Michal Vaskoc61c4492016-01-25 11:13:34 +01001229 if (!opts->crl_store) {
1230 opts->crl_store = X509_STORE_new();
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001231 }
1232
Michal Vasko96830e32016-02-01 10:54:18 +01001233 if (crl_file) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001234 lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001235 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001236 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001237 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001238 }
1239
Michal Vasko96830e32016-02-01 10:54:18 +01001240 if (X509_LOOKUP_load_file(lookup, crl_file, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001241 ERR("Failed to add a revocation lookup file (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001242 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001243 }
1244 }
1245
Michal Vasko96830e32016-02-01 10:54:18 +01001246 if (crl_dir) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001247 lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001248 if (!lookup) {
Michal Vaskod083db62016-01-19 10:31:29 +01001249 ERR("Failed to add a lookup method.");
Michal Vaskob48aa812016-01-18 14:13:09 +01001250 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001251 }
1252
Michal Vasko96830e32016-02-01 10:54:18 +01001253 if (X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +01001254 ERR("Failed to add a revocation lookup directory (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskob48aa812016-01-18 14:13:09 +01001255 goto fail;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001256 }
1257 }
1258
1259 return 0;
Michal Vaskob48aa812016-01-18 14:13:09 +01001260
1261fail:
Michal Vaskob48aa812016-01-18 14:13:09 +01001262 return -1;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001263}
1264
Michal Vaskoc61c4492016-01-25 11:13:34 +01001265API int
Michal Vasko96830e32016-02-01 10:54:18 +01001266nc_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 +01001267{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001268 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001269 struct nc_endpt *endpt;
1270
Michal Vasko51e514d2016-02-02 15:51:52 +01001271 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001272 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001273 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001274 return -1;
1275 }
Michal Vasko96830e32016-02-01 10:54:18 +01001276 ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001277 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001278 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001279
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001280 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001281}
1282
1283API int
Michal Vasko96830e32016-02-01 10:54:18 +01001284nc_server_tls_ch_set_crl_paths(const char *crl_file, const char *crl_dir)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001285{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001286 int ret;
1287
1288 /* OPTS LOCK */
1289 pthread_mutex_lock(&tls_ch_opts_lock);
Michal Vasko96830e32016-02-01 10:54:18 +01001290 ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, &tls_ch_opts);
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001291 /* OPTS UNLOCK */
1292 pthread_mutex_unlock(&tls_ch_opts_lock);
1293
1294 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001295}
1296
1297static void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001298nc_server_tls_clear_crls(struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001299{
Michal Vaskoc61c4492016-01-25 11:13:34 +01001300 if (!opts->crl_store) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001301 return;
1302 }
1303
1304 X509_STORE_free(opts->crl_store);
1305 opts->crl_store = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001306}
1307
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001308API void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001309nc_server_tls_endpt_clear_crls(const char *endpt_name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001310{
Michal Vasko3031aae2016-01-27 16:07:18 +01001311 struct nc_endpt *endpt;
1312
Michal Vasko51e514d2016-02-02 15:51:52 +01001313 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001314 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001315 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001316 return;
1317 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001318 nc_server_tls_clear_crls(endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001319 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001320 nc_server_endpt_unlock(endpt);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001321}
1322
Michal Vaskoc61c4492016-01-25 11:13:34 +01001323API void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001324nc_server_tls_ch_clear_crls(void)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001325{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001326 /* OPTS LOCK */
1327 pthread_mutex_lock(&tls_ch_opts_lock);
1328 nc_server_tls_clear_crls(&tls_ch_opts);
1329 /* OPTS UNLOCK */
1330 pthread_mutex_unlock(&tls_ch_opts_lock);
Michal Vaskoc61c4492016-01-25 11:13:34 +01001331}
1332
1333static int
Michal Vasko3031aae2016-01-27 16:07:18 +01001334nc_server_tls_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001335{
Michal Vasko5e3f3392016-01-20 11:13:01 +01001336 struct nc_ctn *ctn, *new;
1337
Michal Vasko45e53ae2016-04-07 11:46:03 +02001338 if (!fingerprint) {
1339 ERRARG("fingerprint");
1340 return -1;
1341 } else if (!map_type) {
1342 ERRARG("map_type");
1343 return -1;
1344 } else if (((map_type == NC_TLS_CTN_SPECIFIED) && !name)
Michal Vasko1a38c862016-01-15 15:50:07 +01001345 || ((map_type != NC_TLS_CTN_SPECIFIED) && name)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +02001346 ERRARG("map_type and name");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001347 return -1;
1348 }
1349
Michal Vasko5e3f3392016-01-20 11:13:01 +01001350 new = malloc(sizeof *new);
Michal Vasko4eb3c312016-03-01 14:09:37 +01001351 if (!new) {
1352 ERRMEM;
1353 return -1;
1354 }
Michal Vasko5e3f3392016-01-20 11:13:01 +01001355
Michal Vasko5e3f3392016-01-20 11:13:01 +01001356 new->fingerprint = lydict_insert(server_opts.ctx, fingerprint, 0);
1357 new->name = lydict_insert(server_opts.ctx, name, 0);
Michal Vasko5e3f3392016-01-20 11:13:01 +01001358 new->id = id;
1359 new->map_type = map_type;
1360 new->next = NULL;
1361
Michal Vaskoc61c4492016-01-25 11:13:34 +01001362 if (!opts->ctn) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001363 /* the first item */
Michal Vaskoc61c4492016-01-25 11:13:34 +01001364 opts->ctn = new;
1365 } else if (opts->ctn->id > id) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001366 /* insert at the beginning */
Michal Vaskoc61c4492016-01-25 11:13:34 +01001367 new->next = opts->ctn;
1368 opts->ctn = new;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001369 } else {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001370 for (ctn = opts->ctn; ctn->next && ctn->next->id <= id; ctn = ctn->next);
Michal Vasko5e3f3392016-01-20 11:13:01 +01001371 /* insert after ctn */
1372 new->next = ctn->next;
1373 ctn->next = new;
1374 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001375
1376 return 0;
1377}
1378
1379API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001380nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001381{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001382 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001383 struct nc_endpt *endpt;
1384
Michal Vasko51e514d2016-02-02 15:51:52 +01001385 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001386 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001387 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001388 return -1;
1389 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001390 ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001391 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001392 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001393
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001394 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001395}
1396
1397API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001398nc_server_tls_ch_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001399{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001400 int ret;
1401
1402 /* OPTS LOCK */
1403 pthread_mutex_lock(&tls_ch_opts_lock);
1404 ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, &tls_ch_opts);
1405 /* OPTS UNLOCK */
1406 pthread_mutex_unlock(&tls_ch_opts_lock);
1407
1408 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001409}
1410
1411static int
Michal Vasko3031aae2016-01-27 16:07:18 +01001412nc_server_tls_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct nc_server_tls_opts *opts)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001413{
Michal Vasko5e3f3392016-01-20 11:13:01 +01001414 struct nc_ctn *ctn, *next, *prev;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001415 int ret = -1;
1416
Michal Vasko1a38c862016-01-15 15:50:07 +01001417 if ((id < 0) && !fingerprint && !map_type && !name) {
Michal Vaskoc61c4492016-01-25 11:13:34 +01001418 ctn = opts->ctn;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001419 while (ctn) {
1420 lydict_remove(server_opts.ctx, ctn->fingerprint);
1421 lydict_remove(server_opts.ctx, ctn->name);
1422
1423 next = ctn->next;
1424 free(ctn);
1425 ctn = next;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001426
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001427 ret = 0;
1428 }
Michal Vasko3031aae2016-01-27 16:07:18 +01001429 opts->ctn = NULL;
Michal Vasko1a38c862016-01-15 15:50:07 +01001430 } else {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001431 prev = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001432 ctn = opts->ctn;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001433 while (ctn) {
1434 if (((id < 0) || (ctn->id == id))
1435 && (!fingerprint || !strcmp(ctn->fingerprint, fingerprint))
1436 && (!map_type || (ctn->map_type == map_type))
1437 && (!name || (ctn->name && !strcmp(ctn->name, name)))) {
Michal Vasko5e3f3392016-01-20 11:13:01 +01001438 lydict_remove(server_opts.ctx, ctn->fingerprint);
1439 lydict_remove(server_opts.ctx, ctn->name);
Michal Vasko1a38c862016-01-15 15:50:07 +01001440
Michal Vasko5e3f3392016-01-20 11:13:01 +01001441 if (prev) {
1442 prev->next = ctn->next;
1443 next = ctn->next;
1444 } else {
Michal Vasko3031aae2016-01-27 16:07:18 +01001445 opts->ctn = ctn->next;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001446 next = ctn->next;
1447 }
1448 free(ctn);
1449 ctn = next;
Michal Vasko1a38c862016-01-15 15:50:07 +01001450
1451 ret = 0;
Michal Vasko5e3f3392016-01-20 11:13:01 +01001452 } else {
1453 prev = ctn;
1454 ctn = ctn->next;
Michal Vasko1a38c862016-01-15 15:50:07 +01001455 }
1456 }
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001457 }
1458
1459 return ret;
1460}
1461
Michal Vaskoc61c4492016-01-25 11:13:34 +01001462API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001463nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001464{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001465 int ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001466 struct nc_endpt *endpt;
1467
Michal Vasko51e514d2016-02-02 15:51:52 +01001468 /* LOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001469 endpt = nc_server_endpt_lock(endpt_name, NC_TI_OPENSSL);
Michal Vasko3031aae2016-01-27 16:07:18 +01001470 if (!endpt) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001471 return -1;
1472 }
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001473 ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->ti_opts);
Michal Vasko51e514d2016-02-02 15:51:52 +01001474 /* UNLOCK */
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001475 nc_server_endpt_unlock(endpt);
Michal Vasko3031aae2016-01-27 16:07:18 +01001476
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001477 return ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001478}
1479
1480API int
Michal Vasko3031aae2016-01-27 16:07:18 +01001481nc_server_tls_ch_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
Michal Vaskoc61c4492016-01-25 11:13:34 +01001482{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001483 int ret;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001484
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001485 /* OPTS LOCK */
1486 pthread_mutex_lock(&tls_ch_opts_lock);
1487 ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, &tls_ch_opts);
1488 /* OPTS UNLOCK */
1489 pthread_mutex_unlock(&tls_ch_opts_lock);
1490
1491 return ret;
Michal Vasko3031aae2016-01-27 16:07:18 +01001492}
Michal Vaskoc61c4492016-01-25 11:13:34 +01001493
Michal Vasko3031aae2016-01-27 16:07:18 +01001494void
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001495nc_server_tls_clear_opts(struct nc_server_tls_opts *opts)
Michal Vasko3031aae2016-01-27 16:07:18 +01001496{
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001497 nc_server_tls_clear_certs(opts);
1498 nc_server_tls_clear_crls(opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001499 nc_server_tls_del_ctn(-1, NULL, 0, NULL, opts);
Michal Vasko086311b2016-01-08 09:53:11 +01001500}
Michal Vasko9e036d52016-01-08 10:49:26 +01001501
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001502API void
1503nc_server_tls_ch_clear_opts(void)
1504{
1505 /* OPTS LOCK */
1506 pthread_mutex_lock(&tls_ch_opts_lock);
1507 nc_server_tls_clear_opts(&tls_ch_opts);
1508 /* OPTS UNLOCK */
1509 pthread_mutex_unlock(&tls_ch_opts_lock);
1510}
1511
Michal Vasko6d292992016-01-18 09:42:38 +01001512static void
1513nc_tls_make_verify_key(void)
1514{
Michal Vasko5c2f7952016-01-22 13:16:31 +01001515 pthread_key_create(&verify_key, NULL);
Michal Vasko6d292992016-01-18 09:42:38 +01001516}
1517
Michal Vasko71090fc2016-05-24 16:37:28 +02001518API NC_MSG_TYPE
Michal Vasko8f5270d2016-02-29 16:22:25 +01001519nc_connect_callhome_tls(const char *host, uint16_t port, struct nc_session **session)
Michal Vasko9e036d52016-01-08 10:49:26 +01001520{
Michal Vasko8f5270d2016-02-29 16:22:25 +01001521 return nc_connect_callhome(host, port, NC_TI_OPENSSL, session);
Michal Vasko3031aae2016-01-27 16:07:18 +01001522}
1523
1524int
Michal Vasko0190bc32016-03-02 15:47:49 +01001525nc_accept_tls_session(struct nc_session *session, int sock, int timeout)
Michal Vasko3031aae2016-01-27 16:07:18 +01001526{
1527 struct nc_server_tls_opts *opts;
Michal Vasko0190bc32016-03-02 15:47:49 +01001528 int ret, elapsed_usec = 0;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001529
Michal Vasko2cc4c682016-03-01 09:16:48 +01001530 opts = session->data;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001531
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001532 session->ti_type = NC_TI_OPENSSL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001533 session->ti.tls = SSL_new(opts->tls_ctx);
Michal Vasko7f1c78b2016-01-19 09:52:14 +01001534
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001535 if (!session->ti.tls) {
Michal Vaskod083db62016-01-19 10:31:29 +01001536 ERR("Failed to create TLS structure from context.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001537 close(sock);
1538 return -1;
1539 }
1540
1541 SSL_set_fd(session->ti.tls, sock);
1542 SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
1543
Michal Vasko6d292992016-01-18 09:42:38 +01001544 /* store session on per-thread basis */
Michal Vasko5c2f7952016-01-22 13:16:31 +01001545 pthread_once(&verify_once, nc_tls_make_verify_key);
1546 pthread_setspecific(verify_key, session);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001547
Michal Vasko0190bc32016-03-02 15:47:49 +01001548 while (((ret = SSL_accept(session->ti.tls)) == -1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
1549 usleep(NC_TIMEOUT_STEP);
1550 elapsed_usec += NC_TIMEOUT_STEP;
1551 if ((timeout > -1) && (elapsed_usec / 1000 >= timeout)) {
1552 ERR("SSL_accept timeout.");
1553 return 0;
1554 }
1555 }
Michal Vaskob48aa812016-01-18 14:13:09 +01001556
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001557 if (ret != 1) {
1558 switch (SSL_get_error(session->ti.tls, ret)) {
1559 case SSL_ERROR_SYSCALL:
Michal Vaskod083db62016-01-19 10:31:29 +01001560 ERR("SSL_accept failed (%s).", strerror(errno));
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001561 break;
1562 case SSL_ERROR_SSL:
Michal Vaskod083db62016-01-19 10:31:29 +01001563 ERR("SSL_accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001564 break;
1565 default:
Michal Vaskod083db62016-01-19 10:31:29 +01001566 ERR("SSL_accept failed.");
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001567 break;
1568 }
1569 return -1;
1570 }
1571
Michal Vasko1a38c862016-01-15 15:50:07 +01001572 return 1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001573}