blob: d9c574c23dad27a70a0f0ae154c990329008a32e [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 */
22
Michal Vaskoc14e3c82016-01-11 16:14:30 +010023#define _GNU_SOURCE
24
25#include <string.h>
26#include <poll.h>
27
28#include <openssl/ssl.h>
29#include <openssl/evp.h>
30#include <openssl/err.h>
31#include <openssl/x509v3.h>
32
Michal Vasko086311b2016-01-08 09:53:11 +010033#include "session_server.h"
34#include "config.h"
Michal Vaskoc14e3c82016-01-11 16:14:30 +010035#include "session_p.h"
Radek Krejci5da708a2015-09-01 17:33:23 +020036
Michal Vaskoc14e3c82016-01-11 16:14:30 +010037extern struct nc_server_opts server_opts;
38struct nc_tls_server_opts tls_opts;
39
40static char *
41asn1time_to_str(ASN1_TIME *t)
Michal Vasko086311b2016-01-08 09:53:11 +010042{
Michal Vaskoc14e3c82016-01-11 16:14:30 +010043 char *cp;
44 BIO *bio;
45 int n;
Radek Krejci5da708a2015-09-01 17:33:23 +020046
Michal Vaskoc14e3c82016-01-11 16:14:30 +010047 if (!t) {
48 return NULL;
49 }
50 bio = BIO_new(BIO_s_mem());
51 if (!bio) {
52 return NULL;
53 }
54 ASN1_TIME_print(bio, t);
55 n = BIO_pending(bio);
56 cp = malloc(n + 1);
57 n = BIO_read(bio, cp, n);
58 if (n < 0) {
59 BIO_free(bio);
60 free(cp);
61 return NULL;
62 }
63 cp[n] = '\0';
64 BIO_free(bio);
65 return cp;
66}
67
68static void
69digest_to_str(const unsigned char *digest, unsigned int dig_len, char **str)
70{
71 unsigned int i;
72
73 *str = malloc(dig_len * 3);
74 for (i = 0; i < dig_len - 1; ++i) {
75 sprintf((*str) + (i * 3), "%02x:", digest[i]);
76 }
77 sprintf((*str) + (i * 3), "%02x", digest[i]);
78}
79
80/* return NULL - SSL error can be retrieved */
81static X509 *
82base64der_to_cert(const char *in)
83{
84 X509 *out;
85 char *buf;
86 BIO *bio;
87
88 if (in == NULL) {
89 return NULL;
90 }
91
92 if (asprintf(&buf, "%s%s%s", "-----BEGIN CERTIFICATE-----\n", in, "\n-----END CERTIFICATE-----") == -1) {
93 return NULL;
94 }
95 bio = BIO_new_mem_buf(buf, strlen(buf));
96 if (!bio) {
97 free(buf);
98 return NULL;
99 }
100
101 out = PEM_read_bio_X509(bio, NULL, NULL, NULL);
102 if (!out) {
103 free(buf);
104 BIO_free(bio);
105 return NULL;
106 }
107
108 free(buf);
109 BIO_free(bio);
110 return out;
111}
112
113/* return NULL - either errno or SSL error */
114static X509 *
115pem_to_cert(const char *path)
116{
117 FILE *fp;
118 X509 *out;
119
120 fp = fopen(path, "r");
121 if (!fp) {
122 return NULL;
123 }
124
125 out = PEM_read_X509(fp, NULL, NULL, NULL);
126 fclose(fp);
127 return out;
128}
129
130static EVP_PKEY *
131base64der_to_privatekey(const char *in, int rsa)
132{
133 EVP_PKEY *out;
134 char *buf;
135 BIO *bio;
136
137 if (in == NULL) {
138 return NULL;
139 }
140
141 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) {
142 return NULL;
143 }
144 bio = BIO_new_mem_buf(buf, strlen(buf));
145 if (!bio) {
146 free(buf);
147 return NULL;
148 }
149
150 out = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
151 if (!out) {
152 free(buf);
153 BIO_free(bio);
154 return NULL;
155 }
156
157 free(buf);
158 BIO_free(bio);
159 return out;
160}
161
162static int
163cert_pubkey_match(X509 *cert1, X509 *cert2)
164{
165 ASN1_BIT_STRING *bitstr1, *bitstr2;
166
167 bitstr1 = X509_get0_pubkey_bitstr(cert1);
168 bitstr2 = X509_get0_pubkey_bitstr(cert2);
169
170 if (!bitstr1 || !bitstr2 || (bitstr1->length != bitstr2->length) ||
171 memcmp(bitstr1->data, bitstr2->data, bitstr1->length)) {
172 return 0;
173 }
174
175 return 1;
176}
177
178static int
179nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type, char **username)
180{
181 STACK_OF(GENERAL_NAME) *san_names;
182 GENERAL_NAME *san_name;
183 ASN1_OCTET_STRING *ip;
184 int i, san_count;
185 char *subject, *common_name;
186
187 if (map_type == NC_TLS_CTN_COMMON_NAME) {
188 subject = X509_NAME_oneline(X509_get_subject_name(client_cert), NULL, 0);
189 common_name = strstr(subject, "CN=");
190 if (!common_name) {
191 WRN("%s: cert does not include the commonName field", __func__);
192 free(subject);
193 return 1;
194 }
195 common_name += 3;
196 if (strchr(common_name, '/')) {
197 *strchr(common_name, '/') = '\0';
198 }
199 *username = strdup(common_name);
200 free(subject);
201 } else {
202 /* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */
203 san_names = X509_get_ext_d2i(client_cert, NID_subject_alt_name, NULL, NULL);
204 if (!san_names) {
205 WRN("%s: cert has no SANs or failed to retrieve them", __func__);
206 return 1;
207 }
208
209 san_count = sk_GENERAL_NAME_num(san_names);
210 for (i = 0; i < san_count; ++i) {
211 san_name = sk_GENERAL_NAME_value(san_names, i);
212
213 /* rfc822Name (email) */
214 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_RFC822_NAME) &&
215 san_name->type == GEN_EMAIL) {
216 *username = strdup((char *)ASN1_STRING_data(san_name->d.rfc822Name));
217 break;
218 }
219
220 /* dNSName */
221 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_DNS_NAME) &&
222 san_name->type == GEN_DNS) {
223 *username = strdup((char *)ASN1_STRING_data(san_name->d.dNSName));
224 break;
225 }
226
227 /* iPAddress */
228 if ((map_type == NC_TLS_CTN_SAN_ANY || map_type == NC_TLS_CTN_SAN_IP_ADDRESS) &&
229 san_name->type == GEN_IPADD) {
230 ip = san_name->d.iPAddress;
231 if (ip->length == 4) {
232 if (asprintf(username, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
233 ERR("%s: asprintf() failed", __func__);
234 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
235 return -1;
236 }
237 break;
238 } else if (ip->length == 16) {
239 if (asprintf(username, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
240 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
241 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
242 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
243 ERR("%s: asprintf() failed", __func__);
244 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
245 return -1;
246 }
247 break;
248 } else {
249 WRN("%s: SAN IP address in an unknown format (length is %d)", __func__, ip->length);
250 }
251 }
252 }
253 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
254
255 if (i < san_count) {
256 switch (map_type) {
257 case NC_TLS_CTN_SAN_RFC822_NAME:
258 WRN("%s: cert does not include the SAN rfc822Name field", __func__);
259 break;
260 case NC_TLS_CTN_SAN_DNS_NAME:
261 WRN("%s: cert does not include the SAN dNSName field", __func__);
262 break;
263 case NC_TLS_CTN_SAN_IP_ADDRESS:
264 WRN("%s: cert does not include the SAN iPAddress field", __func__);
265 break;
266 case NC_TLS_CTN_SAN_ANY:
267 WRN("%s: cert does not include any relevant SAN fields", __func__);
268 break;
269 default:
270 break;
271 }
272 return 1;
273 }
274 }
275
276 return 0;
277}
278
279/* return: 0 - OK, 1 - no match, -1 - error */
280static int
281nc_tls_cert_to_name(X509 *cert, NC_TLS_CTN_MAPTYPE *map_type, const char **name)
282{
283 char *digest_md5 = NULL, *digest_sha1 = NULL, *digest_sha224 = NULL;
284 char *digest_sha256 = NULL, *digest_sha384 = NULL, *digest_sha512 = NULL;
285 uint16_t i;
286 unsigned char *buf = malloc(64);
287 unsigned int buf_len = 64;
288 int ret = 0;
289
290 if (cert == NULL || map_type == NULL || name == NULL) {
291 free(buf);
292 return -1;
293 }
294
295 for (i = 0; i < tls_opts.ctn_count; ++i) {
296 /* MD5 */
297 if (!strncmp(tls_opts.ctn[i].fingerprint, "01", 2)) {
298 if (!digest_md5) {
299 if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) {
300 ERR("%s: calculating MD5 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
301 ret = -1;
302 goto cleanup;
303 }
304 digest_to_str(buf, buf_len, &digest_md5);
305 }
306
307 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_md5)) {
308 /* we got ourselves a winner! */
309 VRB("Cert verify CTN: entry with a matching fingerprint found");
310 *map_type = tls_opts.ctn[i].map_type;
311 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
312 *name = tls_opts.ctn[i].name;
313 }
314 break;
315 }
316
317 /* SHA-1 */
318 } else if (!strncmp(tls_opts.ctn[i].fingerprint, "02", 2)) {
319 if (!digest_sha1) {
320 if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) {
321 ERR("%s: calculating SHA-1 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
322 ret = -1;
323 goto cleanup;
324 }
325 digest_to_str(buf, buf_len, &digest_sha1);
326 }
327
328 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_sha1)) {
329 /* we got ourselves a winner! */
330 VRB("Cert verify CTN: entry with a matching fingerprint found");
331 *map_type = tls_opts.ctn[i].map_type;
332 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
333 *name = tls_opts.ctn[i].name;
334 }
335 break;
336 }
337
338 /* SHA-224 */
339 } else if (!strncmp(tls_opts.ctn[i].fingerprint, "03", 2)) {
340 if (!digest_sha224) {
341 if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) {
342 ERR("%s: calculating SHA-224 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
343 ret = -1;
344 goto cleanup;
345 }
346 digest_to_str(buf, buf_len, &digest_sha224);
347 }
348
349 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_sha224)) {
350 /* we got ourselves a winner! */
351 VRB("Cert verify CTN: entry with a matching fingerprint found");
352 *map_type = tls_opts.ctn[i].map_type;
353 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
354 *name = tls_opts.ctn[i].name;
355 }
356 break;
357 }
358
359 /* SHA-256 */
360 } else if (!strncmp(tls_opts.ctn[i].fingerprint, "04", 2)) {
361 if (!digest_sha256) {
362 if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) {
363 ERR("%s: calculating SHA-256 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
364 ret = -1;
365 goto cleanup;
366 }
367 digest_to_str(buf, buf_len, &digest_sha256);
368 }
369
370 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_sha256)) {
371 /* we got ourselves a winner! */
372 VRB("Cert verify CTN: entry with a matching fingerprint found");
373 *map_type = tls_opts.ctn[i].map_type;
374 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
375 *name = tls_opts.ctn[i].name;
376 }
377 break;
378 }
379
380 /* SHA-384 */
381 } else if (!strncmp(tls_opts.ctn[i].fingerprint, "05", 2)) {
382 if (!digest_sha384) {
383 if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) {
384 ERR("%s: calculating SHA-384 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
385 ret = -1;
386 goto cleanup;
387 }
388 digest_to_str(buf, buf_len, &digest_sha384);
389 }
390
391 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_sha384)) {
392 /* we got ourselves a winner! */
393 VRB("Cert verify CTN: entry with a matching fingerprint found");
394 *map_type = tls_opts.ctn[i].map_type;
395 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
396 *name = tls_opts.ctn[i].name;
397 }
398 break;
399 }
400
401 /* SHA-512 */
402 } else if (!strncmp(tls_opts.ctn[i].fingerprint, "06", 2)) {
403 if (!digest_sha512) {
404 if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) {
405 ERR("%s: calculating SHA-512 digest: %s", __func__, ERR_reason_error_string(ERR_get_error()));
406 ret = -1;
407 goto cleanup;
408 }
409 digest_to_str(buf, buf_len, &digest_sha512);
410 }
411
412 if (!strcasecmp(tls_opts.ctn[i].fingerprint + 3, digest_sha512)) {
413 /* we got ourselves a winner! */
414 VRB("Cert verify CTN: entry with a matching fingerprint found");
415 *map_type = tls_opts.ctn[i].map_type;
416 if (tls_opts.ctn[i].map_type == NC_TLS_CTN_SPECIFIED) {
417 *name = tls_opts.ctn[i].name;
418 }
419 break;
420 }
421
422 /* unknown */
423 } else {
424 WRN("%s: unknown fingerprint algorithm used (%s), skipping", __func__, tls_opts.ctn[i].fingerprint);
425 }
426 }
427
428 if (i == tls_opts.ctn_count) {
429 ret = 1;
430 }
431
432cleanup:
433 free(digest_md5);
434 free(digest_sha1);
435 free(digest_sha224);
436 free(digest_sha256);
437 free(digest_sha384);
438 free(digest_sha512);
439 free(buf);
440 return ret;
441}
442
443/* TODO */
444struct nc_session *glob_session;
445
446static int
447nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
448{
449 X509_STORE_CTX store_ctx;
450 X509_OBJECT obj;
451 X509_NAME *subject;
452 X509_NAME *issuer;
453 X509 *cert;
454 X509_CRL *crl;
455 X509_REVOKED *revoked;
456 STACK_OF(X509) *cert_stack;
457 EVP_PKEY *pubkey;
458 struct nc_session* session;
459 long serial;
460 int i, n, rc, depth;
461 char *cp;
462 const char *username = NULL;
463 NC_TLS_CTN_MAPTYPE map_type = 0;
464 ASN1_TIME *last_update = NULL, *next_update = NULL;
465
466 /* get the new client structure */
467 session = glob_session;
468
469 /* get the last certificate, that is the peer (client) certificate */
470 if (!session->cert) {
471 cert_stack = X509_STORE_CTX_get1_chain(x509_ctx);
472 /* TODO all that is needed, but function X509_up_ref not present in older OpenSSL versions
473 session->cert = sk_X509_value(cert_stack, sk_X509_num(cert_stack) - 1);
474 X509_up_ref(session->cert);
475 sk_X509_pop_free(cert_stack, X509_free); */
476 while ((cert = sk_X509_pop(cert_stack))) {
477 X509_free(session->cert);
478 session->cert = cert;
479 }
480 sk_X509_pop_free(cert_stack, X509_free);
481 }
482
483 /* standard certificate verification failed, so a trusted client cert must match to continue */
484 if (!preverify_ok) {
485 subject = X509_get_subject_name(session->cert);
486 cert_stack = X509_STORE_get1_certs(x509_ctx, subject);
487 if (cert_stack) {
488 for (i = 0; i < sk_X509_num(cert_stack); ++i) {
489 if (cert_pubkey_match(session->cert, sk_X509_value(cert_stack, i))) {
490 /* we are just overriding the failed standard certificate verification (preverify_ok == 0),
491 * this callback will be called again with the same current certificate and preverify_ok == 1 */
Michal Vasko05ba9df2016-01-13 14:40:27 +0100492 VRB("Cert verify: fail (%s), but the client certificate is trusted, continuing.",
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100493 X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
494 X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
495 sk_X509_pop_free(cert_stack, X509_free);
496 return 1;
497 }
498 }
499 sk_X509_pop_free(cert_stack, X509_free);
500 }
501
502 ERR("Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
503 return 0;
504 }
505
506 /* print cert verify info */
507 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
508 VRB("Cert verify: depth %d", depth);
509
510 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
511 subject = X509_get_subject_name(cert);
512 issuer = X509_get_issuer_name(cert);
513
514 cp = X509_NAME_oneline(subject, NULL, 0);
515 VRB("Cert verify: subject: %s", cp);
516 OPENSSL_free(cp);
517 cp = X509_NAME_oneline(issuer, NULL, 0);
518 VRB("Cert verify: issuer: %s", cp);
519 OPENSSL_free(cp);
520
521 /* check for revocation if set */
522 if (tls_opts.crl_store) {
523 /* try to retrieve a CRL corresponding to the _subject_ of
524 * the current certificate in order to verify it's integrity */
525 memset((char *)&obj, 0, sizeof(obj));
526 X509_STORE_CTX_init(&store_ctx, tls_opts.crl_store, NULL, NULL);
527 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
528 X509_STORE_CTX_cleanup(&store_ctx);
529 crl = obj.data.crl;
530 if (rc > 0 && crl) {
531 cp = X509_NAME_oneline(subject, NULL, 0);
532 VRB("Cert verify CRL: issuer: %s", cp);
533 OPENSSL_free(cp);
534
535 last_update = X509_CRL_get_lastUpdate(crl);
536 next_update = X509_CRL_get_nextUpdate(crl);
537 cp = asn1time_to_str(last_update);
538 VRB("Cert verify CRL: last update: %s", cp);
539 free(cp);
540 cp = asn1time_to_str(next_update);
541 VRB("Cert verify CRL: next update: %s", cp);
542 free(cp);
543
544 /* verify the signature on this CRL */
545 pubkey = X509_get_pubkey(cert);
546 if (X509_CRL_verify(crl, pubkey) <= 0) {
547 ERR("Cert verify CRL: invalid signature.");
548 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
549 X509_OBJECT_free_contents(&obj);
550 if (pubkey) {
551 EVP_PKEY_free(pubkey);
552 }
553 return 0;
554 }
555 if (pubkey) {
556 EVP_PKEY_free(pubkey);
557 }
558
559 /* check date of CRL to make sure it's not expired */
560 if (!next_update) {
561 ERR("Cert verify CRL: invalid nextUpdate field.");
562 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
563 X509_OBJECT_free_contents(&obj);
564 return 0;
565 }
566 if (X509_cmp_current_time(next_update) < 0) {
567 ERR("Cert verify CRL: expired - revoking all certificates.");
568 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
569 X509_OBJECT_free_contents(&obj);
570 return 0;
571 }
572 X509_OBJECT_free_contents(&obj);
573 }
574
575 /* try to retrieve a CRL corresponding to the _issuer_ of
576 * the current certificate in order to check for revocation */
577 memset((char *)&obj, 0, sizeof(obj));
578 X509_STORE_CTX_init(&store_ctx, tls_opts.crl_store, NULL, NULL);
579 rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
580 X509_STORE_CTX_cleanup(&store_ctx);
581 crl = obj.data.crl;
582 if (rc > 0 && crl) {
583 /* check if the current certificate is revoked by this CRL */
584 n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
585 for (i = 0; i < n; i++) {
586 revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
587 if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
588 serial = ASN1_INTEGER_get(revoked->serialNumber);
589 cp = X509_NAME_oneline(issuer, NULL, 0);
590 ERR("Cert verify CRL: certificate with serial %ld (0x%lX) revoked per CRL from issuer %s", serial, serial, cp);
591 OPENSSL_free(cp);
592 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
593 X509_OBJECT_free_contents(&obj);
594 return 0;
595 }
596 }
597 X509_OBJECT_free_contents(&obj);
598 }
599 }
600
601 /* cert-to-name already successful */
602 if (session->username) {
603 return 1;
604 }
605
606 /* cert-to-name */
607 rc = nc_tls_cert_to_name(cert, &map_type, &username);
608 if (rc) {
609 if (rc == -1) {
610 /* fatal error */
611 depth = 0;
612 }
613 /* rc == 1 is a normal CTN fail (no match found) */
614 goto fail;
615 }
616
617 /* cert-to-name match, now to extract the specific field from the peer cert */
618 if (map_type == NC_TLS_CTN_SPECIFIED) {
619 session->username = lydict_insert(server_opts.ctx, username, 0);
620 } else {
621 rc = nc_tls_ctn_get_username_from_cert(session->cert, map_type, &cp);
622 if (rc) {
623 if (rc == -1) {
624 depth = 0;
625 }
626 goto fail;
627 }
628 session->username = lydict_insert_zc(server_opts.ctx, cp);
629 }
630
631 VRB("Cert verify CTN: new client username recognized as \"%s\".", session->username);
632 return 1;
633
634fail:
635 if (depth > 0) {
636 VRB("Cert verify CTN: cert fail, cert-to-name will continue on the next cert in chain.");
637 return 1;
638 }
639
640 VRB("Cert-to-name unsuccessful, dropping the new client.");
641 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
642 return 0;
643}
644
645API int
646nc_tls_server_set_cert(const char *cert)
647{
648 X509 *x509_cert;
649
650 if (!cert) {
651 ERRARG;
652 return -1;
653 }
654
655 if (!tls_opts.tls_ctx) {
656 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
657 if (!tls_opts.tls_ctx) {
658 ERR("%s: failed to create TLS context.", __func__);
659 return -1;
660 }
661 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
662 }
663
664 x509_cert = base64der_to_cert(cert);
665 if (!x509_cert || (SSL_CTX_use_certificate(tls_opts.tls_ctx, x509_cert) != 1)) {
666 ERR("%s: loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
667 X509_free(x509_cert);
668 return -1;
669 }
670 X509_free(x509_cert);
671
672 return 0;
673}
674
675/* PEM only */
676API int
677nc_tls_server_set_cert_path(const char *cert_path)
678{
679 if (!cert_path) {
680 ERRARG;
681 return -1;
682 }
683
684 if (!tls_opts.tls_ctx) {
685 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
686 if (!tls_opts.tls_ctx) {
687 ERR("%s: failed to create TLS context.", __func__);
688 return -1;
689 }
690 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
691 }
692
693 if (SSL_CTX_use_certificate_file(tls_opts.tls_ctx, cert_path, SSL_FILETYPE_PEM) != 1) {
694 ERR("%s: loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
695 return -1;
696 }
697
698 return 0;
699}
700
701API int
702nc_tls_server_set_key(const char *privkey, int is_rsa)
703{
704 EVP_PKEY *key;;
705
706 if (!privkey) {
707 ERRARG;
708 return -1;
709 }
710
711 if (!tls_opts.tls_ctx) {
712 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
713 if (!tls_opts.tls_ctx) {
714 ERR("%s: failed to create TLS context.", __func__);
715 return -1;
716 }
717 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
718 }
719
720 key = base64der_to_privatekey(privkey, is_rsa);
721 if (!key || (SSL_CTX_use_PrivateKey(tls_opts.tls_ctx, key) != 1)) {
722 ERR("%s: loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
723 EVP_PKEY_free(key);
724 return -1;
725 }
726 EVP_PKEY_free(key);
727
728 return 0;
729}
730
731/* PEM only */
732API int
733nc_tls_server_set_key_path(const char *privkey_path)
734{
735 if (!privkey_path) {
736 ERRARG;
737 return -1;
738 }
739
740 if (!tls_opts.tls_ctx) {
741 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
742 if (!tls_opts.tls_ctx) {
743 ERR("%s: failed to create TLS context.", __func__);
744 return -1;
745 }
746 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
747 }
748
749 if (SSL_CTX_use_PrivateKey_file(tls_opts.tls_ctx, privkey_path, SSL_FILETYPE_PEM) != 1) {
750 ERR("%s: loading the server priavte key failed (%s).", ERR_reason_error_string(ERR_get_error()));
751 return -1;
752 }
753
754 return 0;
755}
756
757API int
758nc_tls_server_add_trusted_cert(const char *cert)
759{
760 X509_STORE *cert_store;
761 X509 *x509_cert;
762
763 if (!cert) {
764 ERRARG;
765 return -1;
766 }
767
768 if (!tls_opts.tls_ctx) {
769 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
770 if (!tls_opts.tls_ctx) {
771 ERR("%s: failed to create TLS context.", __func__);
772 return -1;
773 }
774 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
775 }
776
777 cert_store = SSL_CTX_get_cert_store(tls_opts.tls_ctx);
778 if (!cert_store) {
779 cert_store = X509_STORE_new();
780 SSL_CTX_set_cert_store(tls_opts.tls_ctx, cert_store);
781 }
782
783 x509_cert = base64der_to_cert(cert);
784 if (!x509_cert || (X509_STORE_add_cert(cert_store, x509_cert) != 1)) {
785 ERR("%s: adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
786 X509_free(x509_cert);
787 return -1;
788 }
789 X509_free(x509_cert);
790
791 return 0;
792}
793
794API int
795nc_tls_server_add_trusted_cert_path(const char *cert_path)
796{
797 X509_STORE *cert_store;
798 X509 *x509_cert;
799
800 if (!cert_path) {
801 ERRARG;
802 return -1;
803 }
804
805 if (!tls_opts.tls_ctx) {
806 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
807 if (!tls_opts.tls_ctx) {
808 ERR("%s: failed to create TLS context.", __func__);
809 return -1;
810 }
811 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
812 }
813
814 cert_store = SSL_CTX_get_cert_store(tls_opts.tls_ctx);
815 if (!cert_store) {
816 cert_store = X509_STORE_new();
817 SSL_CTX_set_cert_store(tls_opts.tls_ctx, cert_store);
818 }
819
820 errno = 0;
821 x509_cert = pem_to_cert(cert_path);
822 if (!x509_cert || (X509_STORE_add_cert(cert_store, x509_cert) != 1)) {
823 ERR("%s: adding a trusted certificate failed (%s).",
824 (errno ? strerror(errno) : ERR_reason_error_string(ERR_get_error())));
825 X509_free(x509_cert);
826 return -1;
827 }
828 X509_free(x509_cert);
829
830 return 0;
831}
832
833API int
834nc_tls_server_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path)
835{
836 X509_STORE *cert_store;
837 X509_LOOKUP *lookup;
838
839 if (!cacert_file_path && !cacert_dir_path) {
840 ERRARG;
841 return -1;
842 }
843
844 if (!tls_opts.tls_ctx) {
845 tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
846 if (!tls_opts.tls_ctx) {
847 ERR("%s: failed to create TLS context.", __func__);
848 return -1;
849 }
850 SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
851 }
852
853 cert_store = SSL_CTX_get_cert_store(tls_opts.tls_ctx);
854 if (!cert_store) {
855 cert_store = X509_STORE_new();
856 SSL_CTX_set_cert_store(tls_opts.tls_ctx, cert_store);
857 }
858
859 if (cacert_file_path) {
860 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
861 if (!lookup) {
862 ERR("%s: failed to add lookup method.", __func__);
863 return -1;
864 }
865
866 if (X509_LOOKUP_load_file(lookup, cacert_file_path, X509_FILETYPE_PEM) != 1) {
867 ERR("%s: failed to add trusted cert file (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
868 return -1;
869 }
870 }
871
872 if (cacert_dir_path) {
873 lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
874 if (!lookup) {
875 ERR("%s: failed to add lookup method.", __func__);
876 return -1;
877 }
878
879 if (X509_LOOKUP_add_dir(lookup, cacert_dir_path, X509_FILETYPE_PEM) != 1) {
880 ERR("%s: failed to add trusted cert directory (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
881 return -1;
882 }
883 }
884
885 return 0;
Michal Vasko086311b2016-01-08 09:53:11 +0100886}
887
888API void
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100889nc_tls_server_destroy_certs(void)
Michal Vasko086311b2016-01-08 09:53:11 +0100890{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100891 if (!tls_opts.tls_ctx) {
892 return;
893 }
Michal Vasko086311b2016-01-08 09:53:11 +0100894
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100895 SSL_CTX_free(tls_opts.tls_ctx);
896 tls_opts.tls_ctx = NULL;
897}
898
899/* PEM hash dir */
900API int
901nc_tls_server_set_crl_locations(const char *crl_file_path, const char *crl_dir_path)
902{
903 X509_LOOKUP *lookup;
904
905 if (!crl_file_path && !crl_dir_path) {
906 ERRARG;
907 return -1;
908 }
909
910 if (!tls_opts.crl_store) {
911 tls_opts.crl_store = X509_STORE_new();
912 }
913
914 if (crl_file_path) {
915 lookup = X509_STORE_add_lookup(tls_opts.crl_store, X509_LOOKUP_file());
916 if (!lookup) {
917 ERR("%s: failed to add lookup method.", __func__);
918 return -1;
919 }
920
921 if (X509_LOOKUP_load_file(lookup, crl_file_path, X509_FILETYPE_PEM) != 1) {
922 ERR("%s: failed to add revocation lookup file (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
923 return -1;
924 }
925 }
926
927 if (crl_dir_path) {
928 lookup = X509_STORE_add_lookup(tls_opts.crl_store, X509_LOOKUP_hash_dir());
929 if (!lookup) {
930 ERR("%s: failed to add lookup method.", __func__);
931 return -1;
932 }
933
934 if (X509_LOOKUP_add_dir(lookup, crl_dir_path, X509_FILETYPE_PEM) != 1) {
935 ERR("%s: failed to add revocation lookup directory (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
936 return -1;
937 }
938 }
939
940 return 0;
941}
942
943API void
944nc_tls_server_destroy_crls(void)
945{
946 if (!tls_opts.crl_store) {
947 return;
948 }
949
950 X509_STORE_free(tls_opts.crl_store);
951 tls_opts.crl_store = NULL;
952}
953
954API int
955nc_tls_server_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
956{
957 if (!fingerprint || !map_type || ((map_type == NC_TLS_CTN_SPECIFIED) && !name)) {
958 ERRARG;
959 return -1;
960 }
961
962 ++tls_opts.ctn_count;
963 tls_opts.ctn = realloc(tls_opts.ctn, tls_opts.ctn_count * sizeof *tls_opts.ctn);
964
965 tls_opts.ctn[tls_opts.ctn_count - 1].id = id;
966 tls_opts.ctn[tls_opts.ctn_count - 1].fingerprint = lydict_insert(server_opts.ctx, fingerprint, 0);
967 tls_opts.ctn[tls_opts.ctn_count - 1].map_type = map_type;
968 tls_opts.ctn[tls_opts.ctn_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
969
970 return 0;
971}
972
973API int
974nc_tls_server_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
975{
976 uint16_t i;
977 int ret = -1;
978
979 for (i = 0; i < tls_opts.ctn_count; ++i) {
980 if (((!id < 0) || (tls_opts.ctn[i].id == id))
981 && (!fingerprint || !strcmp(tls_opts.ctn[i].fingerprint, fingerprint))
982 && (!map_type || (tls_opts.ctn[i].map_type == map_type))
983 && (!name || (tls_opts.ctn[i].name && !strcmp(tls_opts.ctn[i].name, name)))) {
984 lydict_remove(server_opts.ctx, tls_opts.ctn[i].fingerprint);
985 lydict_remove(server_opts.ctx, tls_opts.ctn[i].name);
986
987 --tls_opts.ctn_count;
988 memmove(&tls_opts.ctn[i], &tls_opts.ctn[i + 1], (tls_opts.ctn_count - i) * sizeof *tls_opts.ctn);
989
990 ret = 0;
991 }
992 }
993
994 return ret;
995}
996
997API void
998nc_tls_server_free_opts(void)
999{
1000 uint16_t i;
1001
1002 nc_tls_server_destroy_certs();
1003 nc_tls_server_destroy_crls();
1004
1005 for (i = 0; i < tls_opts.ctn_count; ++i) {
1006 lydict_remove(server_opts.ctx, tls_opts.ctn[i].fingerprint);
1007 lydict_remove(server_opts.ctx, tls_opts.ctn[i].name);
1008 }
1009 free(tls_opts.ctn);
Michal Vasko086311b2016-01-08 09:53:11 +01001010}
Michal Vasko9e036d52016-01-08 10:49:26 +01001011
1012int
1013nc_accept_tls_session(struct nc_session *session, int sock, int timeout)
1014{
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001015 int ret;
1016 struct pollfd pfd;
1017
1018 pfd.fd = sock;
1019 pfd.events = POLLIN;
1020 pfd.revents = 0;
1021
1022 /* poll for a new connection */
1023 errno = 0;
1024 ret = poll(&pfd, 1, timeout);
1025 if (!ret) {
1026 /* we timeouted */
1027 close(sock);
1028 return -1;
1029 } else if (ret == -1) {
1030 ERR("%s: poll failed (%s).", __func__, strerror(errno));
1031 close(sock);
1032 return -1;
1033 }
1034
1035 /* data waiting */
1036 session->ti_type = NC_TI_OPENSSL;
1037 session->ti.tls = SSL_new(tls_opts.tls_ctx);
1038 if (!session->ti.tls) {
1039 ERRMEM;
1040 close(sock);
1041 return -1;
1042 }
1043
1044 SSL_set_fd(session->ti.tls, sock);
1045 SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
1046
1047 /* generate new index for TLS-specific data, for the verify callback */
1048 /*netopeer_state.tls_state->last_tls_idx = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
1049 SSL_set_ex_data(new_client->tls, netopeer_state.tls_state->last_tls_idx, new_client);*/
1050 glob_session = session;
1051
1052 ret = SSL_accept(session->ti.tls);
1053 if (ret != 1) {
1054 switch (SSL_get_error(session->ti.tls, ret)) {
1055 case SSL_ERROR_SYSCALL:
1056 ERR("%s: SSL_accept failed (%s).", __func__, strerror(errno));
1057 break;
1058 case SSL_ERROR_SSL:
1059 ERR("%s: SSL_accept failed (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
1060 break;
1061 default:
1062 ERR("%s: SSL_accept failed.", __func__);
1063 break;
1064 }
1065 return -1;
1066 }
1067
1068 return 0;
Michal Vasko9e036d52016-01-08 10:49:26 +01001069}