OpenVPN
ssl_verify.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
9 * Copyright (C) 2010-2026 Sentyron B.V. <openvpn@sentyron.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "syshead.h"
34#include <string.h>
35
36#include "base64.h"
37#include "manage.h"
38#include "otime.h"
39#include "run_command.h"
40#include "ssl_verify.h"
41#include "ssl_verify_backend.h"
42
43#ifdef ENABLE_CRYPTO_OPENSSL
44#include "ssl_verify_openssl.h"
45#endif
46#include "auth_token.h"
47#include "push.h"
48#include "ssl_util.h"
49
50static void
52{
53 string_mod(str, CC_PRINT, CC_CRLF, '_');
54}
55
56/*
57 * Export the untrusted IP address and port to the environment
58 */
59static void
61{
62 setenv_link_socket_actual(session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT);
63}
64
65/*
66 * Remove authenticated state from all sessions in the given tunnel
67 */
68static void
70{
71 if (multi)
72 {
73 wipe_auth_token(multi);
74 for (int i = 0; i < TM_SIZE; ++i)
75 {
76 for (int j = 0; j < KS_SIZE; ++j)
77 {
79 }
80 }
81 }
82}
83
84void
85set_common_name(struct tls_session *session, const char *common_name)
86{
87 if (session->common_name)
88 {
89 free(session->common_name);
90 session->common_name = NULL;
91 }
92 if (common_name)
93 {
94 /* FIXME: Last alloc will never be freed */
95 session->common_name = string_alloc(common_name, NULL);
96 }
97 /* update common name in env */
98 setenv_str(session->opt->es, "common_name", common_name);
99}
100
101/*
102 * Retrieve the common name for the given tunnel's active session. If the
103 * common name is NULL or empty, return NULL if null is true, or "UNDEF" if
104 * null is false.
105 */
106const char *
107tls_common_name(const struct tls_multi *multi, const bool null)
108{
109 const char *ret = NULL;
110 if (multi)
111 {
112 ret = multi->session[TM_ACTIVE].common_name;
113 }
114 if (ret && strlen(ret))
115 {
116 return ret;
117 }
118 else if (null)
119 {
120 return NULL;
121 }
122 else
123 {
124 return "UNDEF";
125 }
126}
127
128/*
129 * Lock the common name for the given tunnel.
130 */
131void
133{
134 const char *cn = multi->session[TM_ACTIVE].common_name;
135 if (cn && !multi->locked_cn)
136 {
137 multi->locked_cn = string_alloc(cn, NULL);
138 }
139}
140
141/*
142 * Lock the username for the given tunnel
143 */
144static bool
145tls_lock_username(struct tls_multi *multi, const char *username)
146{
147 if (multi->locked_username)
148 {
149 /* If the username has been overridden, we accept both the original
150 * username and the changed username */
151 if (strcmp(username, multi->locked_username) != 0
152 && (!multi->locked_original_username
153 || strcmp(username, multi->locked_original_username) != 0))
154 {
156 "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
157 multi->locked_username, username);
158
159 /* disable the tunnel */
160 tls_deauthenticate(multi);
161 return false;
162 }
163 }
164 else
165 {
166 multi->locked_username = string_alloc(username, NULL);
167 }
168 return true;
169}
170
171const char *
172tls_username(const struct tls_multi *multi, const bool null)
173{
174 const char *ret = NULL;
175 if (multi)
176 {
177 ret = multi->locked_username;
178 }
179 if (ret && strlen(ret))
180 {
181 return ret;
182 }
183 else if (null)
184 {
185 return NULL;
186 }
187 else
188 {
189 return "UNDEF";
190 }
191}
192
193void
194cert_hash_remember(struct tls_session *session, const int error_depth,
195 const struct buffer *cert_hash)
196{
197 if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH)
198 {
199 if (!session->cert_hash_set)
200 {
201 ALLOC_OBJ_CLEAR(session->cert_hash_set, struct cert_hash_set);
202 }
203 if (!session->cert_hash_set->ch[error_depth])
204 {
205 ALLOC_OBJ(session->cert_hash_set->ch[error_depth], struct cert_hash);
206 }
207
208 struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
209 ASSERT(sizeof(ch->sha256_hash) == BLEN(cert_hash));
210 memcpy(ch->sha256_hash, BPTR(cert_hash), sizeof(ch->sha256_hash));
211 }
212}
213
214void
216{
217 if (chs)
218 {
219 int i;
220 for (i = 0; i < MAX_CERT_DEPTH; ++i)
221 {
222 free(chs->ch[i]);
223 }
224 free(chs);
225 }
226}
227
228bool
229cert_hash_compare(const struct cert_hash_set *chs1, const struct cert_hash_set *chs2)
230{
231 if (chs1 && chs2)
232 {
233 int i;
234 for (i = 0; i < MAX_CERT_DEPTH; ++i)
235 {
236 const struct cert_hash *ch1 = chs1->ch[i];
237 const struct cert_hash *ch2 = chs2->ch[i];
238
239 if (!ch1 && !ch2)
240 {
241 continue;
242 }
243 else if (ch1 && ch2
244 && !memcmp(ch1->sha256_hash, ch2->sha256_hash, sizeof(ch1->sha256_hash)))
245 {
246 continue;
247 }
248 else
249 {
250 return false;
251 }
252 }
253 return true;
254 }
255 else if (!chs1 && !chs2)
256 {
257 return true;
258 }
259 else
260 {
261 return false;
262 }
263}
264
265static struct cert_hash_set *
267{
268 struct cert_hash_set *dest = NULL;
269 if (chs)
270 {
271 int i;
272 ALLOC_OBJ_CLEAR(dest, struct cert_hash_set);
273 for (i = 0; i < MAX_CERT_DEPTH; ++i)
274 {
275 const struct cert_hash *ch = chs->ch[i];
276 if (ch)
277 {
278 ALLOC_OBJ(dest->ch[i], struct cert_hash);
279 memcpy(dest->ch[i]->sha256_hash, ch->sha256_hash, sizeof(dest->ch[i]->sha256_hash));
280 }
281 }
282 }
283 return dest;
284}
285void
287{
288 const struct cert_hash_set *chs = multi->session[TM_ACTIVE].cert_hash_set;
289 if (chs && !multi->locked_cert_hash_set)
290 {
292 }
293}
294
295/*
296 * Returns the string associated with the given certificate type.
297 */
298static const char *
300{
301 switch (type)
302 {
304 return "SERVER";
305
307 return "CLIENT";
308
309 default:
310 return "?";
311 }
312}
313
314/*
315 * Verify the peer's certificate fields.
316 *
317 * @param opt the tls options to verify against
318 * @param peer_cert the peer's certificate
319 * @param subject the peer's extracted subject name
320 * @param subject the peer's extracted common name
321 */
322static result_t
323verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, const char *subject,
324 const char *common_name)
325{
326 /* verify certificate nsCertType */
328 {
329 if (SUCCESS == x509_verify_ns_cert_type(peer_cert, opt->ns_cert_type))
330 {
331 msg(D_HANDSHAKE, "VERIFY OK: nsCertType=%s", print_nsCertType(opt->ns_cert_type));
332 }
333 else
334 {
335 msg(D_HANDSHAKE, "VERIFY nsCertType ERROR: %s, require nsCertType=%s", subject,
337 return FAILURE; /* Reject connection */
338 }
339 }
340
341 /* verify certificate ku */
342 if (opt->remote_cert_ku[0] != 0)
343 {
344 if (SUCCESS == x509_verify_cert_ku(peer_cert, opt->remote_cert_ku, MAX_PARMS))
345 {
346 msg(D_HANDSHAKE, "VERIFY KU OK");
347 }
348 else
349 {
350 msg(D_HANDSHAKE, "VERIFY KU ERROR");
351 return FAILURE; /* Reject connection */
352 }
353 }
354
355 /* verify certificate eku */
356 if (opt->remote_cert_eku != NULL)
357 {
358 if (SUCCESS == x509_verify_cert_eku(peer_cert, opt->remote_cert_eku))
359 {
360 msg(D_HANDSHAKE, "VERIFY EKU OK");
361 }
362 else
363 {
364 msg(D_HANDSHAKE, "VERIFY EKU ERROR");
365 return FAILURE; /* Reject connection */
366 }
367 }
368
369 /* verify X509 name or username against --verify-x509-[user]name */
371 {
372 const char *err_fmt = "VERIFY X509NAME ERROR: %s, must be %s";
373 const char *match_str = common_name;
374 bool verified = false;
375 switch (opt->verify_x509_type)
376 {
378 match_str = subject;
379 verified = !strcmp(opt->verify_x509_name, match_str);
380 break;
382 verified = !strcmp(opt->verify_x509_name, match_str);
383 break;
385 err_fmt = "VERIFY X509NAME ERROR: %s, must start with %s";
386 verified = !strncmp(opt->verify_x509_name, match_str, strlen(opt->verify_x509_name));
387 break;
388 default:
389 ASSERT(0); /* should not happen */
390 break;
391 }
392 if (!verified)
393 {
394 msg(D_HANDSHAKE, err_fmt, match_str, opt->verify_x509_name);
395 return FAILURE;
396 }
397 msg(D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject);
398 }
399
400 return SUCCESS;
401}
402
403/*
404 * Export the subject, common_name, and raw certificate fields to the
405 * environment for later verification by scripts and plugins.
406 */
407static void
408verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth,
409 const char *subject, const struct x509_track *x509_track)
410{
411 char envname[64];
412 char *serial = NULL;
413 struct gc_arena gc = gc_new();
414
415 /* Save X509 fields in environment */
416 if (x509_track)
417 {
418 x509_setenv_track(x509_track, es, cert_depth, peer_cert);
419 }
420 else
421 {
422 x509_setenv(es, cert_depth, peer_cert);
423 }
424
425 /* export subject name string as environmental variable */
426 snprintf(envname, sizeof(envname), "tls_id_%d", cert_depth);
427 setenv_str(es, envname, subject);
428
429 /* export X509 cert fingerprints */
430 {
433
434 snprintf(envname, sizeof(envname), "tls_digest_%d", cert_depth);
435 setenv_str(es, envname, format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc));
436
437 snprintf(envname, sizeof(envname), "tls_digest_sha256_%d", cert_depth);
438 setenv_str(es, envname, format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc));
439 }
440
441 /* export serial number as environmental variable */
443 snprintf(envname, sizeof(envname), "tls_serial_%d", cert_depth);
445
446 /* export serial number in hex as environmental variable */
448 snprintf(envname, sizeof(envname), "tls_serial_hex_%d", cert_depth);
450
451 gc_free(&gc);
452}
453
458static bool
460 const char *pem_export_fname)
461{
462 /* export the path to the current certificate in pem file format */
463 setenv_str(es, "peer_cert", pem_export_fname);
464
466}
467
468static void
470{
471 env_set_del(es, "peer_cert");
473 {
475 }
476}
477
478/*
479 * call --tls-verify plug-in(s)
480 */
481static result_t
482verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es, int cert_depth,
483 openvpn_x509_cert_t *cert, char *subject)
484{
486 {
487 int ret;
488 struct argv argv = argv_new();
489
490 argv_printf(&argv, "%d %s", cert_depth, subject);
491
492 ret =
493 plugin_call_ssl(plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert);
494
495 argv_free(&argv);
496
497 if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
498 {
499 msg(D_HANDSHAKE, "VERIFY PLUGIN OK: depth=%d, %s", cert_depth, subject);
500 }
501 else
502 {
503 msg(D_HANDSHAKE, "VERIFY PLUGIN ERROR: depth=%d, %s", cert_depth, subject);
504 return FAILURE; /* Reject connection */
505 }
506 }
507 return SUCCESS;
508}
509
510/*
511 * run --tls-verify script
512 */
513static result_t
514verify_cert_call_command(const char *verify_command, struct env_set *es, int cert_depth,
515 char *subject)
516{
517 int ret;
518 struct gc_arena gc = gc_new();
519 struct argv argv = argv_new();
520
521 setenv_str(es, "script_type", "tls-verify");
522
523 argv_parse_cmd(&argv, verify_command);
524 argv_printf_cat(&argv, "%d %s", cert_depth, subject);
525
526 argv_msg_prefix(D_TLS_DEBUG, &argv, "TLS: executing verify command");
527 ret = openvpn_run_script(&argv, es, 0, "--tls-verify script");
528
529 gc_free(&gc);
530 argv_free(&argv);
531
532 if (ret)
533 {
534 msg(D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s", cert_depth, subject);
535 return SUCCESS;
536 }
537
538 msg(D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s", cert_depth, subject);
539 return FAILURE; /* Reject connection */
540}
541
542/*
543 * check peer cert against CRL directory
544 */
545static result_t
546verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert, const char *subject,
547 int cert_depth)
548{
549 result_t ret = FAILURE;
550 char fn[256];
551 int fd = -1;
552 struct gc_arena gc = gc_new();
553
554 char *serial = backend_x509_get_serial(cert, &gc);
555 if (!serial)
556 {
557 msg(D_HANDSHAKE, "VERIFY CRL: depth=%d, %s, serial number is not available", cert_depth,
558 subject);
559 goto cleanup;
560 }
561
562 if (!checked_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, PATH_SEPARATOR, serial))
563 {
564 msg(D_HANDSHAKE, "VERIFY CRL: filename overflow");
565 goto cleanup;
566 }
567 fd = platform_open(fn, O_RDONLY, 0);
568 if (fd >= 0)
569 {
570 msg(D_HANDSHAKE, "VERIFY CRL: depth=%d, %s, serial=%s is revoked", cert_depth, subject,
571 serial);
572 goto cleanup;
573 }
574
575 ret = SUCCESS;
576
577cleanup:
578
579 if (fd != -1)
580 {
581 close(fd);
582 }
583 gc_free(&gc);
584 return ret;
585}
586
588verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth)
589{
590 /* need to define these variables here so goto cleanup will always have
591 * them defined */
592 result_t ret = FAILURE;
593 struct gc_arena gc = gc_new();
594 const char *pem_export_fname = NULL;
595
596 const struct tls_options *opt = session->opt;
597 ASSERT(opt);
598
599 session->verified = false;
600
601 /* get the X509 name */
602 char *subject = x509_get_subject(cert, &gc);
603 if (!subject)
604 {
606 "VERIFY ERROR: depth=%d, could not extract X509 "
607 "subject string from certificate",
608 cert_depth);
609 goto cleanup;
610 }
611
612 /* enforce character class restrictions in X509 name */
613 string_mod_remap_name(subject);
614 string_replace_leading(subject, '-', '_');
615
616 /* extract the username (default is CN) */
617 struct buffer buf = alloc_buf_gc(256, &gc);
618 for (int i = 0; opt->x509_username_field[i] != NULL; i++)
619 {
620 char username[TLS_USERNAME_LEN + 1] = { 0 }; /* null-terminated */
621
622 if (SUCCESS
623 != backend_x509_get_username(username, sizeof(username), opt->x509_username_field[i],
624 cert))
625 {
626 if (!cert_depth)
627 {
629 "VERIFY ERROR: could not extract %s from X509 "
630 "subject string ('%s') -- note that the field length is "
631 "limited to %d characters",
633 goto cleanup;
634 }
635 break;
636 }
637 if (!buf_printf(&buf, i ? "_%s" : "%s", username))
638 {
639 if (!cert_depth)
640 {
642 "VERIFY ERROR: could not append %s from X509 "
643 "certificate -- note that the username length is "
644 "limited to %d characters",
645 opt->x509_username_field[i], buf.capacity - 1);
646 goto cleanup;
647 }
648 break;
649 }
650 }
651
652 char *common_name = BSTR(&buf);
653 if (!common_name)
654 {
656 "VERIFY ERROR: depth=%d, could not extract X509 "
657 "username string from certificate",
658 cert_depth);
659 goto cleanup;
660 }
661
662 /* enforce character class restrictions in common name */
663 string_mod_remap_name(common_name);
664
665 /* warn if cert chain is too deep */
667 {
669 "TLS Error: Convoluted certificate chain detected with depth [%d] greater than %d",
671 goto cleanup; /* Reject connection */
672 }
673
674 if (cert_depth == opt->verify_hash_depth && opt->verify_hash)
675 {
676 struct buffer cert_fp = { 0 };
677
678 switch (opt->verify_hash_algo)
679 {
680 case MD_SHA1:
682 break;
683
684 case MD_SHA256:
686 break;
687
688 default:
689 /* This should normally not happen at all; the algorithm used
690 * is parsed by add_option() [options.c] and set to a predefined
691 * value in an enumerated type. So if this unlikely scenario
692 * happens, consider this a failure
693 */
694 msg(M_WARN,
695 "Unexpected invalid algorithm used with "
696 "--verify-hash (%i)",
697 opt->verify_hash_algo);
698 ret = FAILURE;
699 goto cleanup;
700 }
701
702 struct verify_hash_list *current_hash = opt->verify_hash;
703
704 while (current_hash)
705 {
706 if (memcmp_constant_time(BPTR(&cert_fp), current_hash->hash, BLENZ(&cert_fp)) == 0)
707 {
708 break;
709 }
710 current_hash = current_hash->next;
711 }
712
713 if (!current_hash)
714 {
715 const char *hex_fp = format_hex_ex(BPTR(&cert_fp), BLEN(&cert_fp), 0, 1, ":", &gc);
717 "TLS Error: --tls-verify/--peer-fingerprint "
718 "certificate hash verification failed. (got certificate "
719 "fingerprint: %s)",
720 hex_fp);
721 goto cleanup;
722 }
723 }
724
725 /* save common name in session object */
726 if (cert_depth == 0)
727 {
728 set_common_name(session, common_name);
729 }
730
731 session->verify_maxlevel = max_int(session->verify_maxlevel, cert_depth);
732
733 if (opt->export_peer_cert_dir)
734 {
735 pem_export_fname = platform_create_temp_file(opt->export_peer_cert_dir, "pef", &gc);
736
737 if (!pem_export_fname || !verify_cert_cert_export_env(opt->es, cert, pem_export_fname))
738 {
740 "TLS Error: Failed to export certificate for "
741 "--tls-export-cert in %s",
743 goto cleanup;
744 }
745 }
746 /* export certificate values to the environment */
747 verify_cert_set_env(opt->es, cert, cert_depth, subject, opt->x509_track);
748
749 /* export current untrusted IP */
751
752 /* If this is the peer's own certificate, verify it */
753 if (cert_depth == 0 && SUCCESS != verify_peer_cert(opt, cert, subject, common_name))
754 {
755 goto cleanup;
756 }
757
758 /* call --tls-verify plug-in(s), if registered */
759 if (SUCCESS != verify_cert_call_plugin(opt->plugins, opt->es, cert_depth, cert, subject))
760 {
761 goto cleanup;
762 }
763
764 /* run --tls-verify script */
765 if (opt->verify_command
766 && SUCCESS != verify_cert_call_command(opt->verify_command, opt->es, cert_depth, subject))
767 {
768 goto cleanup;
769 }
770
771 /* check peer cert against CRL */
772 if (opt->crl_file)
773 {
775 {
776 if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert, subject, cert_depth))
777 {
778 goto cleanup;
779 }
780 }
781 else
782 {
783 if (tls_verify_crl_missing(opt))
784 {
785 msg(D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded");
786 goto cleanup;
787 }
788 }
789 }
790
791 msg(D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject);
792 session->verified = true;
793 ret = SUCCESS;
794
795cleanup:
796 verify_cert_cert_delete_env(opt->es, pem_export_fname);
797 if (ret != SUCCESS)
798 {
799 tls_clear_error(); /* always? */
800 session->verified = false; /* double sure? */
801 }
802
803 gc_free(&gc);
804
805 return ret;
806}
807
808/* ***************************************************************************
809 * Functions for the management of deferred authentication when using
810 * user/password authentication.
811 *************************************************************************** */
812
813void
814auth_set_client_reason(struct tls_multi *multi, const char *client_reason)
815{
816 free(multi->client_reason);
817 multi->client_reason = NULL;
818
819 if (client_reason && strlen(client_reason))
820 {
821 multi->client_reason = string_alloc(client_reason, NULL);
822 }
823}
824
825#ifdef ENABLE_MANAGEMENT
826
827static inline enum auth_deferred_result
829{
831 {
832 return ks->mda_status;
833 }
834 else
835 {
836 return ACF_DISABLED;
837 }
838}
839#endif /* ifdef ENABLE_MANAGEMENT */
840
845static void
847{
848 if (ads && ads->auth_pending_file)
849 {
851 free(ads->auth_pending_file);
852 ads->auth_pending_file = NULL;
853 }
854}
855
859static bool
860check_auth_pending_method(const char *peer_info, const char *method)
861{
862 struct gc_arena gc = gc_new();
863
864 char *iv_sso = extract_var_peer_info(peer_info, "IV_SSO=", &gc);
865 if (!iv_sso)
866 {
867 gc_free(&gc);
868 return false;
869 }
870
871 char *lasts = NULL;
872 const char *client_method = strtok_r(iv_sso, ",", &lasts);
873 bool supported = false;
874
875 while (client_method)
876 {
877 if (0 == strcmp(client_method, method))
878 {
879 supported = true;
880 break;
881 }
882 client_method = strtok_r(NULL, ",", &lasts);
883 }
884
885 gc_free(&gc);
886 return supported;
887}
888
897static bool
899 struct tls_multi *multi,
900 struct tls_session *session)
901{
902 bool ret = true;
903 if (ads->auth_pending_file)
904 {
905 struct buffer_list *lines = buffer_list_file(ads->auth_pending_file, 1024);
906 if (lines && lines->head)
907 {
908 /* Must have at least three lines. further lines are ignored for
909 * forward compatibility */
910 if (!lines->head->next || !lines->head->next->next)
911 {
912 msg(M_WARN, "auth pending control file is not at least "
913 "three lines long.");
914 buffer_list_free(lines);
915 return false;
916 }
917 struct buffer *timeout_buf = &lines->head->buf;
918 struct buffer *iv_buf = &lines->head->next->buf;
919 struct buffer *extra_buf = &lines->head->next->next->buf;
920
921 /* Remove newline chars at the end of the lines */
925
926 errno = 0;
927 long timeout = strtol(BSTR(timeout_buf), NULL, 10);
928 if (timeout <= 0 || (unsigned long)timeout > UINT_MAX || errno)
929 {
930 msg(M_WARN, "could not parse auth pending file timeout");
932 return false;
933 }
934
935 const char *pending_method = BSTR(iv_buf);
937 {
938 char buf[128];
939 snprintf(buf, sizeof(buf),
940 "Authentication failed, required pending auth "
941 "method '%s' not supported",
943 auth_set_client_reason(multi, buf);
944 msg(M_INFO,
945 "Client does not supported auth pending method '%s'",
947 ret = false;
948 }
949 else
950 {
952 (unsigned int)timeout);
953 }
954 }
955
957 }
959 return ret;
960}
961
966void
968{
969 if (ads->auth_control_file)
970 {
971 platform_unlink(ads->auth_control_file);
972 free(ads->auth_control_file);
973 ads->auth_control_file = NULL;
974 }
975 if (ads->auth_failed_reason_file)
976 {
977 platform_unlink(ads->auth_failed_reason_file);
978 free(ads->auth_failed_reason_file);
979 ads->auth_failed_reason_file = NULL;
980 }
982}
983
990static bool
992{
993 struct gc_arena gc = gc_new();
994
996 const char *acf = platform_create_temp_file(opt->tmp_dir, "acf", &gc);
997 const char *apf = platform_create_temp_file(opt->tmp_dir, "apf", &gc);
998 const char *afr = platform_create_temp_file(opt->tmp_dir, "afr", &gc);
999
1000 if (acf && apf && afr)
1001 {
1002 ads->auth_control_file = string_alloc(acf, NULL);
1003 ads->auth_pending_file = string_alloc(apf, NULL);
1004 ads->auth_failed_reason_file = string_alloc(afr, NULL);
1005
1006 setenv_str(opt->es, "auth_control_file", ads->auth_control_file);
1007 setenv_str(opt->es, "auth_pending_file", ads->auth_pending_file);
1008 setenv_str(opt->es, "auth_failed_reason_file", ads->auth_failed_reason_file);
1009 }
1010
1011 gc_free(&gc);
1012 return (acf && apf && afr);
1013}
1014
1019static char *
1021 struct gc_arena *gc)
1022{
1023 char *ret = NULL;
1024 if (ads->auth_failed_reason_file)
1025 {
1026 struct buffer reason = buffer_read_from_file(ads->auth_failed_reason_file, gc);
1027
1028 if (BLEN(&reason))
1029 {
1030 ret = BSTR(&reason);
1031 }
1032 }
1033 return ret;
1034}
1035
1036
1047static enum auth_deferred_result
1049{
1050 if (ads->auth_control_file)
1051 {
1052 unsigned int ret = ads->auth_control_status;
1053 if (ret == ACF_PENDING && !cached)
1054 {
1055 FILE *fp = fopen(ads->auth_control_file, "r");
1056 if (fp)
1057 {
1058 const int c = fgetc(fp);
1059 if (c == '1')
1060 {
1062 }
1063 else if (c == '0')
1064 {
1065 ret = ACF_FAILED;
1066 }
1067 fclose(fp);
1068 ads->auth_control_status = ret;
1069 }
1070 }
1071 return ret;
1072 }
1073 return ACF_DISABLED;
1074}
1075
1083static void
1085{
1086 if (ks->authenticated == KS_AUTH_FALSE)
1087 {
1088 return;
1089 }
1090 else
1091 {
1097#ifdef ENABLE_MANAGEMENT
1099#endif
1100 ASSERT(auth_plugin < 4 && auth_script < 4 && auth_man < 4);
1101
1103 {
1105 return;
1106 }
1108 || auth_man == ACF_PENDING)
1109 {
1110 if (now >= ks->auth_deferred_expire)
1111 {
1112 /* Window to authenticate the key has expired, mark
1113 * the key as unauthenticated */
1115 }
1116 }
1117 else
1118 {
1119 /* all auth states (auth_plugin, auth_script, auth_man)
1120 * are either ACF_DISABLED or ACF_SUCCEDED now, which
1121 * translates to "not checked" or "auth succeeded"
1122 */
1124 }
1125 }
1126}
1127
1128
1135static time_t cache_intervals[] = { 0, 0, 0, 0, 0, 1, 1, 2, 2, 4, 8 };
1136
1141static bool
1143{
1144 unsigned int idx = min_uint(multi->tas_cache_num_updates, SIZE(cache_intervals) - 1);
1146 return multi->tas_cache_last_update + latency >= now;
1147}
1148
1149enum tls_auth_status
1151{
1152 bool deferred = false;
1153
1154 /* at least one valid key has successfully completed authentication */
1155 bool success = false;
1156
1157 /* at least one key is enabled for decryption */
1158 int active = 0;
1159
1160 /* at least one key already failed authentication */
1161 bool failed_auth = false;
1162
1164
1165 for (int i = 0; i < KEY_SCAN_SIZE; ++i)
1166 {
1167 struct key_state *ks = get_key_scan(multi, i);
1168 if (TLS_AUTHENTICATED(multi, ks))
1169 {
1170 active++;
1171 update_key_auth_status(cached, ks);
1172
1173 if (ks->authenticated == KS_AUTH_FALSE)
1174 {
1175 failed_auth = true;
1176 }
1177 else if (ks->authenticated == KS_AUTH_DEFERRED)
1178 {
1179 deferred = true;
1180 }
1181 else if (ks->authenticated == KS_AUTH_TRUE)
1182 {
1183 success = true;
1184 }
1185 }
1186 }
1187
1188 /* we did not rely on a cached result, remember the cache update time */
1189 if (!cached)
1190 {
1191 multi->tas_cache_last_update = now;
1192 multi->tas_cache_num_updates++;
1193 }
1194
1195#if 0
1196 dmsg(D_TLS_ERRORS, "TAS: a=%d s=%d d=%d f=%d", active, success, deferred, failed_auth);
1197#endif
1198 if (failed_auth)
1199 {
1200 struct gc_arena gc = gc_new();
1201 const struct key_state *ks = get_primary_key(multi);
1202 const char *plugin_message =
1204 const char *script_message =
1206
1207 if (plugin_message)
1208 {
1209 auth_set_client_reason(multi, plugin_message);
1210 }
1211 if (script_message)
1212 {
1213 auth_set_client_reason(multi, script_message);
1214 }
1215
1216 /* We have at least one session that failed authentication. There
1217 * might be still another session with valid keys.
1218 * Although our protocol allows keeping the VPN session alive
1219 * with the other session (and we actually did that in earlier
1220 * version, this behaviour is really strange from a user (admin)
1221 * experience */
1222 gc_free(&gc);
1224 }
1225 else if (success)
1226 {
1228 }
1229 else if (active == 0 || deferred)
1230 {
1231 /* We have a deferred authentication and no currently active key
1232 * (first auth, no renegotiation) */
1234 }
1235 else
1236 {
1237 /* at least one key is active but none is fully authenticated (!success)
1238 * and all active are either failed authed or expired deferred auth */
1240 }
1241}
1242
1243#ifdef ENABLE_MANAGEMENT
1244/*
1245 * For deferred auth, this is where the management interface calls (on server)
1246 * to indicate auth failure/success.
1247 */
1248bool
1249tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, const bool auth,
1250 const char *client_reason)
1251{
1252 bool ret = false;
1253 if (multi)
1254 {
1255 int i;
1256 auth_set_client_reason(multi, client_reason);
1257 for (i = 0; i < KEY_SCAN_SIZE; ++i)
1258 {
1259 struct key_state *ks = get_key_scan(multi, i);
1260 if (ks->mda_key_id == mda_key_id)
1261 {
1262 ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
1263 ret = true;
1264 }
1265 }
1266 }
1267 return ret;
1268}
1269#endif /* ifdef ENABLE_MANAGEMENT */
1270
1271
1272/* ****************************************************************************
1273 * Functions to verify username and password
1274 *
1275 * Authenticate a client using username/password.
1276 * Runs on server.
1277 *
1278 * If you want to add new authentication methods,
1279 * this is the place to start.
1280 *************************************************************************** */
1281
1285static void
1287{
1288 struct gc_arena gc = gc_new();
1290 if (msg)
1291 {
1293 }
1294 gc_free(&gc);
1295}
1296/*
1297 * Verify the user name and password using a script
1298 */
1299static int
1301 const struct user_pass *up)
1302{
1303 struct gc_arena gc = gc_new();
1304 struct argv argv = argv_new();
1305 const char *tmp_file = "";
1306 int retval = OPENVPN_PLUGIN_FUNC_ERROR;
1307 struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
1308
1309 /* Set environmental variables prior to calling script */
1310 setenv_str(session->opt->es, "script_type", "user-pass-verify");
1311
1312 /* format command line */
1313 argv_parse_cmd(&argv, session->opt->auth_user_pass_verify_script);
1314
1315 if (session->opt->auth_user_pass_verify_script_via_file)
1316 {
1317 struct status_output *so;
1318
1319 tmp_file = platform_create_temp_file(session->opt->tmp_dir, "up", &gc);
1320 if (tmp_file)
1321 {
1322 so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
1323 status_printf(so, "%s", up->username);
1324 status_printf(so, "%s", up->password);
1325 if (!status_close(so))
1326 {
1327 msg(D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
1328 tmp_file);
1329 goto done;
1330 }
1331 /* pass temp file name to script */
1332 argv_printf_cat(&argv, "%s", tmp_file);
1333 }
1334 }
1335 else
1336 {
1337 /* username env is already set by set_verify_user_pass_env */
1338 setenv_str(session->opt->es, "password", up->password);
1339 }
1340
1341 /* pre-create files for deferred auth control */
1343 {
1345 "TLS Auth Error (%s): "
1346 "could not create deferred auth control file",
1347 __func__);
1348 retval = OPENVPN_PLUGIN_FUNC_ERROR;
1349 goto error;
1350 }
1351
1352 /* call command */
1353 int script_ret =
1354 openvpn_run_script(&argv, session->opt->es, S_EXITCODE, "--auth-user-pass-verify");
1355 switch (script_ret)
1356 {
1357 case 0:
1358 retval = OPENVPN_PLUGIN_FUNC_SUCCESS;
1359 break;
1360
1361 case 2:
1362 retval = OPENVPN_PLUGIN_FUNC_DEFERRED;
1363 break;
1364
1365 default:
1367 retval = OPENVPN_PLUGIN_FUNC_ERROR;
1368 break;
1369 }
1370 if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED)
1371 {
1372 /* Check if we the plugin has written the pending auth control
1373 * file and send the pending auth to the client */
1375 {
1376 retval = OPENVPN_PLUGIN_FUNC_ERROR;
1378 }
1379 }
1380 else
1381 {
1382 /* purge auth control filename (and file itself) for non-deferred returns */
1384 }
1385
1386done:
1387 if (tmp_file && strlen(tmp_file) > 0)
1388 {
1389 platform_unlink(tmp_file);
1390 }
1391
1392error:
1393 if (!session->opt->auth_user_pass_verify_script_via_file)
1394 {
1395 setenv_del(session->opt->es, "password");
1396 }
1397
1398 argv_free(&argv);
1399 gc_free(&gc);
1400 return retval;
1401}
1402
1403#ifdef ENABLE_PLUGIN
1404void
1405verify_crresponse_plugin(struct tls_multi *multi, const char *cr_response)
1406{
1407 struct tls_session *session = &multi->session[TM_ACTIVE];
1408 setenv_str(session->opt->es, "crresponse", cr_response);
1409
1410 plugin_call(session->opt->plugins, OPENVPN_PLUGIN_CLIENT_CRRESPONSE, NULL, NULL,
1411 session->opt->es);
1412
1413 setenv_del(session->opt->es, "crresponse");
1414}
1415#endif
1416
1417void
1418verify_crresponse_script(struct tls_multi *multi, const char *cr_response)
1419{
1420 struct tls_session *session = &multi->session[TM_ACTIVE];
1421
1422 if (!session->opt->client_crresponse_script)
1423 {
1424 return;
1425 }
1426 struct argv argv = argv_new();
1427 struct gc_arena gc = gc_new();
1428
1429 setenv_str(session->opt->es, "script_type", "client-crresponse");
1430
1431 /* Since cr response might be sensitive, like a stupid way to query
1432 * a password via 2FA, we pass it via file instead environment */
1433 const char *tmp_file = platform_create_temp_file(session->opt->tmp_dir, "cr", &gc);
1434 static const char *openerrmsg = "TLS CR Response Error: could not write "
1435 "crtext challenge response to file: %s";
1436
1437 if (tmp_file)
1438 {
1439 struct status_output *so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
1440 status_printf(so, "%s", cr_response);
1441 if (!status_close(so))
1442 {
1443 msg(D_TLS_ERRORS, openerrmsg, tmp_file);
1444 tls_deauthenticate(multi);
1445 goto done;
1446 }
1447 }
1448 else
1449 {
1450 msg(D_TLS_ERRORS, openerrmsg, "creating file failed");
1451 tls_deauthenticate(multi);
1452 goto done;
1453 }
1454
1455 argv_parse_cmd(&argv, session->opt->client_crresponse_script);
1456 argv_printf_cat(&argv, "%s", tmp_file);
1457
1458
1459 if (!openvpn_run_script(&argv, session->opt->es, 0, "--client-crresponse"))
1460 {
1461 tls_deauthenticate(multi);
1462 }
1463done:
1464 argv_free(&argv);
1465 gc_free(&gc);
1466}
1467
1468/*
1469 * Verify the username and password using a plugin
1470 */
1471static int
1473 const struct user_pass *up)
1474{
1475 int retval = OPENVPN_PLUGIN_FUNC_ERROR;
1476 struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
1477
1478 /* set password in private env space */
1479 setenv_str(session->opt->es, "password", up->password);
1480
1481 /* generate filename for deferred auth control file */
1483 {
1485 "TLS Auth Error (%s): "
1486 "could not create deferred auth control file",
1487 __func__);
1488 return retval;
1489 }
1490
1491 /* call command */
1492 retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL,
1493 session->opt->es);
1494
1495 if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED)
1496 {
1497 /* Check if the plugin has written the pending auth control
1498 * file and send the pending auth to the client */
1500 {
1501 retval = OPENVPN_PLUGIN_FUNC_ERROR;
1502 }
1503 }
1504
1505 if (retval == OPENVPN_PLUGIN_FUNC_ERROR)
1506 {
1508 }
1509
1510 if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
1511 {
1512 /* purge auth control filename (and file itself) for non-deferred returns */
1514 }
1515
1516 setenv_del(session->opt->es, "password");
1517
1518 return retval;
1519}
1520
1521
1522#ifdef ENABLE_MANAGEMENT
1523/*
1524 * management deferred internal ssl_verify.c status codes
1525 */
1526#define KMDA_ERROR 0
1527#define KMDA_SUCCESS 1
1528#define KMDA_UNDEF 2
1529#define KMDA_DEF 3
1530
1531static int
1533{
1534 int retval = KMDA_ERROR;
1535 struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
1536
1537 /* set username/password in private env space */
1538 setenv_str(session->opt->es, "password", up->password);
1539
1540 if (management)
1541 {
1543 session->opt->es);
1544 }
1545
1546 setenv_del(session->opt->es, "password");
1547
1548 retval = KMDA_SUCCESS;
1549
1550 return retval;
1551}
1552#endif /* ifdef ENABLE_MANAGEMENT */
1553
1554static bool
1556{
1557 /* Is username defined? */
1558 if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username))
1559 {
1560 setenv_str(session->opt->es, "username", up->username);
1561
1562 /* setenv incoming cert common name for script */
1563 setenv_str(session->opt->es, "common_name", session->common_name);
1564
1565 /* setenv client real IP address */
1567
1568 /*
1569 * if we are using auth-gen-token, send also the session id of auth gen token to
1570 * allow the management to figure out if it is a new session or a continued one
1571 */
1572 add_session_token_env(session, multi, up);
1573 return true;
1574 }
1575 else
1576 {
1577 msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
1578 return false;
1579 }
1580}
1581
1582bool
1583ssl_verify_username_length(struct tls_session *session, const char *username)
1584{
1585 if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)
1586 && strlen(username) > TLS_USERNAME_LEN)
1587 {
1589 "TLS Auth Error: --username-as-common name specified and "
1590 "username is longer than the maximum permitted Common Name "
1591 "length of %d characters",
1593 return false;
1594 }
1595 else
1596 {
1597 return true;
1598 }
1599}
1600
1607void
1608verify_user_pass(struct user_pass *up, struct tls_multi *multi, struct tls_session *session)
1609{
1610 struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
1611
1612 ASSERT(up && !up->protected);
1613
1614#ifdef ENABLE_MANAGEMENT
1615 int man_def_auth = KMDA_UNDEF;
1616
1618 {
1619 man_def_auth = KMDA_DEF;
1620 }
1621#endif
1622
1623 /* enforce character class restrictions in username/password */
1625 string_mod(up->password, CC_PRINT, CC_CRLF, '_');
1626
1627 /*
1628 * If auth token succeeds we skip the auth
1629 * methods unless otherwise specified
1630 */
1631 bool skip_auth = false;
1632
1633 /* Replace username early if override-username is in effect but only
1634 * if client is sending the original username */
1635 if (multi->locked_original_username
1636 && strncmp(up->username, multi->locked_original_username, sizeof(up->username)) == 0)
1637 {
1639 "TLS: Replacing client provided username '%s' with "
1640 "username from override-user '%s'",
1641 up->username, multi->locked_username);
1642 strncpy(up->username, multi->locked_username, sizeof(up->username));
1643 }
1644
1645 /*
1646 * If server is configured with --auth-gen-token and the client sends
1647 * something that looks like an authentication token, this
1648 * round will be done internally using the token instead of
1649 * calling any external authentication modules.
1650 */
1651 if (session->opt->auth_token_generate && is_auth_token(up->password))
1652 {
1654
1655 /* If this is a valid token and the first time we see an auth-token
1656 * in this multi session, save it as initial auth token. This ensures
1657 * using the same session ID and initial timestamp in new tokens */
1659 {
1660 multi->auth_token_initial = strdup(up->password);
1661 }
1662
1663 if (session->opt->auth_token_call_auth)
1664 {
1665 /*
1666 * we do not care about the result here because it is
1667 * the responsibility of the external authentication to
1668 * decide what to do with the result
1669 */
1670 }
1672 {
1673 /*
1674 * We do not want the EXPIRED or EMPTY USER flags here so check
1675 * for equality with AUTH_TOKEN_HMAC_OK
1676 */
1677 msg(M_WARN,
1678 "TLS: Username/auth-token authentication "
1679 "succeeded for username '%s'",
1680 up->username);
1681 skip_auth = true;
1682 }
1683 else
1684 {
1685 wipe_auth_token(multi);
1687 msg(M_WARN,
1688 "TLS: Username/auth-token authentication "
1689 "failed for username '%s'",
1690 up->username);
1691 return;
1692 }
1693 }
1694
1695 int plugin_status = OPENVPN_PLUGIN_FUNC_SUCCESS;
1696 int script_status = OPENVPN_PLUGIN_FUNC_SUCCESS;
1697 /* Set the environment variables used by all auth variants */
1698 if (!set_verify_user_pass_env(up, multi, session))
1699 {
1700 skip_auth = true;
1701 plugin_status = OPENVPN_PLUGIN_FUNC_ERROR;
1702 }
1703
1704 /* call plugin(s) and/or script */
1705 if (!skip_auth)
1706 {
1707#ifdef ENABLE_MANAGEMENT
1708 if (man_def_auth == KMDA_DEF)
1709 {
1710 man_def_auth = verify_user_pass_management(session, up);
1711 }
1712#endif
1713 if (plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
1714 {
1715 plugin_status = verify_user_pass_plugin(session, multi, up);
1716 }
1717
1718 if (session->opt->auth_user_pass_verify_script)
1719 {
1720 script_status = verify_user_pass_script(session, multi, up);
1721 }
1722 }
1723
1724 /* check sizing of username if it will become our common name */
1726 {
1727 plugin_status = OPENVPN_PLUGIN_FUNC_ERROR;
1728 script_status = OPENVPN_PLUGIN_FUNC_ERROR;
1729 }
1730
1731 /* auth succeeded? */
1732 bool plugin_ok = plugin_status == OPENVPN_PLUGIN_FUNC_SUCCESS
1733 || plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED;
1734
1735 bool script_ok = script_status == OPENVPN_PLUGIN_FUNC_SUCCESS
1736 || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED;
1737
1738 if (script_ok && plugin_ok && tls_lock_username(multi, up->username)
1739#ifdef ENABLE_MANAGEMENT
1740 && man_def_auth != KMDA_ERROR
1741#endif
1742 )
1743 {
1745 if (plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED
1746 || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED)
1747 {
1749 }
1750#ifdef ENABLE_MANAGEMENT
1751 if (man_def_auth != KMDA_UNDEF)
1752 {
1753 if (skip_auth)
1754 {
1756 }
1757 else
1758 {
1760 }
1761 }
1762#endif
1763 if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
1764 {
1766 }
1767
1768 if ((session->opt->auth_token_generate))
1769 {
1770 /*
1771 * If we accepted a (not expired) token, i.e.
1772 * initial auth via token on new connection, we need
1773 * to store the auth-token in multi->auth_token, so
1774 * the initial timestamp and session id can be extracted from it
1775 */
1778 {
1779 multi->auth_token = strdup(up->password);
1780 }
1781
1782 /*
1783 * Server is configured with --auth-gen-token. Generate or renew
1784 * the token.
1785 */
1786 generate_auth_token(up, multi);
1787 }
1788
1789 msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
1790 (ks->authenticated == KS_AUTH_DEFERRED) ? "deferred" : "succeeded", up->username,
1791 (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
1792 }
1793 else
1794 {
1796 msg(D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
1797 }
1798}
1799
1800void
1802{
1803 struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
1804
1805 /* While it shouldn't really happen, don't allow the common name to be NULL */
1806 if (!session->common_name)
1807 {
1809 }
1810
1811 /* Don't allow the CN to change once it's been locked */
1812 if (ks->authenticated > KS_AUTH_FALSE && multi->locked_cn)
1813 {
1814 const char *cn = session->common_name;
1815 if (cn && strcmp(cn, multi->locked_cn))
1816 {
1818 "TLS Auth Error: TLS object CN attempted to change from '%s' to '%s' -- tunnel disabled",
1819 multi->locked_cn, cn);
1820
1821 /* change the common name back to its original value and disable the tunnel */
1823 tls_deauthenticate(multi);
1824 }
1825 }
1826
1827 /* Don't allow the cert hashes to change once they have been locked */
1829 {
1830 const struct cert_hash_set *chs = session->cert_hash_set;
1831 if (chs && !cert_hash_compare(chs, multi->locked_cert_hash_set))
1832 {
1834 "TLS Auth Error: TLS object CN=%s client-provided SSL certs unexpectedly changed during mid-session reauth",
1835 session->common_name);
1836
1837 /* disable the tunnel */
1838 tls_deauthenticate(multi);
1839 }
1840 }
1841
1842 /* verify --client-config-dir based authentication */
1843 if (ks->authenticated > KS_AUTH_FALSE && session->opt->client_config_dir_exclusive)
1844 {
1845 struct gc_arena gc = gc_new();
1846
1847 const char *cn = session->common_name;
1848 const char *path = platform_gen_path(session->opt->client_config_dir_exclusive, cn, &gc);
1849 if (!cn || !strcmp(cn, CCD_DEFAULT) || !platform_test_file(path))
1850 {
1852 wipe_auth_token(multi);
1854 "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'",
1855 session->common_name, path ? path : "UNDEF");
1856 }
1857
1858 gc_free(&gc);
1859 }
1860}
1861
1862void
1864{
1865 struct env_item *item = es->list;
1866 while (item)
1867 {
1868 struct env_item *next = item->next;
1869 if (item->string && 0 == strncmp("X509_", item->string, strlen("X509_")))
1870 {
1871 env_set_del(es, item->string);
1872 }
1873 item = next;
1874 }
1875}
void argv_parse_cmd(struct argv *argres, const char *cmdstr)
Parses a command string, tokenizes it and puts each element into a separate struct argv argument slot...
Definition argv.c:481
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition argv.c:101
void argv_msg_prefix(const msglvl_t msglevel, const struct argv *a, const char *prefix)
Similar to argv_msg() but prefixes the messages being written with a given string.
Definition argv.c:259
bool argv_printf(struct argv *argres, const char *format,...)
printf() variant which populates a struct argv.
Definition argv.c:438
bool argv_printf_cat(struct argv *argres, const char *format,...)
printf() inspired argv concatenation.
Definition argv.c:462
struct argv argv_new(void)
Allocates a new struct argv and ensures it is initialised.
Definition argv.c:87
void generate_auth_token(const struct user_pass *up, struct tls_multi *multi)
Generate an auth token based on username and timestamp.
Definition auth_token.c:179
unsigned int verify_auth_token(struct user_pass *up, struct tls_multi *multi, struct tls_session *session)
Verifies the auth token to be in the format that generate_auth_token create and checks if the token i...
Definition auth_token.c:309
void add_session_token_env(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up)
Put the session id, and auth token status into the environment if auth-token is enabled.
Definition auth_token.c:57
void wipe_auth_token(struct tls_multi *multi)
Wipes the authentication token out of the memory, frees and cleans up related buffers and flags.
Definition auth_token.c:416
bool is_auth_token(const char *password)
Return if the password string has the format of a password.
Definition auth_token.c:40
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:246
void string_replace_leading(char *str, const char match, const char replace)
Definition buffer.c:1125
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Definition buffer.c:1355
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1187
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
char * format_hex_ex(const uint8_t *data, size_t size, size_t maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:488
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition buffer.c:1059
struct buffer buffer_read_from_file(const char *filename, struct gc_arena *gc)
buffer_read_from_file - copy the content of a file into a buffer
Definition buffer.c:1378
bool checked_snprintf(char *str, size_t size, const char *format,...)
Like snprintf() but returns an boolean.
Definition buffer.c:1143
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:653
void buf_chomp(struct buffer *buf)
Definition buffer.c:558
#define ALLOC_OBJ(dptr, type)
Definition buffer.h:1115
#define BSTR(buf)
Definition buffer.h:130
#define BPTR(buf)
Definition buffer.h:124
#define CC_CRLF
carriage return or newline
Definition buffer.h:947
#define BLEN(buf)
Definition buffer.h:127
#define BLENZ(buf)
Definition buffer.h:128
static void gc_free(struct gc_arena *a)
Definition buffer.h:1081
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:918
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1120
static struct gc_arena gc_new(void)
Definition buffer.h:1073
#define CCD_DEFAULT
Definition common.h:63
char * strtok_r(char *s, const char *delim, char **last)
int memcmp_constant_time(const void *a, const void *b, size_t size)
As memcmp(), but constant-time.
@ MD_SHA256
@ MD_SHA1
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition env_set.c:307
bool env_set_del(struct env_set *es, const char *str)
Definition env_set.c:183
void setenv_del(struct env_set *es, const char *name)
Definition env_set.c:352
#define D_HANDSHAKE
Definition errlevel.h:71
#define D_MULTI_LOW
Definition errlevel.h:85
#define D_TLS_ERRORS
Definition errlevel.h:58
#define M_INFO
Definition errlevel.h:54
#define D_TLS_DEBUG
Definition errlevel.h:164
#define KS_SIZE
Size of the tls_session.key array.
Definition ssl_common.h:468
#define KS_PRIMARY
Primary key state index.
Definition ssl_common.h:464
#define TM_SIZE
Size of the tls_multi.session \ array.
Definition ssl_common.h:549
#define TM_ACTIVE
Active tls_session.
Definition ssl_common.h:544
#define TLS_AUTHENTICATED(multi, ks)
Check whether the ks key_state has finished the key exchange part of the OpenVPN hand shake.
Definition ssl_verify.h:113
static unsigned int min_uint(unsigned int x, unsigned int y)
Definition integer.h:66
static int max_int(int x, int y)
Definition integer.h:92
static SERVICE_STATUS status
Definition interactive.c:52
void management_notify_client_needing_auth(struct management *management, const unsigned int mda_key_id, struct man_def_auth_context *mdac, const struct env_set *es)
Definition manage.c:3069
static bool management_enable_def_auth(const struct management *man)
Definition manage.h:440
#define SIZE(x)
Definition basic.h:29
#define dmsg(flags,...)
Definition error.h:172
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
#define MAX_PARMS
Definition options.h:51
time_t now
Definition otime.c:33
bool platform_test_file(const char *filename)
Return true if filename can be opened for read.
Definition platform.c:655
const char * platform_create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc)
Create a temporary file in directory, returns the filename of the created file.
Definition platform.c:540
const char * platform_gen_path(const char *directory, const char *filename, struct gc_arena *gc)
Put a directory and filename together.
Definition platform.c:591
bool platform_unlink(const char *filename)
Definition platform.c:487
int platform_open(const char *path, int flags, int mode)
Definition platform.c:513
int plugin_call_ssl(const struct plugin_list *pl, const int type, const struct argv *av, struct plugin_return *pr, struct env_set *es, int certdepth, openvpn_x509_cert_t *current_cert)
Definition plugin.c:782
bool plugin_defined(const struct plugin_list *pl, const int type)
Definition plugin.c:904
static int plugin_call(const struct plugin_list *pl, const int type, const struct argv *av, struct plugin_return *pr, struct env_set *es)
Definition plugin.h:195
bool send_auth_pending_messages(struct tls_multi *tls_multi, struct tls_session *session, const char *extra, unsigned int timeout)
Sends the auth pending control messages to a client.
Definition push.c:433
#define S_EXITCODE
Instead of returning 1/0 for success/fail, return exit code when between 0 and 255 and -1 otherwise.
Definition run_command.h:53
static int openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook)
Will run a script and return the exit code of the script if between 0 and 255, -1 otherwise.
Definition run_command.h:89
void setenv_link_socket_actual(struct env_set *es, const char *name_prefix, const struct link_socket_actual *act, const unsigned int flags)
#define SA_IP_PORT
Definition socket_util.h:99
void tls_clear_error(void)
Clear the underlying SSL library's error state.
#define AUTH_TOKEN_HMAC_OK
Auth-token sent from client has valid hmac.
Definition ssl_common.h:686
#define KEY_SCAN_SIZE
Definition ssl_common.h:566
auth_deferred_result
Definition ssl_common.h:175
@ ACF_PENDING
deferred auth still pending
Definition ssl_common.h:176
@ ACF_SUCCEEDED
deferred auth has suceeded
Definition ssl_common.h:177
@ ACF_FAILED
deferred auth has failed
Definition ssl_common.h:179
@ ACF_DISABLED
deferred auth is not used
Definition ssl_common.h:178
#define AUTH_TOKEN_EXPIRED
Auth-token sent from client has expired.
Definition ssl_common.h:688
static struct key_state * get_key_scan(struct tls_multi *multi, int index)
gets an item of key_state objects in the order they should be scanned by data channel modules.
Definition ssl_common.h:732
#define SSLF_AUTH_USER_PASS_OPTIONAL
Definition ssl_common.h:426
@ KS_AUTH_TRUE
Key state is authenticated.
Definition ssl_common.h:157
@ KS_AUTH_FALSE
Key state is not authenticated
Definition ssl_common.h:154
@ KS_AUTH_DEFERRED
Key state authentication is being deferred, by async auth.
Definition ssl_common.h:155
#define SSLF_CRL_VERIFY_DIR
Definition ssl_common.h:428
static const struct key_state * get_primary_key(const struct tls_multi *multi)
gets an item of key_state objects in the order they should be scanned by data channel modules.
Definition ssl_common.h:755
#define SSLF_USERNAME_AS_COMMON_NAME
Definition ssl_common.h:425
char * extract_var_peer_info(const char *peer_info, const char *var, struct gc_arena *gc)
Extracts a variable from peer info, the returned string will be allocated using the supplied gc_arena...
Definition ssl_util.c:31
SSL utility functions.
static result_t verify_cert_call_command(const char *verify_command, struct env_set *es, int cert_depth, char *subject)
Definition ssl_verify.c:514
static void verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth, const char *subject, const struct x509_track *x509_track)
Definition ssl_verify.c:408
void key_state_rm_auth_control_files(struct auth_deferred_status *ads)
Removes auth_pending and auth_control files from file system and key_state structure.
Definition ssl_verify.c:967
static bool key_state_gen_auth_control_files(struct auth_deferred_status *ads, const struct tls_options *opt)
Generates and creates the control files used for deferred authentification in the temporary directory...
Definition ssl_verify.c:991
static struct cert_hash_set * cert_hash_copy(const struct cert_hash_set *chs)
Definition ssl_verify.c:266
static void key_state_rm_auth_pending_file(struct auth_deferred_status *ads)
Removes auth_pending file from the file system and key_state structure.
Definition ssl_verify.c:846
#define KMDA_SUCCESS
bool ssl_verify_username_length(struct tls_session *session, const char *username)
Checks if the username length is valid to use.
static result_t verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert, const char *subject, int cert_depth)
Definition ssl_verify.c:546
#define KMDA_DEF
bool tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason)
static void verify_cert_cert_delete_env(struct env_set *es, const char *pem_export_fname)
Definition ssl_verify.c:469
static void tls_deauthenticate(struct tls_multi *multi)
Definition ssl_verify.c:69
void verify_crresponse_plugin(struct tls_multi *multi, const char *cr_response)
Call the plugin OPENVPN_PLUGIN_CLIENT_CRRESPONSE.
bool cert_hash_compare(const struct cert_hash_set *chs1, const struct cert_hash_set *chs2)
Compares certificates hashes, returns true if hashes are equal.
Definition ssl_verify.c:229
void tls_x509_clear_env(struct env_set *es)
Remove any X509_ env variables from env_set es.
static void update_key_auth_status(bool cached, struct key_state *ks)
This method takes a key_state and if updates the state of the key if it is deferred.
void tls_lock_cert_hash_set(struct tls_multi *multi)
Locks the certificate hash set used in the given tunnel.
Definition ssl_verify.c:286
static result_t verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, const char *subject, const char *common_name)
Definition ssl_verify.c:323
result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth)
Definition ssl_verify.c:588
void tls_lock_common_name(struct tls_multi *multi)
Locks the common name field for the given tunnel.
Definition ssl_verify.c:132
static enum auth_deferred_result man_def_auth_test(const struct key_state *ks)
Definition ssl_verify.c:828
#define KMDA_UNDEF
void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session)
Perform final authentication checks, including locking of the cn, the allowed certificate hashes,...
static bool tls_lock_username(struct tls_multi *multi, const char *username)
Definition ssl_verify.c:145
static int verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up)
static bool key_state_check_auth_pending_file(struct auth_deferred_status *ads, struct tls_multi *multi, struct tls_session *session)
Checks if the deferred state should also send auth pending request to the client.
Definition ssl_verify.c:898
const char * tls_username(const struct tls_multi *multi, const bool null)
Returns the username field for the given tunnel.
Definition ssl_verify.c:172
void set_common_name(struct tls_session *session, const char *common_name)
Sets the common name field for the given tunnel.
Definition ssl_verify.c:85
#define KMDA_ERROR
static char * key_state_check_auth_failed_message_file(const struct auth_deferred_status *ads, struct gc_arena *gc)
Checks if the auth failed reason file has any content and if yes it will be returned as string alloca...
void auth_set_client_reason(struct tls_multi *multi, const char *client_reason)
Sets the reason why authentication of a client failed.
Definition ssl_verify.c:814
static result_t verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert, char *subject)
Definition ssl_verify.c:482
enum tls_auth_status tls_authentication_status(struct tls_multi *multi)
Return current session authentication state of the tls_multi structure This will return TLS_AUTHENTIC...
void verify_user_pass(struct user_pass *up, struct tls_multi *multi, struct tls_session *session)
Main username/password verification entry point.
static bool tls_authentication_status_use_cache(struct tls_multi *multi)
uses cache_intervals times to determine if we should update the cache.
static void check_for_client_reason(struct tls_multi *multi, struct auth_deferred_status *status)
Check if the script/plugin left a message in the auth failed message file and relay it to the user.
static const char * print_nsCertType(int type)
Definition ssl_verify.c:299
void verify_crresponse_script(struct tls_multi *multi, const char *cr_response)
Runs the –client-crresponse script if one is defined.
static time_t cache_intervals[]
The minimum times to have passed to update the cache.
static int verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up)
static enum auth_deferred_result key_state_test_auth_control_file(struct auth_deferred_status *ads, bool cached)
Checks the auth control status from a file.
static void string_mod_remap_name(char *str)
Definition ssl_verify.c:51
void cert_hash_remember(struct tls_session *session, const int error_depth, const struct buffer *cert_hash)
Definition ssl_verify.c:194
static void setenv_untrusted(struct tls_session *session)
Definition ssl_verify.c:60
const char * tls_common_name(const struct tls_multi *multi, const bool null)
Returns the common name field for the given tunnel.
Definition ssl_verify.c:107
static int verify_user_pass_management(struct tls_session *session, const struct user_pass *up)
static bool verify_cert_cert_export_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, const char *pem_export_fname)
Exports the certificate in peer_cert into the environment and adds the filname.
Definition ssl_verify.c:459
void cert_hash_free(struct cert_hash_set *chs)
Frees the given set of certificate hashes.
Definition ssl_verify.c:215
static bool check_auth_pending_method(const char *peer_info, const char *method)
Check peer_info if the client supports the requested pending auth method.
Definition ssl_verify.c:860
static bool set_verify_user_pass_env(struct user_pass *up, struct tls_multi *multi, struct tls_session *session)
Control Channel Verification Module.
tls_auth_status
Definition ssl_verify.h:74
@ TLS_AUTHENTICATION_DEFERRED
Definition ssl_verify.h:77
@ TLS_AUTHENTICATION_SUCCEEDED
Definition ssl_verify.h:75
@ TLS_AUTHENTICATION_FAILED
Definition ssl_verify.h:76
#define VERIFY_X509_SUBJECT_DN
Definition ssl_verify.h:69
#define VERIFY_X509_SUBJECT_RDN
Definition ssl_verify.h:70
#define NS_CERT_CHECK_CLIENT
Do not perform Netscape certificate type verification.
Definition ssl_verify.h:254
#define VERIFY_X509_NONE
Definition ssl_verify.h:68
#define TLS_USERNAME_LEN
Maximum length of common name.
Definition ssl_verify.h:54
#define VERIFY_X509_SUBJECT_RDN_PREFIX
Definition ssl_verify.h:71
#define MAX_CERT_DEPTH
Maximum certificate depth we will allow.
Definition ssl_verify.h:51
#define NS_CERT_CHECK_NONE
Do not perform Netscape certificate type verification.
Definition ssl_verify.h:250
#define NS_CERT_CHECK_SERVER
Do not perform Netscape certificate type verification.
Definition ssl_verify.h:252
Control Channel Verification Module library-specific backend interface.
struct buffer x509_get_sha256_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA256 fingerprint.
void x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int depth, openvpn_x509_cert_t *x509)
void x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
bool tls_verify_crl_missing(const struct tls_options *opt)
Return true iff a CRL is configured, but is not loaded.
result_t backend_x509_write_pem(openvpn_x509_cert_t *cert, const char *filename)
result_t x509_verify_ns_cert_type(openvpn_x509_cert_t *cert, const int usage)
char * backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
struct buffer x509_get_sha1_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA1 fingerprint.
result_t x509_verify_cert_ku(openvpn_x509_cert_t *x509, const unsigned *const expected_ku, size_t expected_len)
char * x509_get_subject(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Definition test_pkcs11.c:68
char * backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc)
result_t backend_x509_get_username(char *common_name, size_t cn_len, char *x509_username_field, openvpn_x509_cert_t *peer_cert)
result_t
Result of verification function.
@ FAILURE
@ SUCCESS
result_t x509_verify_cert_eku(openvpn_x509_cert_t *x509, const char *const expected_oid)
mbedtls_x509_crt openvpn_x509_cert_t
Control Channel Verification Module OpenSSL backend.
void status_printf(struct status_output *so, const char *format,...)
Definition status.c:212
struct status_output * status_open(const char *filename, const int refresh_freq, const int msglevel, const struct virtual_output *vout, const unsigned int flags)
Definition status.c:59
bool status_close(struct status_output *so)
Definition status.c:178
#define STATUS_OUTPUT_WRITE
Definition status.h:51
Definition argv.h:35
char * auth_failed_reason_file
Definition ssl_common.h:168
struct buffer_entry * next
Definition buffer.h:1177
struct buffer_entry * head
Definition buffer.h:1182
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int capacity
Size in bytes of memory allocated by malloc().
Definition buffer.h:62
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Structure containing the hashes for a full certificate chain.
Definition ssl_verify.h:64
struct cert_hash * ch[MAX_CERT_DEPTH]
Array of certificate hashes.
Definition ssl_verify.h:65
Structure containing the hash for a single certificate.
Definition ssl_verify.h:58
unsigned char sha256_hash[256/8]
Definition ssl_verify.h:59
char * string
Definition env_set.h:38
struct env_item * next
Definition env_set.h:39
struct env_item * list
Definition env_set.h:45
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
Security parameter state of one TLS and data channel key session.
Definition ssl_common.h:208
unsigned int auth_token_state_flags
The state of the auth-token sent from the client.
Definition ssl_common.h:211
struct auth_deferred_status plugin_auth
Definition ssl_common.h:268
unsigned int mda_key_id
Definition ssl_common.h:263
struct auth_deferred_status script_auth
Definition ssl_common.h:269
enum auth_deferred_result mda_status
Definition ssl_common.h:264
enum ks_auth_state authenticated
Definition ssl_common.h:259
time_t auth_deferred_expire
Definition ssl_common.h:260
Security parameter state for a single VPN tunnel.
Definition ssl_common.h:611
char * auth_token_initial
The first auth-token we sent to a client.
Definition ssl_common.h:683
char * peer_info
A multi-line string of general-purpose info received from peer over control channel.
Definition ssl_common.h:672
char * locked_username
The locked username is the username we assume the client is using.
Definition ssl_common.h:649
unsigned int tas_cache_num_updates
The number of times we updated the cache.
Definition ssl_common.h:663
struct tls_session session[TM_SIZE]
Array of tls_session objects representing control channel sessions with the remote peer.
Definition ssl_common.h:711
struct cert_hash_set * locked_cert_hash_set
Definition ssl_common.h:655
time_t tas_cache_last_update
Time of last when we updated the cached state of tls_authentication_status deferred files.
Definition ssl_common.h:660
char * locked_cn
Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi ob...
Definition ssl_common.h:644
char * client_reason
An error message to send to client on AUTH_FAILED.
Definition ssl_common.h:666
char * auth_token
If server sends a generated auth-token, this is the token to use for future user/pass authentications...
Definition ssl_common.h:678
char * locked_original_username
The username that client initially used before being overridden by –override-user.
Definition ssl_common.h:653
struct env_set * es
Definition ssl_common.h:413
unsigned remote_cert_ku[MAX_PARMS]
Definition ssl_common.h:358
const char * tmp_dir
Definition ssl_common.h:394
int verify_hash_depth
Definition ssl_common.h:361
const struct plugin_list * plugins
Definition ssl_common.h:415
const char * export_peer_cert_dir
Definition ssl_common.h:395
char * x509_username_field[MAX_PARMS]
Definition ssl_common.h:364
const char * verify_command
Definition ssl_common.h:352
struct verify_hash_list * verify_hash
Definition ssl_common.h:360
int verify_x509_type
Definition ssl_common.h:353
const char * verify_x509_name
Definition ssl_common.h:354
const struct x509_track * x509_track
Definition ssl_common.h:440
unsigned int ssl_flags
Definition ssl_common.h:434
hash_algo_type verify_hash_algo
Definition ssl_common.h:363
const char * crl_file
Definition ssl_common.h:355
const char * remote_cert_eku
Definition ssl_common.h:359
Security parameter state of a single session within a VPN tunnel.
Definition ssl_common.h:489
struct key_state key[KS_SIZE]
Definition ssl_common.h:524
struct cert_hash_set * cert_hash_set
Definition ssl_common.h:517
char * common_name
Definition ssl_common.h:515
bool protected
Definition misc.h:61
char password[USER_PASS_LEN]
Definition misc.h:71
char username[USER_PASS_LEN]
Definition misc.h:70
struct verify_hash_list * next
Definition options.h:252
uint8_t hash[SHA256_DIGEST_LENGTH]
Definition options.h:251
#define PATH_SEPARATOR
Definition syshead.h:432
struct env_set * es
static int cleanup(void **state)
struct gc_arena gc
Definition test_ssl.c:133