summaryrefslogtreecommitdiffstats
path: root/lib/ext
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ext')
-rw-r--r--lib/ext/Makefile.am63
-rw-r--r--lib/ext/Makefile.in2517
-rw-r--r--lib/ext/alpn.c327
-rw-r--r--lib/ext/alpn.h40
-rw-r--r--lib/ext/cert_types.h88
-rw-r--r--lib/ext/client_cert_type.c393
-rw-r--r--lib/ext/client_cert_type.h36
-rw-r--r--lib/ext/compress_certificate.c252
-rw-r--r--lib/ext/compress_certificate.h49
-rw-r--r--lib/ext/cookie.c117
-rw-r--r--lib/ext/cookie.h30
-rw-r--r--lib/ext/dumbfw.c84
-rw-r--r--lib/ext/dumbfw.h28
-rw-r--r--lib/ext/early_data.c147
-rw-r--r--lib/ext/early_data.h30
-rw-r--r--lib/ext/ec_point_formats.c124
-rw-r--r--lib/ext/ec_point_formats.h30
-rw-r--r--lib/ext/etm.c151
-rw-r--r--lib/ext/etm.h30
-rw-r--r--lib/ext/ext_master_secret.c155
-rw-r--r--lib/ext/ext_master_secret.h30
-rw-r--r--lib/ext/heartbeat.c574
-rw-r--r--lib/ext/heartbeat.h44
-rw-r--r--lib/ext/key_share.c794
-rw-r--r--lib/ext/key_share.h30
-rw-r--r--lib/ext/max_record.c317
-rw-r--r--lib/ext/max_record.h30
-rw-r--r--lib/ext/post_handshake.c101
-rw-r--r--lib/ext/post_handshake.h30
-rw-r--r--lib/ext/pre_shared_key.c911
-rw-r--r--lib/ext/pre_shared_key.h23
-rw-r--r--lib/ext/psk_ke_modes.c205
-rw-r--r--lib/ext/psk_ke_modes.h8
-rw-r--r--lib/ext/record_size_limit.c157
-rw-r--r--lib/ext/record_size_limit.h30
-rw-r--r--lib/ext/safe_renegotiation.c449
-rw-r--r--lib/ext/safe_renegotiation.h49
-rw-r--r--lib/ext/server_cert_type.c370
-rw-r--r--lib/ext/server_cert_type.h36
-rw-r--r--lib/ext/server_name.c385
-rw-r--r--lib/ext/server_name.h33
-rw-r--r--lib/ext/session_ticket.c843
-rw-r--r--lib/ext/session_ticket.h40
-rw-r--r--lib/ext/signature.c587
-rw-r--r--lib/ext/signature.h61
-rw-r--r--lib/ext/srp.c277
-rw-r--r--lib/ext/srp.h42
-rw-r--r--lib/ext/srtp.c672
-rw-r--r--lib/ext/srtp.h45
-rw-r--r--lib/ext/status_request.c512
-rw-r--r--lib/ext/status_request.h41
-rw-r--r--lib/ext/supported_groups.c269
-rw-r--r--lib/ext/supported_groups.h34
-rw-r--r--lib/ext/supported_versions.c239
-rw-r--r--lib/ext/supported_versions.h30
55 files changed, 12989 insertions, 0 deletions
diff --git a/lib/ext/Makefile.am b/lib/ext/Makefile.am
new file mode 100644
index 0000000..81efdbc
--- /dev/null
+++ b/lib/ext/Makefile.am
@@ -0,0 +1,63 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2002-2012 Free Software Foundation, Inc.
+#
+# Author: Nikos Mavrogiannopoulos
+#
+# This file is part of GnuTLS.
+#
+# The GnuTLS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# The GnuTLS is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+include $(top_srcdir)/lib/common.mk
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../gl \
+ -I$(builddir)/../../gl \
+ -I$(srcdir)/../includes \
+ -I$(builddir)/../includes \
+ -I$(builddir)/../../gl \
+ -I$(srcdir)/..
+
+if ENABLE_MINITASN1
+AM_CPPFLAGS += -I$(srcdir)/../minitasn1
+endif
+
+noinst_LTLIBRARIES = libgnutls_ext.la
+
+libgnutls_ext_la_SOURCES = max_record.c \
+ server_name.c signature.c safe_renegotiation.c \
+ max_record.h server_name.h srp.h \
+ session_ticket.h signature.h safe_renegotiation.h \
+ session_ticket.c srp.c heartbeat.c heartbeat.h \
+ status_request.h status_request.c dumbfw.c dumbfw.h \
+ ext_master_secret.c ext_master_secret.h etm.h etm.c \
+ supported_versions.c supported_versions.h \
+ post_handshake.c post_handshake.h key_share.c key_share.h \
+ cookie.c cookie.h \
+ psk_ke_modes.c psk_ke_modes.h pre_shared_key.c pre_shared_key.h \
+ supported_groups.c supported_groups.h \
+ ec_point_formats.c ec_point_formats.h \
+ early_data.c early_data.h \
+ record_size_limit.c record_size_limit.h \
+ client_cert_type.c client_cert_type.h \
+ server_cert_type.c server_cert_type.h \
+ cert_types.h \
+ compress_certificate.c compress_certificate.h
+
+if ENABLE_ALPN
+libgnutls_ext_la_SOURCES += alpn.c alpn.h
+endif
+
+if ENABLE_DTLS_SRTP
+libgnutls_ext_la_SOURCES += srtp.c srtp.h
+endif
diff --git a/lib/ext/Makefile.in b/lib/ext/Makefile.in
new file mode 100644
index 0000000..47c4abc
--- /dev/null
+++ b/lib/ext/Makefile.in
@@ -0,0 +1,2517 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright (C) 2002-2012 Free Software Foundation, Inc.
+#
+# Author: Nikos Mavrogiannopoulos
+#
+# This file is part of GnuTLS.
+#
+# The GnuTLS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# The GnuTLS is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_MINITASN1_TRUE@am__append_1 = -I$(srcdir)/../minitasn1
+@ENABLE_ALPN_TRUE@am__append_2 = alpn.c alpn.h
+@ENABLE_DTLS_SRTP_TRUE@am__append_3 = srtp.c srtp.h
+subdir = lib/ext
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/lib/unistring/m4/gnulib-comp.m4 \
+ $(top_srcdir)/lib/unistring/m4/inline.m4 \
+ $(top_srcdir)/lib/unistring/m4/libunistring-base.m4 \
+ $(top_srcdir)/src/gl/m4/atoll.m4 \
+ $(top_srcdir)/src/gl/m4/bison.m4 \
+ $(top_srcdir)/src/gl/m4/calloc.m4 \
+ $(top_srcdir)/src/gl/m4/clock_time.m4 \
+ $(top_srcdir)/src/gl/m4/codeset.m4 \
+ $(top_srcdir)/src/gl/m4/ctype_h.m4 \
+ $(top_srcdir)/src/gl/m4/environ.m4 \
+ $(top_srcdir)/src/gl/m4/error.m4 \
+ $(top_srcdir)/src/gl/m4/fdopen.m4 \
+ $(top_srcdir)/src/gl/m4/flexmember.m4 \
+ $(top_srcdir)/src/gl/m4/fpending.m4 \
+ $(top_srcdir)/src/gl/m4/fpieee.m4 \
+ $(top_srcdir)/src/gl/m4/fseek.m4 \
+ $(top_srcdir)/src/gl/m4/ftruncate.m4 \
+ $(top_srcdir)/src/gl/m4/getaddrinfo.m4 \
+ $(top_srcdir)/src/gl/m4/getcwd.m4 \
+ $(top_srcdir)/src/gl/m4/getpagesize.m4 \
+ $(top_srcdir)/src/gl/m4/getpass.m4 \
+ $(top_srcdir)/src/gl/m4/getprogname.m4 \
+ $(top_srcdir)/src/gl/m4/gettime.m4 \
+ $(top_srcdir)/src/gl/m4/gnulib-comp.m4 \
+ $(top_srcdir)/src/gl/m4/hostent.m4 \
+ $(top_srcdir)/src/gl/m4/intl-thread-locale.m4 \
+ $(top_srcdir)/src/gl/m4/inttostr.m4 \
+ $(top_srcdir)/src/gl/m4/ioctl.m4 \
+ $(top_srcdir)/src/gl/m4/isblank.m4 \
+ $(top_srcdir)/src/gl/m4/langinfo_h.m4 \
+ $(top_srcdir)/src/gl/m4/lcmessage.m4 \
+ $(top_srcdir)/src/gl/m4/locale-fr.m4 \
+ $(top_srcdir)/src/gl/m4/locale-ja.m4 \
+ $(top_srcdir)/src/gl/m4/locale-tr.m4 \
+ $(top_srcdir)/src/gl/m4/locale-zh.m4 \
+ $(top_srcdir)/src/gl/m4/locale_h.m4 \
+ $(top_srcdir)/src/gl/m4/localename.m4 \
+ $(top_srcdir)/src/gl/m4/lstat.m4 \
+ $(top_srcdir)/src/gl/m4/mktime.m4 \
+ $(top_srcdir)/src/gl/m4/nanosleep.m4 \
+ $(top_srcdir)/src/gl/m4/nstrftime.m4 \
+ $(top_srcdir)/src/gl/m4/parse-datetime.m4 \
+ $(top_srcdir)/src/gl/m4/perror.m4 \
+ $(top_srcdir)/src/gl/m4/pipe.m4 \
+ $(top_srcdir)/src/gl/m4/pthread-thread.m4 \
+ $(top_srcdir)/src/gl/m4/pthread_h.m4 \
+ $(top_srcdir)/src/gl/m4/pthread_sigmask.m4 \
+ $(top_srcdir)/src/gl/m4/putenv.m4 \
+ $(top_srcdir)/src/gl/m4/raise.m4 \
+ $(top_srcdir)/src/gl/m4/reallocarray.m4 \
+ $(top_srcdir)/src/gl/m4/sched_h.m4 \
+ $(top_srcdir)/src/gl/m4/sched_yield.m4 \
+ $(top_srcdir)/src/gl/m4/select.m4 \
+ $(top_srcdir)/src/gl/m4/semaphore.m4 \
+ $(top_srcdir)/src/gl/m4/servent.m4 \
+ $(top_srcdir)/src/gl/m4/setenv.m4 \
+ $(top_srcdir)/src/gl/m4/setlocale.m4 \
+ $(top_srcdir)/src/gl/m4/setlocale_null.m4 \
+ $(top_srcdir)/src/gl/m4/sigaction.m4 \
+ $(top_srcdir)/src/gl/m4/signal_h.m4 \
+ $(top_srcdir)/src/gl/m4/signalblocking.m4 \
+ $(top_srcdir)/src/gl/m4/sleep.m4 \
+ $(top_srcdir)/src/gl/m4/sockets.m4 \
+ $(top_srcdir)/src/gl/m4/strerror.m4 \
+ $(top_srcdir)/src/gl/m4/strerror_r.m4 \
+ $(top_srcdir)/src/gl/m4/strtoll.m4 \
+ $(top_srcdir)/src/gl/m4/symlink.m4 \
+ $(top_srcdir)/src/gl/m4/sys_ioctl_h.m4 \
+ $(top_srcdir)/src/gl/m4/sys_select_h.m4 \
+ $(top_srcdir)/src/gl/m4/thread.m4 \
+ $(top_srcdir)/src/gl/m4/time_rz.m4 \
+ $(top_srcdir)/src/gl/m4/timegm.m4 \
+ $(top_srcdir)/src/gl/m4/timespec.m4 \
+ $(top_srcdir)/src/gl/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/src/gl/m4/tzset.m4 \
+ $(top_srcdir)/src/gl/m4/usleep.m4 \
+ $(top_srcdir)/src/gl/m4/visibility.m4 \
+ $(top_srcdir)/src/gl/m4/xalloc.m4 \
+ $(top_srcdir)/src/gl/m4/yield.m4 $(top_srcdir)/m4/00gnulib.m4 \
+ $(top_srcdir)/m4/__inline.m4 \
+ $(top_srcdir)/m4/absolute-header.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/arpa_inet_h.m4 \
+ $(top_srcdir)/m4/ax_ac_append_to_file.m4 \
+ $(top_srcdir)/m4/ax_ac_print_to_file.m4 \
+ $(top_srcdir)/m4/ax_add_am_macro_static.m4 \
+ $(top_srcdir)/m4/ax_am_macros_static.m4 \
+ $(top_srcdir)/m4/ax_check_gnu_make.m4 \
+ $(top_srcdir)/m4/ax_code_coverage.m4 \
+ $(top_srcdir)/m4/ax_file_escapes.m4 \
+ $(top_srcdir)/m4/builtin-expect.m4 \
+ $(top_srcdir)/m4/byteswap.m4 $(top_srcdir)/m4/close.m4 \
+ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.m4 \
+ $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/errno_h.m4 \
+ $(top_srcdir)/m4/explicit_bzero.m4 \
+ $(top_srcdir)/m4/exponentd.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fcntl-o.m4 \
+ $(top_srcdir)/m4/fcntl.m4 $(top_srcdir)/m4/fcntl_h.m4 \
+ $(top_srcdir)/m4/float_h.m4 $(top_srcdir)/m4/fopen.m4 \
+ $(top_srcdir)/m4/free.m4 $(top_srcdir)/m4/fseeko.m4 \
+ $(top_srcdir)/m4/fstat.m4 $(top_srcdir)/m4/ftell.m4 \
+ $(top_srcdir)/m4/ftello.m4 $(top_srcdir)/m4/func.m4 \
+ $(top_srcdir)/m4/getdelim.m4 $(top_srcdir)/m4/getdtablesize.m4 \
+ $(top_srcdir)/m4/getline.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gettimeofday.m4 \
+ $(top_srcdir)/m4/gnulib-common.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+ $(top_srcdir)/m4/guile.m4 $(top_srcdir)/m4/hooks.m4 \
+ $(top_srcdir)/m4/host-cpu-c-abi.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/include_next.m4 $(top_srcdir)/m4/inet_ntop.m4 \
+ $(top_srcdir)/m4/inet_pton.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/largefile.m4 \
+ $(top_srcdir)/m4/ld-output-def.m4 \
+ $(top_srcdir)/m4/ld-version-script.m4 $(top_srcdir)/m4/ldd.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/limits-h.m4 $(top_srcdir)/m4/lock.m4 \
+ $(top_srcdir)/m4/lseek.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/malloc.m4 \
+ $(top_srcdir)/m4/malloca.m4 $(top_srcdir)/m4/manywarnings.m4 \
+ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmem.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mmap-anon.m4 \
+ $(top_srcdir)/m4/mode_t.m4 $(top_srcdir)/m4/msvc-inval.m4 \
+ $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \
+ $(top_srcdir)/m4/netdb_h.m4 $(top_srcdir)/m4/netinet_in_h.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/off_t.m4 \
+ $(top_srcdir)/m4/open-cloexec.m4 \
+ $(top_srcdir)/m4/open-slash.m4 $(top_srcdir)/m4/open.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/printf.m4 \
+ $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/pthread_rwlock_rdlock.m4 \
+ $(top_srcdir)/m4/read-file.m4 $(top_srcdir)/m4/realloc.m4 \
+ $(top_srcdir)/m4/secure_getenv.m4 $(top_srcdir)/m4/size_max.m4 \
+ $(top_srcdir)/m4/snprintf.m4 $(top_srcdir)/m4/socketlib.m4 \
+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-time.m4 \
+ $(top_srcdir)/m4/stat.m4 $(top_srcdir)/m4/stdalign.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stddef_h.m4 \
+ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/m4/stdint_h.m4 \
+ $(top_srcdir)/m4/stdio_h.m4 $(top_srcdir)/m4/stdlib_h.m4 \
+ $(top_srcdir)/m4/stpcpy.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/string_h.m4 \
+ $(top_srcdir)/m4/strings_h.m4 $(top_srcdir)/m4/strndup.m4 \
+ $(top_srcdir)/m4/strnlen.m4 $(top_srcdir)/m4/strtok_r.m4 \
+ $(top_srcdir)/m4/strverscmp.m4 \
+ $(top_srcdir)/m4/sys_socket_h.m4 \
+ $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \
+ $(top_srcdir)/m4/sys_types_h.m4 $(top_srcdir)/m4/sys_uio_h.m4 \
+ $(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/time_h.m4 \
+ $(top_srcdir)/m4/time_r.m4 $(top_srcdir)/m4/ungetc.m4 \
+ $(top_srcdir)/m4/unistd_h.m4 \
+ $(top_srcdir)/m4/valgrind-tests.m4 \
+ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \
+ $(top_srcdir)/m4/vsnprintf.m4 $(top_srcdir)/m4/warn-on-use.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/m4/wchar_h.m4 \
+ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/zzgnulib.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libgnutls_ext_la_LIBADD =
+am__libgnutls_ext_la_SOURCES_DIST = max_record.c server_name.c \
+ signature.c safe_renegotiation.c max_record.h server_name.h \
+ srp.h session_ticket.h signature.h safe_renegotiation.h \
+ session_ticket.c srp.c heartbeat.c heartbeat.h \
+ status_request.h status_request.c dumbfw.c dumbfw.h \
+ ext_master_secret.c ext_master_secret.h etm.h etm.c \
+ supported_versions.c supported_versions.h post_handshake.c \
+ post_handshake.h key_share.c key_share.h cookie.c cookie.h \
+ psk_ke_modes.c psk_ke_modes.h pre_shared_key.c \
+ pre_shared_key.h supported_groups.c supported_groups.h \
+ ec_point_formats.c ec_point_formats.h early_data.c \
+ early_data.h record_size_limit.c record_size_limit.h \
+ client_cert_type.c client_cert_type.h server_cert_type.c \
+ server_cert_type.h cert_types.h compress_certificate.c \
+ compress_certificate.h alpn.c alpn.h srtp.c srtp.h
+@ENABLE_ALPN_TRUE@am__objects_1 = alpn.lo
+@ENABLE_DTLS_SRTP_TRUE@am__objects_2 = srtp.lo
+am_libgnutls_ext_la_OBJECTS = max_record.lo server_name.lo \
+ signature.lo safe_renegotiation.lo session_ticket.lo srp.lo \
+ heartbeat.lo status_request.lo dumbfw.lo ext_master_secret.lo \
+ etm.lo supported_versions.lo post_handshake.lo key_share.lo \
+ cookie.lo psk_ke_modes.lo pre_shared_key.lo \
+ supported_groups.lo ec_point_formats.lo early_data.lo \
+ record_size_limit.lo client_cert_type.lo server_cert_type.lo \
+ compress_certificate.lo $(am__objects_1) $(am__objects_2)
+libgnutls_ext_la_OBJECTS = $(am_libgnutls_ext_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/alpn.Plo \
+ ./$(DEPDIR)/client_cert_type.Plo \
+ ./$(DEPDIR)/compress_certificate.Plo ./$(DEPDIR)/cookie.Plo \
+ ./$(DEPDIR)/dumbfw.Plo ./$(DEPDIR)/early_data.Plo \
+ ./$(DEPDIR)/ec_point_formats.Plo ./$(DEPDIR)/etm.Plo \
+ ./$(DEPDIR)/ext_master_secret.Plo ./$(DEPDIR)/heartbeat.Plo \
+ ./$(DEPDIR)/key_share.Plo ./$(DEPDIR)/max_record.Plo \
+ ./$(DEPDIR)/post_handshake.Plo ./$(DEPDIR)/pre_shared_key.Plo \
+ ./$(DEPDIR)/psk_ke_modes.Plo ./$(DEPDIR)/record_size_limit.Plo \
+ ./$(DEPDIR)/safe_renegotiation.Plo \
+ ./$(DEPDIR)/server_cert_type.Plo ./$(DEPDIR)/server_name.Plo \
+ ./$(DEPDIR)/session_ticket.Plo ./$(DEPDIR)/signature.Plo \
+ ./$(DEPDIR)/srp.Plo ./$(DEPDIR)/srtp.Plo \
+ ./$(DEPDIR)/status_request.Plo \
+ ./$(DEPDIR)/supported_groups.Plo \
+ ./$(DEPDIR)/supported_versions.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgnutls_ext_la_SOURCES)
+DIST_SOURCES = $(am__libgnutls_ext_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp $(top_srcdir)/lib/common.mk
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AARCH64_CCASFLAGS = @AARCH64_CCASFLAGS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_VALGRINDFLAGS = @AM_VALGRINDFLAGS@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+ASN1PARSER = @ASN1PARSER@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+BYTESWAP_H = @BYTESWAP_H@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
+CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
+CONFIG_INCLUDE = @CONFIG_INCLUDE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYWRAP_PATCHLEVEL = @CRYWRAP_PATCHLEVEL@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXX_LT_AGE = @CXX_LT_AGE@
+CXX_LT_CURRENT = @CXX_LT_CURRENT@
+CXX_LT_REVISION = @CXX_LT_REVISION@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_VALGRINDFLAGS = @DEFAULT_VALGRINDFLAGS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DLL_SSL_VERSION = @DLL_SSL_VERSION@
+DLL_VERSION = @DLL_VERSION@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENABLE_PADLOCK = @ENABLE_PADLOCK@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FIPS140_LIBS = @FIPS140_LIBS@
+FLOAT_H = @FLOAT_H@
+GCOV = @GCOV@
+GENHTML = @GENHTML@
+GETADDRINFO_LIB = @GETADDRINFO_LIB@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GL_GGL_GNULIB_ACCEPT = @GL_GGL_GNULIB_ACCEPT@
+GL_GGL_GNULIB_ACCEPT4 = @GL_GGL_GNULIB_ACCEPT4@
+GL_GGL_GNULIB_ACCESS = @GL_GGL_GNULIB_ACCESS@
+GL_GGL_GNULIB_ALIGNED_ALLOC = @GL_GGL_GNULIB_ALIGNED_ALLOC@
+GL_GGL_GNULIB_ATOLL = @GL_GGL_GNULIB_ATOLL@
+GL_GGL_GNULIB_BIND = @GL_GGL_GNULIB_BIND@
+GL_GGL_GNULIB_BTOWC = @GL_GGL_GNULIB_BTOWC@
+GL_GGL_GNULIB_CALLOC_POSIX = @GL_GGL_GNULIB_CALLOC_POSIX@
+GL_GGL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GGL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GGL_GNULIB_CHDIR = @GL_GGL_GNULIB_CHDIR@
+GL_GGL_GNULIB_CHOWN = @GL_GGL_GNULIB_CHOWN@
+GL_GGL_GNULIB_CLOSE = @GL_GGL_GNULIB_CLOSE@
+GL_GGL_GNULIB_CONNECT = @GL_GGL_GNULIB_CONNECT@
+GL_GGL_GNULIB_COPY_FILE_RANGE = @GL_GGL_GNULIB_COPY_FILE_RANGE@
+GL_GGL_GNULIB_CREAT = @GL_GGL_GNULIB_CREAT@
+GL_GGL_GNULIB_CTIME = @GL_GGL_GNULIB_CTIME@
+GL_GGL_GNULIB_DPRINTF = @GL_GGL_GNULIB_DPRINTF@
+GL_GGL_GNULIB_DUP = @GL_GGL_GNULIB_DUP@
+GL_GGL_GNULIB_DUP2 = @GL_GGL_GNULIB_DUP2@
+GL_GGL_GNULIB_DUP3 = @GL_GGL_GNULIB_DUP3@
+GL_GGL_GNULIB_DUPLOCALE = @GL_GGL_GNULIB_DUPLOCALE@
+GL_GGL_GNULIB_ENVIRON = @GL_GGL_GNULIB_ENVIRON@
+GL_GGL_GNULIB_EUIDACCESS = @GL_GGL_GNULIB_EUIDACCESS@
+GL_GGL_GNULIB_EXECL = @GL_GGL_GNULIB_EXECL@
+GL_GGL_GNULIB_EXECLE = @GL_GGL_GNULIB_EXECLE@
+GL_GGL_GNULIB_EXECLP = @GL_GGL_GNULIB_EXECLP@
+GL_GGL_GNULIB_EXECV = @GL_GGL_GNULIB_EXECV@
+GL_GGL_GNULIB_EXECVE = @GL_GGL_GNULIB_EXECVE@
+GL_GGL_GNULIB_EXECVP = @GL_GGL_GNULIB_EXECVP@
+GL_GGL_GNULIB_EXECVPE = @GL_GGL_GNULIB_EXECVPE@
+GL_GGL_GNULIB_EXPLICIT_BZERO = @GL_GGL_GNULIB_EXPLICIT_BZERO@
+GL_GGL_GNULIB_FACCESSAT = @GL_GGL_GNULIB_FACCESSAT@
+GL_GGL_GNULIB_FCHDIR = @GL_GGL_GNULIB_FCHDIR@
+GL_GGL_GNULIB_FCHMODAT = @GL_GGL_GNULIB_FCHMODAT@
+GL_GGL_GNULIB_FCHOWNAT = @GL_GGL_GNULIB_FCHOWNAT@
+GL_GGL_GNULIB_FCLOSE = @GL_GGL_GNULIB_FCLOSE@
+GL_GGL_GNULIB_FCNTL = @GL_GGL_GNULIB_FCNTL@
+GL_GGL_GNULIB_FDATASYNC = @GL_GGL_GNULIB_FDATASYNC@
+GL_GGL_GNULIB_FDOPEN = @GL_GGL_GNULIB_FDOPEN@
+GL_GGL_GNULIB_FFLUSH = @GL_GGL_GNULIB_FFLUSH@
+GL_GGL_GNULIB_FFS = @GL_GGL_GNULIB_FFS@
+GL_GGL_GNULIB_FFSL = @GL_GGL_GNULIB_FFSL@
+GL_GGL_GNULIB_FFSLL = @GL_GGL_GNULIB_FFSLL@
+GL_GGL_GNULIB_FGETC = @GL_GGL_GNULIB_FGETC@
+GL_GGL_GNULIB_FGETS = @GL_GGL_GNULIB_FGETS@
+GL_GGL_GNULIB_FOPEN = @GL_GGL_GNULIB_FOPEN@
+GL_GGL_GNULIB_FPRINTF = @GL_GGL_GNULIB_FPRINTF@
+GL_GGL_GNULIB_FPRINTF_POSIX = @GL_GGL_GNULIB_FPRINTF_POSIX@
+GL_GGL_GNULIB_FPURGE = @GL_GGL_GNULIB_FPURGE@
+GL_GGL_GNULIB_FPUTC = @GL_GGL_GNULIB_FPUTC@
+GL_GGL_GNULIB_FPUTS = @GL_GGL_GNULIB_FPUTS@
+GL_GGL_GNULIB_FREAD = @GL_GGL_GNULIB_FREAD@
+GL_GGL_GNULIB_FREE_POSIX = @GL_GGL_GNULIB_FREE_POSIX@
+GL_GGL_GNULIB_FREOPEN = @GL_GGL_GNULIB_FREOPEN@
+GL_GGL_GNULIB_FSCANF = @GL_GGL_GNULIB_FSCANF@
+GL_GGL_GNULIB_FSEEK = @GL_GGL_GNULIB_FSEEK@
+GL_GGL_GNULIB_FSEEKO = @GL_GGL_GNULIB_FSEEKO@
+GL_GGL_GNULIB_FSTAT = @GL_GGL_GNULIB_FSTAT@
+GL_GGL_GNULIB_FSTATAT = @GL_GGL_GNULIB_FSTATAT@
+GL_GGL_GNULIB_FSYNC = @GL_GGL_GNULIB_FSYNC@
+GL_GGL_GNULIB_FTELL = @GL_GGL_GNULIB_FTELL@
+GL_GGL_GNULIB_FTELLO = @GL_GGL_GNULIB_FTELLO@
+GL_GGL_GNULIB_FTRUNCATE = @GL_GGL_GNULIB_FTRUNCATE@
+GL_GGL_GNULIB_FUTIMENS = @GL_GGL_GNULIB_FUTIMENS@
+GL_GGL_GNULIB_FWRITE = @GL_GGL_GNULIB_FWRITE@
+GL_GGL_GNULIB_GETADDRINFO = @GL_GGL_GNULIB_GETADDRINFO@
+GL_GGL_GNULIB_GETC = @GL_GGL_GNULIB_GETC@
+GL_GGL_GNULIB_GETCHAR = @GL_GGL_GNULIB_GETCHAR@
+GL_GGL_GNULIB_GETCWD = @GL_GGL_GNULIB_GETCWD@
+GL_GGL_GNULIB_GETDELIM = @GL_GGL_GNULIB_GETDELIM@
+GL_GGL_GNULIB_GETDOMAINNAME = @GL_GGL_GNULIB_GETDOMAINNAME@
+GL_GGL_GNULIB_GETDTABLESIZE = @GL_GGL_GNULIB_GETDTABLESIZE@
+GL_GGL_GNULIB_GETENTROPY = @GL_GGL_GNULIB_GETENTROPY@
+GL_GGL_GNULIB_GETGROUPS = @GL_GGL_GNULIB_GETGROUPS@
+GL_GGL_GNULIB_GETHOSTNAME = @GL_GGL_GNULIB_GETHOSTNAME@
+GL_GGL_GNULIB_GETLINE = @GL_GGL_GNULIB_GETLINE@
+GL_GGL_GNULIB_GETLOADAVG = @GL_GGL_GNULIB_GETLOADAVG@
+GL_GGL_GNULIB_GETLOGIN = @GL_GGL_GNULIB_GETLOGIN@
+GL_GGL_GNULIB_GETLOGIN_R = @GL_GGL_GNULIB_GETLOGIN_R@
+GL_GGL_GNULIB_GETOPT_POSIX = @GL_GGL_GNULIB_GETOPT_POSIX@
+GL_GGL_GNULIB_GETPAGESIZE = @GL_GGL_GNULIB_GETPAGESIZE@
+GL_GGL_GNULIB_GETPASS = @GL_GGL_GNULIB_GETPASS@
+GL_GGL_GNULIB_GETPEERNAME = @GL_GGL_GNULIB_GETPEERNAME@
+GL_GGL_GNULIB_GETSOCKNAME = @GL_GGL_GNULIB_GETSOCKNAME@
+GL_GGL_GNULIB_GETSOCKOPT = @GL_GGL_GNULIB_GETSOCKOPT@
+GL_GGL_GNULIB_GETSUBOPT = @GL_GGL_GNULIB_GETSUBOPT@
+GL_GGL_GNULIB_GETTIMEOFDAY = @GL_GGL_GNULIB_GETTIMEOFDAY@
+GL_GGL_GNULIB_GETUMASK = @GL_GGL_GNULIB_GETUMASK@
+GL_GGL_GNULIB_GETUSERSHELL = @GL_GGL_GNULIB_GETUSERSHELL@
+GL_GGL_GNULIB_GRANTPT = @GL_GGL_GNULIB_GRANTPT@
+GL_GGL_GNULIB_GROUP_MEMBER = @GL_GGL_GNULIB_GROUP_MEMBER@
+GL_GGL_GNULIB_IMAXABS = @GL_GGL_GNULIB_IMAXABS@
+GL_GGL_GNULIB_IMAXDIV = @GL_GGL_GNULIB_IMAXDIV@
+GL_GGL_GNULIB_INET_NTOP = @GL_GGL_GNULIB_INET_NTOP@
+GL_GGL_GNULIB_INET_PTON = @GL_GGL_GNULIB_INET_PTON@
+GL_GGL_GNULIB_IOCTL = @GL_GGL_GNULIB_IOCTL@
+GL_GGL_GNULIB_ISATTY = @GL_GGL_GNULIB_ISATTY@
+GL_GGL_GNULIB_ISBLANK = @GL_GGL_GNULIB_ISBLANK@
+GL_GGL_GNULIB_LCHMOD = @GL_GGL_GNULIB_LCHMOD@
+GL_GGL_GNULIB_LCHOWN = @GL_GGL_GNULIB_LCHOWN@
+GL_GGL_GNULIB_LINK = @GL_GGL_GNULIB_LINK@
+GL_GGL_GNULIB_LINKAT = @GL_GGL_GNULIB_LINKAT@
+GL_GGL_GNULIB_LISTEN = @GL_GGL_GNULIB_LISTEN@
+GL_GGL_GNULIB_LOCALECONV = @GL_GGL_GNULIB_LOCALECONV@
+GL_GGL_GNULIB_LOCALENAME = @GL_GGL_GNULIB_LOCALENAME@
+GL_GGL_GNULIB_LOCALTIME = @GL_GGL_GNULIB_LOCALTIME@
+GL_GGL_GNULIB_LSEEK = @GL_GGL_GNULIB_LSEEK@
+GL_GGL_GNULIB_LSTAT = @GL_GGL_GNULIB_LSTAT@
+GL_GGL_GNULIB_MALLOC_POSIX = @GL_GGL_GNULIB_MALLOC_POSIX@
+GL_GGL_GNULIB_MBRLEN = @GL_GGL_GNULIB_MBRLEN@
+GL_GGL_GNULIB_MBRTOWC = @GL_GGL_GNULIB_MBRTOWC@
+GL_GGL_GNULIB_MBSCASECMP = @GL_GGL_GNULIB_MBSCASECMP@
+GL_GGL_GNULIB_MBSCASESTR = @GL_GGL_GNULIB_MBSCASESTR@
+GL_GGL_GNULIB_MBSCHR = @GL_GGL_GNULIB_MBSCHR@
+GL_GGL_GNULIB_MBSCSPN = @GL_GGL_GNULIB_MBSCSPN@
+GL_GGL_GNULIB_MBSINIT = @GL_GGL_GNULIB_MBSINIT@
+GL_GGL_GNULIB_MBSLEN = @GL_GGL_GNULIB_MBSLEN@
+GL_GGL_GNULIB_MBSNCASECMP = @GL_GGL_GNULIB_MBSNCASECMP@
+GL_GGL_GNULIB_MBSNLEN = @GL_GGL_GNULIB_MBSNLEN@
+GL_GGL_GNULIB_MBSNRTOWCS = @GL_GGL_GNULIB_MBSNRTOWCS@
+GL_GGL_GNULIB_MBSPBRK = @GL_GGL_GNULIB_MBSPBRK@
+GL_GGL_GNULIB_MBSPCASECMP = @GL_GGL_GNULIB_MBSPCASECMP@
+GL_GGL_GNULIB_MBSRCHR = @GL_GGL_GNULIB_MBSRCHR@
+GL_GGL_GNULIB_MBSRTOWCS = @GL_GGL_GNULIB_MBSRTOWCS@
+GL_GGL_GNULIB_MBSSEP = @GL_GGL_GNULIB_MBSSEP@
+GL_GGL_GNULIB_MBSSPN = @GL_GGL_GNULIB_MBSSPN@
+GL_GGL_GNULIB_MBSSTR = @GL_GGL_GNULIB_MBSSTR@
+GL_GGL_GNULIB_MBSTOK_R = @GL_GGL_GNULIB_MBSTOK_R@
+GL_GGL_GNULIB_MBTOWC = @GL_GGL_GNULIB_MBTOWC@
+GL_GGL_GNULIB_MDA_ACCESS = @GL_GGL_GNULIB_MDA_ACCESS@
+GL_GGL_GNULIB_MDA_CHDIR = @GL_GGL_GNULIB_MDA_CHDIR@
+GL_GGL_GNULIB_MDA_CHMOD = @GL_GGL_GNULIB_MDA_CHMOD@
+GL_GGL_GNULIB_MDA_CLOSE = @GL_GGL_GNULIB_MDA_CLOSE@
+GL_GGL_GNULIB_MDA_CREAT = @GL_GGL_GNULIB_MDA_CREAT@
+GL_GGL_GNULIB_MDA_DUP = @GL_GGL_GNULIB_MDA_DUP@
+GL_GGL_GNULIB_MDA_DUP2 = @GL_GGL_GNULIB_MDA_DUP2@
+GL_GGL_GNULIB_MDA_ECVT = @GL_GGL_GNULIB_MDA_ECVT@
+GL_GGL_GNULIB_MDA_EXECL = @GL_GGL_GNULIB_MDA_EXECL@
+GL_GGL_GNULIB_MDA_EXECLE = @GL_GGL_GNULIB_MDA_EXECLE@
+GL_GGL_GNULIB_MDA_EXECLP = @GL_GGL_GNULIB_MDA_EXECLP@
+GL_GGL_GNULIB_MDA_EXECV = @GL_GGL_GNULIB_MDA_EXECV@
+GL_GGL_GNULIB_MDA_EXECVE = @GL_GGL_GNULIB_MDA_EXECVE@
+GL_GGL_GNULIB_MDA_EXECVP = @GL_GGL_GNULIB_MDA_EXECVP@
+GL_GGL_GNULIB_MDA_EXECVPE = @GL_GGL_GNULIB_MDA_EXECVPE@
+GL_GGL_GNULIB_MDA_FCLOSEALL = @GL_GGL_GNULIB_MDA_FCLOSEALL@
+GL_GGL_GNULIB_MDA_FCVT = @GL_GGL_GNULIB_MDA_FCVT@
+GL_GGL_GNULIB_MDA_FDOPEN = @GL_GGL_GNULIB_MDA_FDOPEN@
+GL_GGL_GNULIB_MDA_FILENO = @GL_GGL_GNULIB_MDA_FILENO@
+GL_GGL_GNULIB_MDA_GCVT = @GL_GGL_GNULIB_MDA_GCVT@
+GL_GGL_GNULIB_MDA_GETCWD = @GL_GGL_GNULIB_MDA_GETCWD@
+GL_GGL_GNULIB_MDA_GETPID = @GL_GGL_GNULIB_MDA_GETPID@
+GL_GGL_GNULIB_MDA_GETW = @GL_GGL_GNULIB_MDA_GETW@
+GL_GGL_GNULIB_MDA_ISATTY = @GL_GGL_GNULIB_MDA_ISATTY@
+GL_GGL_GNULIB_MDA_LSEEK = @GL_GGL_GNULIB_MDA_LSEEK@
+GL_GGL_GNULIB_MDA_MEMCCPY = @GL_GGL_GNULIB_MDA_MEMCCPY@
+GL_GGL_GNULIB_MDA_MKDIR = @GL_GGL_GNULIB_MDA_MKDIR@
+GL_GGL_GNULIB_MDA_MKTEMP = @GL_GGL_GNULIB_MDA_MKTEMP@
+GL_GGL_GNULIB_MDA_OPEN = @GL_GGL_GNULIB_MDA_OPEN@
+GL_GGL_GNULIB_MDA_PUTENV = @GL_GGL_GNULIB_MDA_PUTENV@
+GL_GGL_GNULIB_MDA_PUTW = @GL_GGL_GNULIB_MDA_PUTW@
+GL_GGL_GNULIB_MDA_READ = @GL_GGL_GNULIB_MDA_READ@
+GL_GGL_GNULIB_MDA_RMDIR = @GL_GGL_GNULIB_MDA_RMDIR@
+GL_GGL_GNULIB_MDA_STRDUP = @GL_GGL_GNULIB_MDA_STRDUP@
+GL_GGL_GNULIB_MDA_SWAB = @GL_GGL_GNULIB_MDA_SWAB@
+GL_GGL_GNULIB_MDA_TEMPNAM = @GL_GGL_GNULIB_MDA_TEMPNAM@
+GL_GGL_GNULIB_MDA_TZSET = @GL_GGL_GNULIB_MDA_TZSET@
+GL_GGL_GNULIB_MDA_UMASK = @GL_GGL_GNULIB_MDA_UMASK@
+GL_GGL_GNULIB_MDA_UNLINK = @GL_GGL_GNULIB_MDA_UNLINK@
+GL_GGL_GNULIB_MDA_WCSDUP = @GL_GGL_GNULIB_MDA_WCSDUP@
+GL_GGL_GNULIB_MDA_WRITE = @GL_GGL_GNULIB_MDA_WRITE@
+GL_GGL_GNULIB_MEMCHR = @GL_GGL_GNULIB_MEMCHR@
+GL_GGL_GNULIB_MEMMEM = @GL_GGL_GNULIB_MEMMEM@
+GL_GGL_GNULIB_MEMPCPY = @GL_GGL_GNULIB_MEMPCPY@
+GL_GGL_GNULIB_MEMRCHR = @GL_GGL_GNULIB_MEMRCHR@
+GL_GGL_GNULIB_MKDIR = @GL_GGL_GNULIB_MKDIR@
+GL_GGL_GNULIB_MKDIRAT = @GL_GGL_GNULIB_MKDIRAT@
+GL_GGL_GNULIB_MKDTEMP = @GL_GGL_GNULIB_MKDTEMP@
+GL_GGL_GNULIB_MKFIFO = @GL_GGL_GNULIB_MKFIFO@
+GL_GGL_GNULIB_MKFIFOAT = @GL_GGL_GNULIB_MKFIFOAT@
+GL_GGL_GNULIB_MKNOD = @GL_GGL_GNULIB_MKNOD@
+GL_GGL_GNULIB_MKNODAT = @GL_GGL_GNULIB_MKNODAT@
+GL_GGL_GNULIB_MKOSTEMP = @GL_GGL_GNULIB_MKOSTEMP@
+GL_GGL_GNULIB_MKOSTEMPS = @GL_GGL_GNULIB_MKOSTEMPS@
+GL_GGL_GNULIB_MKSTEMP = @GL_GGL_GNULIB_MKSTEMP@
+GL_GGL_GNULIB_MKSTEMPS = @GL_GGL_GNULIB_MKSTEMPS@
+GL_GGL_GNULIB_MKTIME = @GL_GGL_GNULIB_MKTIME@
+GL_GGL_GNULIB_NANOSLEEP = @GL_GGL_GNULIB_NANOSLEEP@
+GL_GGL_GNULIB_NL_LANGINFO = @GL_GGL_GNULIB_NL_LANGINFO@
+GL_GGL_GNULIB_NONBLOCKING = @GL_GGL_GNULIB_NONBLOCKING@
+GL_GGL_GNULIB_OBSTACK_PRINTF = @GL_GGL_GNULIB_OBSTACK_PRINTF@
+GL_GGL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GGL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GGL_GNULIB_OPEN = @GL_GGL_GNULIB_OPEN@
+GL_GGL_GNULIB_OPENAT = @GL_GGL_GNULIB_OPENAT@
+GL_GGL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GGL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GGL_GNULIB_PCLOSE = @GL_GGL_GNULIB_PCLOSE@
+GL_GGL_GNULIB_PERROR = @GL_GGL_GNULIB_PERROR@
+GL_GGL_GNULIB_PIPE = @GL_GGL_GNULIB_PIPE@
+GL_GGL_GNULIB_PIPE2 = @GL_GGL_GNULIB_PIPE2@
+GL_GGL_GNULIB_POPEN = @GL_GGL_GNULIB_POPEN@
+GL_GGL_GNULIB_POSIX_MEMALIGN = @GL_GGL_GNULIB_POSIX_MEMALIGN@
+GL_GGL_GNULIB_POSIX_OPENPT = @GL_GGL_GNULIB_POSIX_OPENPT@
+GL_GGL_GNULIB_PREAD = @GL_GGL_GNULIB_PREAD@
+GL_GGL_GNULIB_PRINTF = @GL_GGL_GNULIB_PRINTF@
+GL_GGL_GNULIB_PRINTF_POSIX = @GL_GGL_GNULIB_PRINTF_POSIX@
+GL_GGL_GNULIB_PSELECT = @GL_GGL_GNULIB_PSELECT@
+GL_GGL_GNULIB_PTHREAD_COND = @GL_GGL_GNULIB_PTHREAD_COND@
+GL_GGL_GNULIB_PTHREAD_MUTEX = @GL_GGL_GNULIB_PTHREAD_MUTEX@
+GL_GGL_GNULIB_PTHREAD_MUTEX_TIMEDLOCK = @GL_GGL_GNULIB_PTHREAD_MUTEX_TIMEDLOCK@
+GL_GGL_GNULIB_PTHREAD_ONCE = @GL_GGL_GNULIB_PTHREAD_ONCE@
+GL_GGL_GNULIB_PTHREAD_RWLOCK = @GL_GGL_GNULIB_PTHREAD_RWLOCK@
+GL_GGL_GNULIB_PTHREAD_SIGMASK = @GL_GGL_GNULIB_PTHREAD_SIGMASK@
+GL_GGL_GNULIB_PTHREAD_SPIN = @GL_GGL_GNULIB_PTHREAD_SPIN@
+GL_GGL_GNULIB_PTHREAD_THREAD = @GL_GGL_GNULIB_PTHREAD_THREAD@
+GL_GGL_GNULIB_PTHREAD_TSS = @GL_GGL_GNULIB_PTHREAD_TSS@
+GL_GGL_GNULIB_PTSNAME = @GL_GGL_GNULIB_PTSNAME@
+GL_GGL_GNULIB_PTSNAME_R = @GL_GGL_GNULIB_PTSNAME_R@
+GL_GGL_GNULIB_PUTC = @GL_GGL_GNULIB_PUTC@
+GL_GGL_GNULIB_PUTCHAR = @GL_GGL_GNULIB_PUTCHAR@
+GL_GGL_GNULIB_PUTENV = @GL_GGL_GNULIB_PUTENV@
+GL_GGL_GNULIB_PUTS = @GL_GGL_GNULIB_PUTS@
+GL_GGL_GNULIB_PWRITE = @GL_GGL_GNULIB_PWRITE@
+GL_GGL_GNULIB_QSORT_R = @GL_GGL_GNULIB_QSORT_R@
+GL_GGL_GNULIB_RAISE = @GL_GGL_GNULIB_RAISE@
+GL_GGL_GNULIB_RANDOM = @GL_GGL_GNULIB_RANDOM@
+GL_GGL_GNULIB_RANDOM_R = @GL_GGL_GNULIB_RANDOM_R@
+GL_GGL_GNULIB_RAWMEMCHR = @GL_GGL_GNULIB_RAWMEMCHR@
+GL_GGL_GNULIB_READ = @GL_GGL_GNULIB_READ@
+GL_GGL_GNULIB_READLINK = @GL_GGL_GNULIB_READLINK@
+GL_GGL_GNULIB_READLINKAT = @GL_GGL_GNULIB_READLINKAT@
+GL_GGL_GNULIB_REALLOCARRAY = @GL_GGL_GNULIB_REALLOCARRAY@
+GL_GGL_GNULIB_REALLOC_POSIX = @GL_GGL_GNULIB_REALLOC_POSIX@
+GL_GGL_GNULIB_REALPATH = @GL_GGL_GNULIB_REALPATH@
+GL_GGL_GNULIB_RECV = @GL_GGL_GNULIB_RECV@
+GL_GGL_GNULIB_RECVFROM = @GL_GGL_GNULIB_RECVFROM@
+GL_GGL_GNULIB_REMOVE = @GL_GGL_GNULIB_REMOVE@
+GL_GGL_GNULIB_RENAME = @GL_GGL_GNULIB_RENAME@
+GL_GGL_GNULIB_RENAMEAT = @GL_GGL_GNULIB_RENAMEAT@
+GL_GGL_GNULIB_RMDIR = @GL_GGL_GNULIB_RMDIR@
+GL_GGL_GNULIB_RPMATCH = @GL_GGL_GNULIB_RPMATCH@
+GL_GGL_GNULIB_SCANF = @GL_GGL_GNULIB_SCANF@
+GL_GGL_GNULIB_SCHED_YIELD = @GL_GGL_GNULIB_SCHED_YIELD@
+GL_GGL_GNULIB_SECURE_GETENV = @GL_GGL_GNULIB_SECURE_GETENV@
+GL_GGL_GNULIB_SELECT = @GL_GGL_GNULIB_SELECT@
+GL_GGL_GNULIB_SEND = @GL_GGL_GNULIB_SEND@
+GL_GGL_GNULIB_SENDTO = @GL_GGL_GNULIB_SENDTO@
+GL_GGL_GNULIB_SETENV = @GL_GGL_GNULIB_SETENV@
+GL_GGL_GNULIB_SETHOSTNAME = @GL_GGL_GNULIB_SETHOSTNAME@
+GL_GGL_GNULIB_SETLOCALE = @GL_GGL_GNULIB_SETLOCALE@
+GL_GGL_GNULIB_SETLOCALE_NULL = @GL_GGL_GNULIB_SETLOCALE_NULL@
+GL_GGL_GNULIB_SETSOCKOPT = @GL_GGL_GNULIB_SETSOCKOPT@
+GL_GGL_GNULIB_SHUTDOWN = @GL_GGL_GNULIB_SHUTDOWN@
+GL_GGL_GNULIB_SIGABBREV_NP = @GL_GGL_GNULIB_SIGABBREV_NP@
+GL_GGL_GNULIB_SIGACTION = @GL_GGL_GNULIB_SIGACTION@
+GL_GGL_GNULIB_SIGDESCR_NP = @GL_GGL_GNULIB_SIGDESCR_NP@
+GL_GGL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GGL_GNULIB_SIGNAL_H_SIGPIPE@
+GL_GGL_GNULIB_SIGPROCMASK = @GL_GGL_GNULIB_SIGPROCMASK@
+GL_GGL_GNULIB_SLEEP = @GL_GGL_GNULIB_SLEEP@
+GL_GGL_GNULIB_SNPRINTF = @GL_GGL_GNULIB_SNPRINTF@
+GL_GGL_GNULIB_SOCKET = @GL_GGL_GNULIB_SOCKET@
+GL_GGL_GNULIB_SPRINTF_POSIX = @GL_GGL_GNULIB_SPRINTF_POSIX@
+GL_GGL_GNULIB_STAT = @GL_GGL_GNULIB_STAT@
+GL_GGL_GNULIB_STDIO_H_NONBLOCKING = @GL_GGL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GGL_GNULIB_STDIO_H_SIGPIPE = @GL_GGL_GNULIB_STDIO_H_SIGPIPE@
+GL_GGL_GNULIB_STPCPY = @GL_GGL_GNULIB_STPCPY@
+GL_GGL_GNULIB_STPNCPY = @GL_GGL_GNULIB_STPNCPY@
+GL_GGL_GNULIB_STRCASESTR = @GL_GGL_GNULIB_STRCASESTR@
+GL_GGL_GNULIB_STRCHRNUL = @GL_GGL_GNULIB_STRCHRNUL@
+GL_GGL_GNULIB_STRDUP = @GL_GGL_GNULIB_STRDUP@
+GL_GGL_GNULIB_STRERROR = @GL_GGL_GNULIB_STRERROR@
+GL_GGL_GNULIB_STRERRORNAME_NP = @GL_GGL_GNULIB_STRERRORNAME_NP@
+GL_GGL_GNULIB_STRERROR_R = @GL_GGL_GNULIB_STRERROR_R@
+GL_GGL_GNULIB_STRFTIME = @GL_GGL_GNULIB_STRFTIME@
+GL_GGL_GNULIB_STRNCAT = @GL_GGL_GNULIB_STRNCAT@
+GL_GGL_GNULIB_STRNDUP = @GL_GGL_GNULIB_STRNDUP@
+GL_GGL_GNULIB_STRNLEN = @GL_GGL_GNULIB_STRNLEN@
+GL_GGL_GNULIB_STRPBRK = @GL_GGL_GNULIB_STRPBRK@
+GL_GGL_GNULIB_STRPTIME = @GL_GGL_GNULIB_STRPTIME@
+GL_GGL_GNULIB_STRSEP = @GL_GGL_GNULIB_STRSEP@
+GL_GGL_GNULIB_STRSIGNAL = @GL_GGL_GNULIB_STRSIGNAL@
+GL_GGL_GNULIB_STRSTR = @GL_GGL_GNULIB_STRSTR@
+GL_GGL_GNULIB_STRTOD = @GL_GGL_GNULIB_STRTOD@
+GL_GGL_GNULIB_STRTOIMAX = @GL_GGL_GNULIB_STRTOIMAX@
+GL_GGL_GNULIB_STRTOK_R = @GL_GGL_GNULIB_STRTOK_R@
+GL_GGL_GNULIB_STRTOL = @GL_GGL_GNULIB_STRTOL@
+GL_GGL_GNULIB_STRTOLD = @GL_GGL_GNULIB_STRTOLD@
+GL_GGL_GNULIB_STRTOLL = @GL_GGL_GNULIB_STRTOLL@
+GL_GGL_GNULIB_STRTOUL = @GL_GGL_GNULIB_STRTOUL@
+GL_GGL_GNULIB_STRTOULL = @GL_GGL_GNULIB_STRTOULL@
+GL_GGL_GNULIB_STRTOUMAX = @GL_GGL_GNULIB_STRTOUMAX@
+GL_GGL_GNULIB_STRVERSCMP = @GL_GGL_GNULIB_STRVERSCMP@
+GL_GGL_GNULIB_SYMLINK = @GL_GGL_GNULIB_SYMLINK@
+GL_GGL_GNULIB_SYMLINKAT = @GL_GGL_GNULIB_SYMLINKAT@
+GL_GGL_GNULIB_SYSTEM_POSIX = @GL_GGL_GNULIB_SYSTEM_POSIX@
+GL_GGL_GNULIB_TIMEGM = @GL_GGL_GNULIB_TIMEGM@
+GL_GGL_GNULIB_TIMESPEC_GET = @GL_GGL_GNULIB_TIMESPEC_GET@
+GL_GGL_GNULIB_TIME_R = @GL_GGL_GNULIB_TIME_R@
+GL_GGL_GNULIB_TIME_RZ = @GL_GGL_GNULIB_TIME_RZ@
+GL_GGL_GNULIB_TMPFILE = @GL_GGL_GNULIB_TMPFILE@
+GL_GGL_GNULIB_TRUNCATE = @GL_GGL_GNULIB_TRUNCATE@
+GL_GGL_GNULIB_TTYNAME_R = @GL_GGL_GNULIB_TTYNAME_R@
+GL_GGL_GNULIB_TZSET = @GL_GGL_GNULIB_TZSET@
+GL_GGL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GGL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GGL_GNULIB_UNISTD_H_SIGPIPE = @GL_GGL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GGL_GNULIB_UNLINK = @GL_GGL_GNULIB_UNLINK@
+GL_GGL_GNULIB_UNLINKAT = @GL_GGL_GNULIB_UNLINKAT@
+GL_GGL_GNULIB_UNLOCKPT = @GL_GGL_GNULIB_UNLOCKPT@
+GL_GGL_GNULIB_UNSETENV = @GL_GGL_GNULIB_UNSETENV@
+GL_GGL_GNULIB_USLEEP = @GL_GGL_GNULIB_USLEEP@
+GL_GGL_GNULIB_UTIMENSAT = @GL_GGL_GNULIB_UTIMENSAT@
+GL_GGL_GNULIB_VASPRINTF = @GL_GGL_GNULIB_VASPRINTF@
+GL_GGL_GNULIB_VDPRINTF = @GL_GGL_GNULIB_VDPRINTF@
+GL_GGL_GNULIB_VFPRINTF = @GL_GGL_GNULIB_VFPRINTF@
+GL_GGL_GNULIB_VFPRINTF_POSIX = @GL_GGL_GNULIB_VFPRINTF_POSIX@
+GL_GGL_GNULIB_VFSCANF = @GL_GGL_GNULIB_VFSCANF@
+GL_GGL_GNULIB_VPRINTF = @GL_GGL_GNULIB_VPRINTF@
+GL_GGL_GNULIB_VPRINTF_POSIX = @GL_GGL_GNULIB_VPRINTF_POSIX@
+GL_GGL_GNULIB_VSCANF = @GL_GGL_GNULIB_VSCANF@
+GL_GGL_GNULIB_VSNPRINTF = @GL_GGL_GNULIB_VSNPRINTF@
+GL_GGL_GNULIB_VSPRINTF_POSIX = @GL_GGL_GNULIB_VSPRINTF_POSIX@
+GL_GGL_GNULIB_WCPCPY = @GL_GGL_GNULIB_WCPCPY@
+GL_GGL_GNULIB_WCPNCPY = @GL_GGL_GNULIB_WCPNCPY@
+GL_GGL_GNULIB_WCRTOMB = @GL_GGL_GNULIB_WCRTOMB@
+GL_GGL_GNULIB_WCSCASECMP = @GL_GGL_GNULIB_WCSCASECMP@
+GL_GGL_GNULIB_WCSCAT = @GL_GGL_GNULIB_WCSCAT@
+GL_GGL_GNULIB_WCSCHR = @GL_GGL_GNULIB_WCSCHR@
+GL_GGL_GNULIB_WCSCMP = @GL_GGL_GNULIB_WCSCMP@
+GL_GGL_GNULIB_WCSCOLL = @GL_GGL_GNULIB_WCSCOLL@
+GL_GGL_GNULIB_WCSCPY = @GL_GGL_GNULIB_WCSCPY@
+GL_GGL_GNULIB_WCSCSPN = @GL_GGL_GNULIB_WCSCSPN@
+GL_GGL_GNULIB_WCSDUP = @GL_GGL_GNULIB_WCSDUP@
+GL_GGL_GNULIB_WCSFTIME = @GL_GGL_GNULIB_WCSFTIME@
+GL_GGL_GNULIB_WCSLEN = @GL_GGL_GNULIB_WCSLEN@
+GL_GGL_GNULIB_WCSNCASECMP = @GL_GGL_GNULIB_WCSNCASECMP@
+GL_GGL_GNULIB_WCSNCAT = @GL_GGL_GNULIB_WCSNCAT@
+GL_GGL_GNULIB_WCSNCMP = @GL_GGL_GNULIB_WCSNCMP@
+GL_GGL_GNULIB_WCSNCPY = @GL_GGL_GNULIB_WCSNCPY@
+GL_GGL_GNULIB_WCSNLEN = @GL_GGL_GNULIB_WCSNLEN@
+GL_GGL_GNULIB_WCSNRTOMBS = @GL_GGL_GNULIB_WCSNRTOMBS@
+GL_GGL_GNULIB_WCSPBRK = @GL_GGL_GNULIB_WCSPBRK@
+GL_GGL_GNULIB_WCSRCHR = @GL_GGL_GNULIB_WCSRCHR@
+GL_GGL_GNULIB_WCSRTOMBS = @GL_GGL_GNULIB_WCSRTOMBS@
+GL_GGL_GNULIB_WCSSPN = @GL_GGL_GNULIB_WCSSPN@
+GL_GGL_GNULIB_WCSSTR = @GL_GGL_GNULIB_WCSSTR@
+GL_GGL_GNULIB_WCSTOK = @GL_GGL_GNULIB_WCSTOK@
+GL_GGL_GNULIB_WCSWIDTH = @GL_GGL_GNULIB_WCSWIDTH@
+GL_GGL_GNULIB_WCSXFRM = @GL_GGL_GNULIB_WCSXFRM@
+GL_GGL_GNULIB_WCTOB = @GL_GGL_GNULIB_WCTOB@
+GL_GGL_GNULIB_WCTOMB = @GL_GGL_GNULIB_WCTOMB@
+GL_GGL_GNULIB_WCWIDTH = @GL_GGL_GNULIB_WCWIDTH@
+GL_GGL_GNULIB_WMEMCHR = @GL_GGL_GNULIB_WMEMCHR@
+GL_GGL_GNULIB_WMEMCMP = @GL_GGL_GNULIB_WMEMCMP@
+GL_GGL_GNULIB_WMEMCPY = @GL_GGL_GNULIB_WMEMCPY@
+GL_GGL_GNULIB_WMEMMOVE = @GL_GGL_GNULIB_WMEMMOVE@
+GL_GGL_GNULIB_WMEMPCPY = @GL_GGL_GNULIB_WMEMPCPY@
+GL_GGL_GNULIB_WMEMSET = @GL_GGL_GNULIB_WMEMSET@
+GL_GGL_GNULIB_WRITE = @GL_GGL_GNULIB_WRITE@
+GL_GGL_GNULIB__EXIT = @GL_GGL_GNULIB__EXIT@
+GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@
+GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_BIND = @GL_GNULIB_BIND@
+GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFS = @GL_GNULIB_FFS@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETADDRINFO = @GL_GNULIB_GETADDRINFO@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@
+GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@
+GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_INET_NTOP = @GL_GNULIB_INET_NTOP@
+GL_GNULIB_INET_PTON = @GL_GNULIB_INET_PTON@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@
+GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_RECV = @GL_GNULIB_RECV@
+GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SEND = @GL_GNULIB_SEND@
+GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@
+GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@
+GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@
+GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@
+GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@
+GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@
+GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@
+GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@
+GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@
+GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@
+GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@
+GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@
+GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@
+GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@
+GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@
+GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@
+GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@
+GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@
+GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@
+GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@
+GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@
+GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@
+GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@
+GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@
+GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@
+GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@
+GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@
+GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@
+GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@
+GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@
+GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@
+GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@
+GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@
+GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@
+GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
+GMP_CFLAGS = @GMP_CFLAGS@
+GMP_LIBS = @GMP_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GNUTLS_LIBS_PRIVATE = @GNUTLS_LIBS_PRIVATE@
+GNUTLS_REQUIRES_PRIVATE = @GNUTLS_REQUIRES_PRIVATE@
+GPERF = @GPERF@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUILD = @GUILD@
+GUILE = @GUILE@
+GUILE_CFLAGS = @GUILE_CFLAGS@
+GUILE_CONFIG = @GUILE_CONFIG@
+GUILE_EFFECTIVE_VERSION = @GUILE_EFFECTIVE_VERSION@
+GUILE_EXTENSION = @GUILE_EXTENSION@
+GUILE_LDFLAGS = @GUILE_LDFLAGS@
+GUILE_LIBS = @GUILE_LIBS@
+GUILE_LTLIBS = @GUILE_LTLIBS@
+GUILE_SITE = @GUILE_SITE@
+GUILE_SITE_CCACHE = @GUILE_SITE_CCACHE@
+GUILE_TOOLS = @GUILE_TOOLS@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
+HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@
+HAVE_DECL_FCVT = @HAVE_DECL_FCVT@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_FREEADDRINFO = @HAVE_DECL_FREEADDRINFO@
+HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@
+HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@
+HAVE_DECL_GAI_STRERROR = @HAVE_DECL_GAI_STRERROR@
+HAVE_DECL_GCVT = @HAVE_DECL_GCVT@
+HAVE_DECL_GETADDRINFO = @HAVE_DECL_GETADDRINFO@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_GETNAMEINFO = @HAVE_DECL_GETNAMEINFO@
+HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@
+HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@
+HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_SETENV = @HAVE_DECL_SETENV@
+HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@
+HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCSDUP = @HAVE_DECL_WCSDUP@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_EXECVPE = @HAVE_EXECVPE@
+HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHDIR = @HAVE_FCHDIR@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDATASYNC = @HAVE_FDATASYNC@
+HAVE_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFS = @HAVE_FFS@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+HAVE_FREELOCALE = @HAVE_FREELOCALE@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETENTROPY = @HAVE_GETENTROPY@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETPASS = @HAVE_GETPASS@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@
+HAVE_GETUMASK = @HAVE_GETUMASK@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@
+HAVE_INITSTATE = @HAVE_INITSTATE@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISBLANK = @HAVE_ISBLANK@
+HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@
+HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@
+HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@
+HAVE_LANGINFO_H = @HAVE_LANGINFO_H@
+HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@
+HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LIBCRYPTO = @HAVE_LIBCRYPTO@
+HAVE_LIBDL = @HAVE_LIBDL@
+HAVE_LIBEV = @HAVE_LIBEV@
+HAVE_LIBPTHREAD = @HAVE_LIBPTHREAD@
+HAVE_LIBRT = @HAVE_LIBRT@
+HAVE_LIBSECCOMP = @HAVE_LIBSECCOMP@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMP = @HAVE_MKSTEMP@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@
+HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NETDB_H = @HAVE_NETDB_H@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+HAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@
+HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@
+HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_PSELECT = @HAVE_PSELECT@
+HAVE_PTHREAD_ATTR_DESTROY = @HAVE_PTHREAD_ATTR_DESTROY@
+HAVE_PTHREAD_ATTR_GETDETACHSTATE = @HAVE_PTHREAD_ATTR_GETDETACHSTATE@
+HAVE_PTHREAD_ATTR_INIT = @HAVE_PTHREAD_ATTR_INIT@
+HAVE_PTHREAD_ATTR_SETDETACHSTATE = @HAVE_PTHREAD_ATTR_SETDETACHSTATE@
+HAVE_PTHREAD_CONDATTR_DESTROY = @HAVE_PTHREAD_CONDATTR_DESTROY@
+HAVE_PTHREAD_CONDATTR_INIT = @HAVE_PTHREAD_CONDATTR_INIT@
+HAVE_PTHREAD_COND_BROADCAST = @HAVE_PTHREAD_COND_BROADCAST@
+HAVE_PTHREAD_COND_DESTROY = @HAVE_PTHREAD_COND_DESTROY@
+HAVE_PTHREAD_COND_INIT = @HAVE_PTHREAD_COND_INIT@
+HAVE_PTHREAD_COND_SIGNAL = @HAVE_PTHREAD_COND_SIGNAL@
+HAVE_PTHREAD_COND_TIMEDWAIT = @HAVE_PTHREAD_COND_TIMEDWAIT@
+HAVE_PTHREAD_COND_WAIT = @HAVE_PTHREAD_COND_WAIT@
+HAVE_PTHREAD_CREATE = @HAVE_PTHREAD_CREATE@
+HAVE_PTHREAD_CREATE_DETACHED = @HAVE_PTHREAD_CREATE_DETACHED@
+HAVE_PTHREAD_DETACH = @HAVE_PTHREAD_DETACH@
+HAVE_PTHREAD_EQUAL = @HAVE_PTHREAD_EQUAL@
+HAVE_PTHREAD_EXIT = @HAVE_PTHREAD_EXIT@
+HAVE_PTHREAD_GETSPECIFIC = @HAVE_PTHREAD_GETSPECIFIC@
+HAVE_PTHREAD_H = @HAVE_PTHREAD_H@
+HAVE_PTHREAD_JOIN = @HAVE_PTHREAD_JOIN@
+HAVE_PTHREAD_KEY_CREATE = @HAVE_PTHREAD_KEY_CREATE@
+HAVE_PTHREAD_KEY_DELETE = @HAVE_PTHREAD_KEY_DELETE@
+HAVE_PTHREAD_MUTEXATTR_DESTROY = @HAVE_PTHREAD_MUTEXATTR_DESTROY@
+HAVE_PTHREAD_MUTEXATTR_GETROBUST = @HAVE_PTHREAD_MUTEXATTR_GETROBUST@
+HAVE_PTHREAD_MUTEXATTR_GETTYPE = @HAVE_PTHREAD_MUTEXATTR_GETTYPE@
+HAVE_PTHREAD_MUTEXATTR_INIT = @HAVE_PTHREAD_MUTEXATTR_INIT@
+HAVE_PTHREAD_MUTEXATTR_SETROBUST = @HAVE_PTHREAD_MUTEXATTR_SETROBUST@
+HAVE_PTHREAD_MUTEXATTR_SETTYPE = @HAVE_PTHREAD_MUTEXATTR_SETTYPE@
+HAVE_PTHREAD_MUTEX_DESTROY = @HAVE_PTHREAD_MUTEX_DESTROY@
+HAVE_PTHREAD_MUTEX_INIT = @HAVE_PTHREAD_MUTEX_INIT@
+HAVE_PTHREAD_MUTEX_LOCK = @HAVE_PTHREAD_MUTEX_LOCK@
+HAVE_PTHREAD_MUTEX_RECURSIVE = @HAVE_PTHREAD_MUTEX_RECURSIVE@
+HAVE_PTHREAD_MUTEX_ROBUST = @HAVE_PTHREAD_MUTEX_ROBUST@
+HAVE_PTHREAD_MUTEX_TIMEDLOCK = @HAVE_PTHREAD_MUTEX_TIMEDLOCK@
+HAVE_PTHREAD_MUTEX_TRYLOCK = @HAVE_PTHREAD_MUTEX_TRYLOCK@
+HAVE_PTHREAD_MUTEX_UNLOCK = @HAVE_PTHREAD_MUTEX_UNLOCK@
+HAVE_PTHREAD_ONCE = @HAVE_PTHREAD_ONCE@
+HAVE_PTHREAD_PROCESS_SHARED = @HAVE_PTHREAD_PROCESS_SHARED@
+HAVE_PTHREAD_RWLOCKATTR_DESTROY = @HAVE_PTHREAD_RWLOCKATTR_DESTROY@
+HAVE_PTHREAD_RWLOCKATTR_INIT = @HAVE_PTHREAD_RWLOCKATTR_INIT@
+HAVE_PTHREAD_RWLOCK_DESTROY = @HAVE_PTHREAD_RWLOCK_DESTROY@
+HAVE_PTHREAD_RWLOCK_INIT = @HAVE_PTHREAD_RWLOCK_INIT@
+HAVE_PTHREAD_RWLOCK_RDLOCK = @HAVE_PTHREAD_RWLOCK_RDLOCK@
+HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK = @HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK@
+HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK = @HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK@
+HAVE_PTHREAD_RWLOCK_TRYRDLOCK = @HAVE_PTHREAD_RWLOCK_TRYRDLOCK@
+HAVE_PTHREAD_RWLOCK_TRYWRLOCK = @HAVE_PTHREAD_RWLOCK_TRYWRLOCK@
+HAVE_PTHREAD_RWLOCK_UNLOCK = @HAVE_PTHREAD_RWLOCK_UNLOCK@
+HAVE_PTHREAD_RWLOCK_WRLOCK = @HAVE_PTHREAD_RWLOCK_WRLOCK@
+HAVE_PTHREAD_SELF = @HAVE_PTHREAD_SELF@
+HAVE_PTHREAD_SETSPECIFIC = @HAVE_PTHREAD_SETSPECIFIC@
+HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@
+HAVE_PTHREAD_SPINLOCK_T = @HAVE_PTHREAD_SPINLOCK_T@
+HAVE_PTHREAD_SPIN_DESTROY = @HAVE_PTHREAD_SPIN_DESTROY@
+HAVE_PTHREAD_SPIN_INIT = @HAVE_PTHREAD_SPIN_INIT@
+HAVE_PTHREAD_SPIN_LOCK = @HAVE_PTHREAD_SPIN_LOCK@
+HAVE_PTHREAD_SPIN_TRYLOCK = @HAVE_PTHREAD_SPIN_TRYLOCK@
+HAVE_PTHREAD_SPIN_UNLOCK = @HAVE_PTHREAD_SPIN_UNLOCK@
+HAVE_PTHREAD_T = @HAVE_PTHREAD_T@
+HAVE_PTSNAME = @HAVE_PTSNAME@
+HAVE_PTSNAME_R = @HAVE_PTSNAME_R@
+HAVE_PWRITE = @HAVE_PWRITE@
+HAVE_QSORT_R = @HAVE_QSORT_R@
+HAVE_RAISE = @HAVE_RAISE@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SCHED_H = @HAVE_SCHED_H@
+HAVE_SCHED_YIELD = @HAVE_SCHED_YIELD@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
+HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@
+HAVE_SIGACTION = @HAVE_SIGACTION@
+HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@
+HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@
+HAVE_SIGINFO_T = @HAVE_SIGINFO_T@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SIGSET_T = @HAVE_SIGSET_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@
+HAVE_STRINGS_H = @HAVE_STRINGS_H@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
+HAVE_STRTOLD = @HAVE_STRTOLD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_ADDRINFO = @HAVE_STRUCT_ADDRINFO@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_SCHED_PARAM = @HAVE_STRUCT_SCHED_PARAM@
+HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@
+HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@
+HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_IOCTL_H = @HAVE_SYS_IOCTL_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@
+HAVE_TIMEGM = @HAVE_TIMEGM@
+HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@
+HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@
+HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNLOCKPT = @HAVE_UNLOCKPT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCPCPY = @HAVE_WCPCPY@
+HAVE_WCPNCPY = @HAVE_WCPNCPY@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSCASECMP = @HAVE_WCSCASECMP@
+HAVE_WCSCAT = @HAVE_WCSCAT@
+HAVE_WCSCHR = @HAVE_WCSCHR@
+HAVE_WCSCMP = @HAVE_WCSCMP@
+HAVE_WCSCOLL = @HAVE_WCSCOLL@
+HAVE_WCSCPY = @HAVE_WCSCPY@
+HAVE_WCSCSPN = @HAVE_WCSCSPN@
+HAVE_WCSDUP = @HAVE_WCSDUP@
+HAVE_WCSFTIME = @HAVE_WCSFTIME@
+HAVE_WCSLEN = @HAVE_WCSLEN@
+HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@
+HAVE_WCSNCAT = @HAVE_WCSNCAT@
+HAVE_WCSNCMP = @HAVE_WCSNCMP@
+HAVE_WCSNCPY = @HAVE_WCSNCPY@
+HAVE_WCSNLEN = @HAVE_WCSNLEN@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSPBRK = @HAVE_WCSPBRK@
+HAVE_WCSRCHR = @HAVE_WCSRCHR@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCSSPN = @HAVE_WCSSPN@
+HAVE_WCSSTR = @HAVE_WCSSTR@
+HAVE_WCSTOK = @HAVE_WCSTOK@
+HAVE_WCSWIDTH = @HAVE_WCSWIDTH@
+HAVE_WCSXFRM = @HAVE_WCSXFRM@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE_WMEMCHR = @HAVE_WMEMCHR@
+HAVE_WMEMCMP = @HAVE_WMEMCMP@
+HAVE_WMEMCPY = @HAVE_WMEMCPY@
+HAVE_WMEMMOVE = @HAVE_WMEMMOVE@
+HAVE_WMEMPCPY = @HAVE_WMEMPCPY@
+HAVE_WMEMSET = @HAVE_WMEMSET@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE_XLOCALE_H = @HAVE_XLOCALE_H@
+HAVE__BOOL = @HAVE__BOOL@
+HAVE__EXIT = @HAVE__EXIT@
+HOGWEED_CFLAGS = @HOGWEED_CFLAGS@
+HOGWEED_LIBS = @HOGWEED_LIBS@
+HOSTENT_LIB = @HOSTENT_LIB@
+HTML_DIR = @HTML_DIR@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INET_NTOP_LIB = @INET_NTOP_LIB@
+INET_PTON_LIB = @INET_PTON_LIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LCOV = @LCOV@
+LD = @LD@
+LDDPOSTPROC = @LDDPOSTPROC@
+LDDPROG = @LDDPROG@
+LDFLAGS = @LDFLAGS@
+LIBATOMIC_LIBS = @LIBATOMIC_LIBS@
+LIBBROTLIDEC_CFLAGS = @LIBBROTLIDEC_CFLAGS@
+LIBBROTLIDEC_LIBS = @LIBBROTLIDEC_LIBS@
+LIBBROTLIENC_CFLAGS = @LIBBROTLIENC_CFLAGS@
+LIBBROTLIENC_LIBS = @LIBBROTLIENC_LIBS@
+LIBCRYPTO = @LIBCRYPTO@
+LIBCRYPTO_PREFIX = @LIBCRYPTO_PREFIX@
+LIBDL = @LIBDL@
+LIBDL_PREFIX = @LIBDL_PREFIX@
+LIBEV = @LIBEV@
+LIBEV_LIBS = @LIBEV_LIBS@
+LIBEV_PREFIX = @LIBEV_PREFIX@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBICONV = @LIBICONV@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBINTL = @LIBINTL@
+LIBKCAPI_CFLAGS = @LIBKCAPI_CFLAGS@
+LIBKCAPI_LIBS = @LIBKCAPI_LIBS@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPMULTITHREAD = @LIBPMULTITHREAD@
+LIBPTHREAD = @LIBPTHREAD@
+LIBPTHREAD_PREFIX = @LIBPTHREAD_PREFIX@
+LIBRT = @LIBRT@
+LIBRT_PREFIX = @LIBRT_PREFIX@
+LIBS = @LIBS@
+LIBSECCOMP = @LIBSECCOMP@
+LIBSECCOMP_PREFIX = @LIBSECCOMP_PREFIX@
+LIBSOCKET = @LIBSOCKET@
+LIBSTDTHREAD = @LIBSTDTHREAD@
+LIBTASN1_CFLAGS = @LIBTASN1_CFLAGS@
+LIBTASN1_LIBS = @LIBTASN1_LIBS@
+LIBTESTS_LIBDEPS = @LIBTESTS_LIBDEPS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBUNISTRING = @LIBUNISTRING@
+LIBUNISTRING_UNICTYPE_H = @LIBUNISTRING_UNICTYPE_H@
+LIBUNISTRING_UNINORM_H = @LIBUNISTRING_UNINORM_H@
+LIBUNISTRING_UNISTR_H = @LIBUNISTRING_UNISTR_H@
+LIBUNISTRING_UNITYPES_H = @LIBUNISTRING_UNITYPES_H@
+LIBZ = @LIBZ@
+LIBZSTD_CFLAGS = @LIBZSTD_CFLAGS@
+LIBZSTD_LIBS = @LIBZSTD_LIBS@
+LIBZ_PC = @LIBZ_PC@
+LIBZ_PREFIX = @LIBZ_PREFIX@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LIB_PTHREAD = @LIB_PTHREAD@
+LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
+LIB_SCHED_YIELD = @LIB_SCHED_YIELD@
+LIB_SELECT = @LIB_SELECT@
+LIB_SEMAPHORE = @LIB_SEMAPHORE@
+LIB_SETLOCALE = @LIB_SETLOCALE@
+LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@
+LIMITS_H = @LIMITS_H@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@
+LOCALE_FR = @LOCALE_FR@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_TR_UTF8 = @LOCALE_TR_UTF8@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LOG_VALGRIND = @LOG_VALGRIND@
+LTALLOCA = @LTALLOCA@
+LTLIBCRYPTO = @LTLIBCRYPTO@
+LTLIBDL = @LTLIBDL@
+LTLIBEV = @LTLIBEV@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTHREAD = @LTLIBPTHREAD@
+LTLIBRT = @LTLIBRT@
+LTLIBSECCOMP = @LTLIBSECCOMP@
+LTLIBTHREAD = @LTLIBTHREAD@
+LTLIBZ = @LTLIBZ@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_DANE_AGE = @LT_DANE_AGE@
+LT_DANE_CURRENT = @LT_DANE_CURRENT@
+LT_DANE_REVISION = @LT_DANE_REVISION@
+LT_REVISION = @LT_REVISION@
+LT_SSL_AGE = @LT_SSL_AGE@
+LT_SSL_CURRENT = @LT_SSL_CURRENT@
+LT_SSL_REVISION = @LT_SSL_REVISION@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_XSSL_AGE = @LT_XSSL_AGE@
+LT_XSSL_CURRENT = @LT_XSSL_CURRENT@
+LT_XSSL_REVISION = @LT_XSSL_REVISION@
+MAINT = @MAINT@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MINOR_VERSION = @MINOR_VERSION@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
+NETINET_IN_H = @NETINET_IN_H@
+NETTLE_CFLAGS = @NETTLE_CFLAGS@
+NETTLE_LIBS = @NETTLE_LIBS@
+NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@
+NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
+NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@
+NEXT_AS_FIRST_DIRECTIVE_NETDB_H = @NEXT_AS_FIRST_DIRECTIVE_NETDB_H@
+NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@
+NEXT_AS_FIRST_DIRECTIVE_PTHREAD_H = @NEXT_AS_FIRST_DIRECTIVE_PTHREAD_H@
+NEXT_AS_FIRST_DIRECTIVE_SCHED_H = @NEXT_AS_FIRST_DIRECTIVE_SCHED_H@
+NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_CTYPE_H = @NEXT_CTYPE_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_H@
+NEXT_LIMITS_H = @NEXT_LIMITS_H@
+NEXT_LOCALE_H = @NEXT_LOCALE_H@
+NEXT_NETDB_H = @NEXT_NETDB_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_PTHREAD_H = @NEXT_PTHREAD_H@
+NEXT_SCHED_H = @NEXT_SCHED_H@
+NEXT_SIGNAL_H = @NEXT_SIGNAL_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRINGS_H = @NEXT_STRINGS_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_IOCTL_H = @NEXT_SYS_IOCTL_H@
+NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@
+NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NUMBER_VERSION = @NUMBER_VERSION@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11_KIT_CFLAGS = @P11_KIT_CFLAGS@
+P11_KIT_LIBS = @P11_KIT_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARSE_DATETIME_BISON = @PARSE_DATETIME_BISON@
+PATCH_VERSION = @PATCH_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKCS12_ITER_COUNT = @PKCS12_ITER_COUNT@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PMCCABE = @PMCCABE@
+POSUB = @POSUB@
+PRAGMA_COLUMNS = @PRAGMA_COLUMNS@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+REPLACE_ACCESS = @REPLACE_ACCESS@
+REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC = @REPLACE_CALLOC@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_CREAT = @REPLACE_CREAT@
+REPLACE_CTIME = @REPLACE_CTIME@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_EXECL = @REPLACE_EXECL@
+REPLACE_EXECLE = @REPLACE_EXECLE@
+REPLACE_EXECLP = @REPLACE_EXECLP@
+REPLACE_EXECV = @REPLACE_EXECV@
+REPLACE_EXECVE = @REPLACE_EXECVE@
+REPLACE_EXECVP = @REPLACE_EXECVP@
+REPLACE_EXECVPE = @REPLACE_EXECVPE@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
+REPLACE_FCHMODAT = @REPLACE_FCHMODAT@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FFSLL = @REPLACE_FFSLL@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREE = @REPLACE_FREE@
+REPLACE_FREELOCALE = @REPLACE_FREELOCALE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GAI_STRERROR = @REPLACE_GAI_STRERROR@
+REPLACE_GETADDRINFO = @REPLACE_GETADDRINFO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@
+REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETPASS = @REPLACE_GETPASS@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_INET_NTOP = @REPLACE_INET_NTOP@
+REPLACE_INET_PTON = @REPLACE_INET_PTON@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
+REPLACE_IOCTL = @REPLACE_IOCTL@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ITOLD = @REPLACE_ITOLD@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALECONV = @REPLACE_LOCALECONV@
+REPLACE_LOCALTIME = @REPLACE_LOCALTIME@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MALLOC = @REPLACE_MALLOC@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MBTOWC = @REPLACE_MBTOWC@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKNODAT = @REPLACE_MKNODAT@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@
+REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PSELECT = @REPLACE_PSELECT@
+REPLACE_PTHREAD_ATTR_DESTROY = @REPLACE_PTHREAD_ATTR_DESTROY@
+REPLACE_PTHREAD_ATTR_GETDETACHSTATE = @REPLACE_PTHREAD_ATTR_GETDETACHSTATE@
+REPLACE_PTHREAD_ATTR_INIT = @REPLACE_PTHREAD_ATTR_INIT@
+REPLACE_PTHREAD_ATTR_SETDETACHSTATE = @REPLACE_PTHREAD_ATTR_SETDETACHSTATE@
+REPLACE_PTHREAD_CONDATTR_DESTROY = @REPLACE_PTHREAD_CONDATTR_DESTROY@
+REPLACE_PTHREAD_CONDATTR_INIT = @REPLACE_PTHREAD_CONDATTR_INIT@
+REPLACE_PTHREAD_COND_BROADCAST = @REPLACE_PTHREAD_COND_BROADCAST@
+REPLACE_PTHREAD_COND_DESTROY = @REPLACE_PTHREAD_COND_DESTROY@
+REPLACE_PTHREAD_COND_INIT = @REPLACE_PTHREAD_COND_INIT@
+REPLACE_PTHREAD_COND_SIGNAL = @REPLACE_PTHREAD_COND_SIGNAL@
+REPLACE_PTHREAD_COND_TIMEDWAIT = @REPLACE_PTHREAD_COND_TIMEDWAIT@
+REPLACE_PTHREAD_COND_WAIT = @REPLACE_PTHREAD_COND_WAIT@
+REPLACE_PTHREAD_CREATE = @REPLACE_PTHREAD_CREATE@
+REPLACE_PTHREAD_DETACH = @REPLACE_PTHREAD_DETACH@
+REPLACE_PTHREAD_EQUAL = @REPLACE_PTHREAD_EQUAL@
+REPLACE_PTHREAD_EXIT = @REPLACE_PTHREAD_EXIT@
+REPLACE_PTHREAD_GETSPECIFIC = @REPLACE_PTHREAD_GETSPECIFIC@
+REPLACE_PTHREAD_JOIN = @REPLACE_PTHREAD_JOIN@
+REPLACE_PTHREAD_KEY_CREATE = @REPLACE_PTHREAD_KEY_CREATE@
+REPLACE_PTHREAD_KEY_DELETE = @REPLACE_PTHREAD_KEY_DELETE@
+REPLACE_PTHREAD_MUTEXATTR_DESTROY = @REPLACE_PTHREAD_MUTEXATTR_DESTROY@
+REPLACE_PTHREAD_MUTEXATTR_GETROBUST = @REPLACE_PTHREAD_MUTEXATTR_GETROBUST@
+REPLACE_PTHREAD_MUTEXATTR_GETTYPE = @REPLACE_PTHREAD_MUTEXATTR_GETTYPE@
+REPLACE_PTHREAD_MUTEXATTR_INIT = @REPLACE_PTHREAD_MUTEXATTR_INIT@
+REPLACE_PTHREAD_MUTEXATTR_SETROBUST = @REPLACE_PTHREAD_MUTEXATTR_SETROBUST@
+REPLACE_PTHREAD_MUTEXATTR_SETTYPE = @REPLACE_PTHREAD_MUTEXATTR_SETTYPE@
+REPLACE_PTHREAD_MUTEX_DESTROY = @REPLACE_PTHREAD_MUTEX_DESTROY@
+REPLACE_PTHREAD_MUTEX_INIT = @REPLACE_PTHREAD_MUTEX_INIT@
+REPLACE_PTHREAD_MUTEX_LOCK = @REPLACE_PTHREAD_MUTEX_LOCK@
+REPLACE_PTHREAD_MUTEX_TIMEDLOCK = @REPLACE_PTHREAD_MUTEX_TIMEDLOCK@
+REPLACE_PTHREAD_MUTEX_TRYLOCK = @REPLACE_PTHREAD_MUTEX_TRYLOCK@
+REPLACE_PTHREAD_MUTEX_UNLOCK = @REPLACE_PTHREAD_MUTEX_UNLOCK@
+REPLACE_PTHREAD_ONCE = @REPLACE_PTHREAD_ONCE@
+REPLACE_PTHREAD_RWLOCKATTR_DESTROY = @REPLACE_PTHREAD_RWLOCKATTR_DESTROY@
+REPLACE_PTHREAD_RWLOCKATTR_INIT = @REPLACE_PTHREAD_RWLOCKATTR_INIT@
+REPLACE_PTHREAD_RWLOCK_DESTROY = @REPLACE_PTHREAD_RWLOCK_DESTROY@
+REPLACE_PTHREAD_RWLOCK_INIT = @REPLACE_PTHREAD_RWLOCK_INIT@
+REPLACE_PTHREAD_RWLOCK_RDLOCK = @REPLACE_PTHREAD_RWLOCK_RDLOCK@
+REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK = @REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK@
+REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK = @REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK@
+REPLACE_PTHREAD_RWLOCK_TRYRDLOCK = @REPLACE_PTHREAD_RWLOCK_TRYRDLOCK@
+REPLACE_PTHREAD_RWLOCK_TRYWRLOCK = @REPLACE_PTHREAD_RWLOCK_TRYWRLOCK@
+REPLACE_PTHREAD_RWLOCK_UNLOCK = @REPLACE_PTHREAD_RWLOCK_UNLOCK@
+REPLACE_PTHREAD_RWLOCK_WRLOCK = @REPLACE_PTHREAD_RWLOCK_WRLOCK@
+REPLACE_PTHREAD_SELF = @REPLACE_PTHREAD_SELF@
+REPLACE_PTHREAD_SETSPECIFIC = @REPLACE_PTHREAD_SETSPECIFIC@
+REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@
+REPLACE_PTHREAD_SPIN_DESTROY = @REPLACE_PTHREAD_SPIN_DESTROY@
+REPLACE_PTHREAD_SPIN_INIT = @REPLACE_PTHREAD_SPIN_INIT@
+REPLACE_PTHREAD_SPIN_LOCK = @REPLACE_PTHREAD_SPIN_LOCK@
+REPLACE_PTHREAD_SPIN_TRYLOCK = @REPLACE_PTHREAD_SPIN_TRYLOCK@
+REPLACE_PTHREAD_SPIN_UNLOCK = @REPLACE_PTHREAD_SPIN_UNLOCK@
+REPLACE_PTSNAME = @REPLACE_PTSNAME@
+REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_PWRITE = @REPLACE_PWRITE@
+REPLACE_QSORT_R = @REPLACE_QSORT_R@
+REPLACE_RAISE = @REPLACE_RAISE@
+REPLACE_RANDOM = @REPLACE_RANDOM@
+REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOC = @REPLACE_REALLOC@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_SCHED_YIELD = @REPLACE_SCHED_YIELD@
+REPLACE_SELECT = @REPLACE_SELECT@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STPNCPY = @REPLACE_STPNCPY@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@
+REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
+REPLACE_STRFTIME = @REPLACE_STRFTIME@
+REPLACE_STRNCAT = @REPLACE_STRNCAT@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRNLEN = @REPLACE_STRNLEN@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
+REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
+REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
+REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_TMPFILE = @REPLACE_TMPFILE@
+REPLACE_TRUNCATE = @REPLACE_TRUNCATE@
+REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_TZSET = @REPLACE_TZSET@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSFTIME = @REPLACE_WCSFTIME@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSTOK = @REPLACE_WCSTOK@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+SED = @SED@
+SERVENT_LIB = @SERVENT_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+STDALIGN_H = @STDALIGN_H@
+STDBOOL_H = @STDBOOL_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SYS_IOCTL_H_HAVE_WINSOCK2_H = @SYS_IOCTL_H_HAVE_WINSOCK2_H@
+SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@
+TROUSERS_LIB = @TROUSERS_LIB@
+TSS2_CFLAGS = @TSS2_CFLAGS@
+TSS2_LIBS = @TSS2_LIBS@
+TSS_CFLAGS = @TSS_CFLAGS@
+TSS_LIBS = @TSS_LIBS@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNBOUND_CFLAGS = @UNBOUND_CFLAGS@
+UNBOUND_LIBS = @UNBOUND_LIBS@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@
+UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+USE_NLS = @USE_NLS@
+VALGRIND = @VALGRIND@
+VALGRINDFLAGS = @VALGRINDFLAGS@
+VALGRIND_PROGRAM = @VALGRIND_PROGRAM@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WERROR_CFLAGS = @WERROR_CFLAGS@
+WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@
+WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@
+WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@
+WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+WSTACK_CFLAGS = @WSTACK_CFLAGS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+YIELD_LIB = @YIELD_LIB@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_time_t = @ac_cv_sizeof_time_t@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+ggl_LIBOBJS = @ggl_LIBOBJS@
+ggl_LTLIBOBJS = @ggl_LTLIBOBJS@
+ggltests_LIBOBJS = @ggltests_LIBOBJS@
+ggltests_LTLIBOBJS = @ggltests_LTLIBOBJS@
+ggltests_WITNESS = @ggltests_WITNESS@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+gltests_WITNESS = @gltests_WITNESS@
+gnutls_so = @gnutls_so@
+guile_snarf = @guile_snarf@
+guileextensiondir = @guileextensiondir@
+guilesiteccachedir = @guilesiteccachedir@
+guilesitedir = @guilesitedir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+ifGNUmake = @ifGNUmake@
+ifnGNUmake = @ifnGNUmake@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+maybe_guileextensiondir = @maybe_guileextensiondir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+unistring_LIBOBJS = @unistring_LIBOBJS@
+unistring_LTLIBOBJS = @unistring_LTLIBOBJS@
+unistringtests_LIBOBJS = @unistringtests_LIBOBJS@
+unistringtests_LTLIBOBJS = @unistringtests_LTLIBOBJS@
+unistringtests_WITNESS = @unistringtests_WITNESS@
+AM_CFLAGS = $(WERROR_CFLAGS) $(WSTACK_CFLAGS) $(WARN_CFLAGS) $(NETTLE_CFLAGS) \
+ $(LIBTASN1_CFLAGS) $(LIBIDN2_CFLAGS) $(P11_KIT_CFLAGS) $(LIBZSTD_CFLAGS) \
+ $(CODE_COVERAGE_CFLAGS)
+
+COMMON_LINK_FLAGS = $(CODE_COVERAGE_LDFLAGS)
+V_GPERF = $(V_GPERF_@AM_V@)
+V_GPERF_ = $(V_GPERF_@AM_DEFAULT_V@)
+V_GPERF_0 = @echo " GPERF " $@;
+AM_CPPFLAGS = -I$(srcdir)/../../gl -I$(builddir)/../../gl \
+ -I$(srcdir)/../includes -I$(builddir)/../includes \
+ -I$(builddir)/../../gl -I$(srcdir)/.. $(am__append_1)
+noinst_LTLIBRARIES = libgnutls_ext.la
+libgnutls_ext_la_SOURCES = max_record.c server_name.c signature.c \
+ safe_renegotiation.c max_record.h server_name.h srp.h \
+ session_ticket.h signature.h safe_renegotiation.h \
+ session_ticket.c srp.c heartbeat.c heartbeat.h \
+ status_request.h status_request.c dumbfw.c dumbfw.h \
+ ext_master_secret.c ext_master_secret.h etm.h etm.c \
+ supported_versions.c supported_versions.h post_handshake.c \
+ post_handshake.h key_share.c key_share.h cookie.c cookie.h \
+ psk_ke_modes.c psk_ke_modes.h pre_shared_key.c \
+ pre_shared_key.h supported_groups.c supported_groups.h \
+ ec_point_formats.c ec_point_formats.h early_data.c \
+ early_data.h record_size_limit.c record_size_limit.h \
+ client_cert_type.c client_cert_type.h server_cert_type.c \
+ server_cert_type.h cert_types.h compress_certificate.c \
+ compress_certificate.h $(am__append_2) $(am__append_3)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/lib/common.mk $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/ext/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign lib/ext/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/lib/common.mk $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgnutls_ext.la: $(libgnutls_ext_la_OBJECTS) $(libgnutls_ext_la_DEPENDENCIES) $(EXTRA_libgnutls_ext_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libgnutls_ext_la_OBJECTS) $(libgnutls_ext_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client_cert_type.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress_certificate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cookie.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dumbfw.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/early_data.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ec_point_formats.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext_master_secret.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heartbeat.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key_share.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/max_record.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/post_handshake.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_shared_key.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_ke_modes.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/record_size_limit.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe_renegotiation.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_cert_type.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_name.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_ticket.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signature.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srtp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status_request.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/supported_groups.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/supported_versions.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/alpn.Plo
+ -rm -f ./$(DEPDIR)/client_cert_type.Plo
+ -rm -f ./$(DEPDIR)/compress_certificate.Plo
+ -rm -f ./$(DEPDIR)/cookie.Plo
+ -rm -f ./$(DEPDIR)/dumbfw.Plo
+ -rm -f ./$(DEPDIR)/early_data.Plo
+ -rm -f ./$(DEPDIR)/ec_point_formats.Plo
+ -rm -f ./$(DEPDIR)/etm.Plo
+ -rm -f ./$(DEPDIR)/ext_master_secret.Plo
+ -rm -f ./$(DEPDIR)/heartbeat.Plo
+ -rm -f ./$(DEPDIR)/key_share.Plo
+ -rm -f ./$(DEPDIR)/max_record.Plo
+ -rm -f ./$(DEPDIR)/post_handshake.Plo
+ -rm -f ./$(DEPDIR)/pre_shared_key.Plo
+ -rm -f ./$(DEPDIR)/psk_ke_modes.Plo
+ -rm -f ./$(DEPDIR)/record_size_limit.Plo
+ -rm -f ./$(DEPDIR)/safe_renegotiation.Plo
+ -rm -f ./$(DEPDIR)/server_cert_type.Plo
+ -rm -f ./$(DEPDIR)/server_name.Plo
+ -rm -f ./$(DEPDIR)/session_ticket.Plo
+ -rm -f ./$(DEPDIR)/signature.Plo
+ -rm -f ./$(DEPDIR)/srp.Plo
+ -rm -f ./$(DEPDIR)/srtp.Plo
+ -rm -f ./$(DEPDIR)/status_request.Plo
+ -rm -f ./$(DEPDIR)/supported_groups.Plo
+ -rm -f ./$(DEPDIR)/supported_versions.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/alpn.Plo
+ -rm -f ./$(DEPDIR)/client_cert_type.Plo
+ -rm -f ./$(DEPDIR)/compress_certificate.Plo
+ -rm -f ./$(DEPDIR)/cookie.Plo
+ -rm -f ./$(DEPDIR)/dumbfw.Plo
+ -rm -f ./$(DEPDIR)/early_data.Plo
+ -rm -f ./$(DEPDIR)/ec_point_formats.Plo
+ -rm -f ./$(DEPDIR)/etm.Plo
+ -rm -f ./$(DEPDIR)/ext_master_secret.Plo
+ -rm -f ./$(DEPDIR)/heartbeat.Plo
+ -rm -f ./$(DEPDIR)/key_share.Plo
+ -rm -f ./$(DEPDIR)/max_record.Plo
+ -rm -f ./$(DEPDIR)/post_handshake.Plo
+ -rm -f ./$(DEPDIR)/pre_shared_key.Plo
+ -rm -f ./$(DEPDIR)/psk_ke_modes.Plo
+ -rm -f ./$(DEPDIR)/record_size_limit.Plo
+ -rm -f ./$(DEPDIR)/safe_renegotiation.Plo
+ -rm -f ./$(DEPDIR)/server_cert_type.Plo
+ -rm -f ./$(DEPDIR)/server_name.Plo
+ -rm -f ./$(DEPDIR)/session_ticket.Plo
+ -rm -f ./$(DEPDIR)/signature.Plo
+ -rm -f ./$(DEPDIR)/srp.Plo
+ -rm -f ./$(DEPDIR)/srtp.Plo
+ -rm -f ./$(DEPDIR)/status_request.Plo
+ -rm -f ./$(DEPDIR)/supported_groups.Plo
+ -rm -f ./$(DEPDIR)/supported_versions.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/ext/alpn.c b/lib/ext/alpn.c
new file mode 100644
index 0000000..7cc7997
--- /dev/null
+++ b/lib/ext/alpn.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "auth.h"
+#include "errors.h"
+#include "num.h"
+#include <ext/alpn.h>
+
+static int _gnutls_alpn_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_alpn_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+static void _gnutls_alpn_deinit_data(gnutls_ext_priv_data_t priv);
+
+
+const hello_ext_entry_st ext_mod_alpn = {
+ .name = "ALPN",
+ .tls_id = 16,
+ .gid = GNUTLS_EXTENSION_ALPN,
+ /* this extension must be parsed even on resumption */
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
+ GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_alpn_recv_params,
+ .send_func = _gnutls_alpn_send_params,
+ .deinit_func = _gnutls_alpn_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+static int
+_gnutls_alpn_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ unsigned int i;
+ int ret;
+ const uint8_t *p = data;
+ unsigned len1, len;
+ alpn_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ int selected_protocol_index;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_ALPN,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ len = _gnutls_read_uint16(p);
+ p += 2;
+
+ if (len == 0 || len > (size_t)data_size)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ selected_protocol_index = MAX_ALPN_PROTOCOLS+1;
+
+ while (data_size > 0) {
+ DECR_LENGTH_RET(data_size, 1, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ len1 = *p;
+ p += 1;
+ DECR_LENGTH_RET(data_size, len1, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (len1 == 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ for (i = 0; i < priv->size; i++) {
+ if (priv->protocol_size[i] == len1
+ && memcmp(p, priv->protocols[i],
+ len1) == 0) {
+
+ if (priv->flags & GNUTLS_ALPN_SERVER_PRECEDENCE) {
+ if (selected_protocol_index > (int)i) {
+ selected_protocol_index = i;
+ priv->selected_protocol =
+ priv->protocols[i];
+ priv->selected_protocol_size =
+ priv->protocol_size[i];
+ break;
+ }
+ } else {
+ priv->selected_protocol =
+ priv->protocols[i];
+ priv->selected_protocol_size =
+ priv->protocol_size[i];
+ return 0;
+ }
+ }
+ }
+ p += len1;
+ }
+ } else {
+ DECR_LENGTH_RET(data_size, 1, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ len1 = *p;
+ p += 1;
+ DECR_LENGTH_RET(data_size, len1, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ for (i = 0; i < priv->size; i++) {
+ if (priv->protocol_size[i] == len1
+ && memcmp(p, priv->protocols[i], len1) == 0) {
+ priv->selected_protocol =
+ priv->protocols[i];
+ priv->selected_protocol_size =
+ priv->protocol_size[i];
+ break;
+ }
+ }
+ /*p += len1;*/
+ }
+
+ if (priv->selected_protocol == NULL
+ && (priv->flags & GNUTLS_ALPN_MAND))
+ return gnutls_assert_val(GNUTLS_E_NO_APPLICATION_PROTOCOL);
+
+ return 0;
+}
+
+static int
+_gnutls_alpn_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ unsigned i;
+ int total_size = 0, ret;
+ alpn_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_ALPN,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ if (priv->size == 0)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (priv->selected_protocol_size == 0)
+ return 0;
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ priv->
+ selected_protocol_size +
+ 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ total_size += 2;
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 8,
+ priv->
+ selected_protocol,
+ priv->
+ selected_protocol_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ total_size += 1 + priv->selected_protocol_size;
+ } else {
+ int t = 0;
+ for (i = 0; i < priv->size; i++)
+ t += priv->protocol_size[i] + 1;
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, t);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ total_size += 2;
+
+ for (i = 0; i < priv->size; i++) {
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 8,
+ priv->
+ protocols[i],
+ priv->
+ protocol_size
+ [i]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ total_size += 1 + priv->protocol_size[i];
+ }
+ }
+
+ return total_size;
+}
+
+/**
+ * gnutls_alpn_get_selected_protocol:
+ * @session: is a #gnutls_session_t type.
+ * @protocol: will hold the protocol name
+ *
+ * This function allows you to get the negotiated protocol name. The
+ * returned protocol should be treated as opaque, constant value and
+ * only valid during the session life.
+ *
+ * The selected protocol is the first supported by the list sent
+ * by the client.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.2.0
+ **/
+int
+gnutls_alpn_get_selected_protocol(gnutls_session_t session,
+ gnutls_datum_t * protocol)
+{
+ alpn_ext_st *priv;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_ALPN,
+ &epriv);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ priv = epriv;
+
+ if (priv->selected_protocol_size == 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ protocol->data = priv->selected_protocol;
+ protocol->size = priv->selected_protocol_size;
+
+ return 0;
+}
+
+/**
+ * gnutls_alpn_set_protocols:
+ * @session: is a #gnutls_session_t type.
+ * @protocols: is the protocol names to add.
+ * @protocols_size: the number of protocols to add.
+ * @flags: zero or a sequence of %gnutls_alpn_flags_t
+ *
+ * This function is to be used by both clients and servers, to declare
+ * the supported ALPN protocols, which are used during negotiation with peer.
+ *
+ * See %gnutls_alpn_flags_t description for the documentation of available
+ * flags.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.2.0
+ **/
+int
+gnutls_alpn_set_protocols(gnutls_session_t session,
+ const gnutls_datum_t * protocols,
+ unsigned protocols_size, unsigned int flags)
+{
+ int ret;
+ alpn_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ unsigned i;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_ALPN,
+ &epriv);
+ if (ret < 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_ALPN, epriv);
+ } else
+ priv = epriv;
+
+ if (protocols_size > MAX_ALPN_PROTOCOLS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ for (i = 0; i < protocols_size; i++) {
+ if (protocols[i].size >= MAX_ALPN_PROTOCOL_NAME)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ memcpy(priv->protocols[i], protocols[i].data,
+ protocols[i].size);
+ priv->protocol_size[i] = protocols[i].size;
+ priv->size++;
+ }
+ priv->flags = flags;
+
+ return 0;
+}
+
+
+static void _gnutls_alpn_deinit_data(gnutls_ext_priv_data_t priv)
+{
+ gnutls_free(priv);
+}
diff --git a/lib/ext/alpn.h b/lib/ext/alpn.h
new file mode 100644
index 0000000..0b32a32
--- /dev/null
+++ b/lib/ext/alpn.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_ALPN_H
+#define GNUTLS_LIB_EXT_ALPN_H
+
+#include <hello_ext.h>
+
+#define MAX_ALPN_PROTOCOLS 8
+#define MAX_ALPN_PROTOCOL_NAME 32
+
+typedef struct {
+ uint8_t protocols[MAX_ALPN_PROTOCOLS][MAX_ALPN_PROTOCOL_NAME];
+ unsigned protocol_size[MAX_ALPN_PROTOCOLS];
+ unsigned size;
+ uint8_t *selected_protocol;
+ unsigned selected_protocol_size;
+ unsigned flags;
+} alpn_ext_st;
+
+extern const hello_ext_entry_st ext_mod_alpn;
+
+#endif /* GNUTLS_LIB_EXT_ALPN_H */
diff --git a/lib/ext/cert_types.h b/lib/ext/cert_types.h
new file mode 100644
index 0000000..98dfdef
--- /dev/null
+++ b/lib/ext/cert_types.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 ARPA2 project
+ *
+ * Author: Tom Vrancken (dev@tomvrancken.nl)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ * This file provides common functionality for certificate type
+ * handling during TLS hello extensions.
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_CERT_TYPES_H
+#define GNUTLS_LIB_EXT_CERT_TYPES_H
+
+/* Maps IANA TLS Certificate Types identifiers to internal
+ * certificate type representation.
+ */
+static inline gnutls_certificate_type_t IANA2cert_type(int num)
+{
+ switch (num) {
+ case 0:
+ return GNUTLS_CRT_X509;
+ case 2:
+ return GNUTLS_CRT_RAWPK;
+ default:
+ return GNUTLS_CRT_UNKNOWN;
+ }
+}
+
+/* Maps internal certificate type representation to
+ * IANA TLS Certificate Types identifiers.
+ */
+static inline int cert_type2IANA(gnutls_certificate_type_t cert_type)
+{
+ switch (cert_type) {
+ case GNUTLS_CRT_X509:
+ return 0;
+ case GNUTLS_CRT_RAWPK:
+ return 2;
+ default:
+ return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+}
+
+/* Checks whether the given cert type is enabled in the application
+ */
+static inline bool is_cert_type_enabled(gnutls_session_t session, gnutls_certificate_type_t cert_type)
+{
+ switch(cert_type) {
+ case GNUTLS_CRT_X509:
+ // Default cert type, always enabled
+ return true;
+ case GNUTLS_CRT_RAWPK:
+ return session->internals.flags & GNUTLS_ENABLE_RAWPK;
+ default:
+ // When not explicitly supported here disable it
+ return false;
+ }
+}
+
+/* Checks whether alternative cert types (i.e. other than X.509)
+ * are enabled in the application
+ */
+static inline bool are_alternative_cert_types_allowed(gnutls_session_t session)
+{
+ // OR-ed list of defined cert type init flags
+ #define CERT_TYPES_FLAGS GNUTLS_ENABLE_RAWPK
+
+ return session->internals.flags & CERT_TYPES_FLAGS;
+
+ #undef CERT_TYPES_FLAGS
+}
+
+#endif /* GNUTLS_LIB_EXT_CERT_TYPES_H */
diff --git a/lib/ext/client_cert_type.c b/lib/ext/client_cert_type.c
new file mode 100644
index 0000000..261b56c
--- /dev/null
+++ b/lib/ext/client_cert_type.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2016 - 2018 ARPA2 project
+ *
+ * Author: Tom Vrancken (dev@tomvrancken.nl)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ * This file is part of the client_certificate_type extension as
+ * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
+ *
+ * The client_certificate_type extension in the client hello indicates
+ * the certificate types the client is able to provide to the server,
+ * when requested using a certificate_request message.
+ */
+
+#include "gnutls_int.h"
+#include <gnutls/gnutls.h>
+#include "ext/cert_types.h"
+#include "ext/client_cert_type.h"
+#include "hello_ext.h"
+#include "hello_ext_lib.h"
+#include "errors.h"
+#include "state.h"
+#include "datum.h"
+
+
+static int _gnutls_client_cert_type_recv_params(gnutls_session_t session,
+ const uint8_t* data,
+ size_t data_size);
+static int _gnutls_client_cert_type_send_params(gnutls_session_t session,
+ gnutls_buffer_st* data);
+
+
+const hello_ext_entry_st ext_mod_client_cert_type = {
+ .name = "Client Certificate Type",
+ .tls_id = 19,
+ .gid = GNUTLS_EXTENSION_CLIENT_CERT_TYPE,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS |
+ GNUTLS_EXT_FLAG_DTLS |
+ GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
+ GNUTLS_EXT_FLAG_EE,
+ .recv_func = _gnutls_client_cert_type_recv_params,
+ .send_func = _gnutls_client_cert_type_send_params,
+ .pack_func = _gnutls_hello_ext_default_pack,
+ .unpack_func = _gnutls_hello_ext_default_unpack,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 1
+};
+
+
+static int _gnutls_client_cert_type_recv_params(gnutls_session_t session,
+ const uint8_t* data,
+ size_t data_size)
+{
+ int ret;
+ gnutls_certificate_type_t cert_type;
+ size_t i;
+ bool found = false;
+ const uint8_t* pdata = data;
+
+ /* Only activate this extension if we have cert credentials set
+ * and alternative cert types are allowed */
+ if (!are_alternative_cert_types_allowed(session) ||
+ (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
+ return 0;
+
+ if (!IS_SERVER(session)) { // client mode
+ gnutls_datum_t sent_cert_types; // Holds the previously sent cert types
+
+ /* Compare packet length with expected packet length. For the
+ * client this is a single byte. */
+ if (data_size != 1) {
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+
+ /* The server picked one of the offered cert types if he supports
+ * at least one of them and decided to do a client certificate
+ * request. If both parties play by the rules then we may only
+ * receive a cert type that we offered, i.e. one that we support.
+ * Because the world isn't as beautiful as it may seem, we're going
+ * to check it nevertheless. */
+ cert_type = IANA2cert_type(pdata[0]);
+
+ _gnutls_handshake_log("EXT[%p]: Received a %s client certificate type confirmation from the server.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ // Check validity of cert type
+ if (cert_type == GNUTLS_CRT_UNKNOWN) {
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
+ }
+
+ /* Get the cert types that we sent to the server (they were stored
+ * in IANA representation.
+ */
+ ret = _gnutls_hello_ext_get_datum(session,
+ GNUTLS_EXTENSION_CLIENT_CERT_TYPE,
+ &sent_cert_types);
+ if (ret < 0) {
+ /* This should not happen and indicate a memory corruption!
+ * Assertion are always on in production code so execution
+ * will halt here. */
+ assert(false);
+ }
+
+ // Check whether what we got back is actually offered by us
+ for (i = 0; i < sent_cert_types.size; i++) {
+ if (IANA2cert_type(sent_cert_types.data[i]) == cert_type)
+ found = true;
+ }
+
+ if (found) {
+ // Everything OK, now set the client certificate type
+ _gnutls_session_client_cert_type_set(session, cert_type);
+ ret = GNUTLS_E_SUCCESS;
+ } else {
+ // No valid cert type found
+ ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+
+ return ret;
+
+ } else { // server mode
+ gnutls_datum_t cert_types; // Holds the received cert types
+
+ // Compare packet length with expected packet length.
+ DECR_LEN(data_size, 1);
+ if (data[0] != data_size) {
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+ pdata += 1;
+
+ // Assign the contents of our data buffer to a gnutls_datum_t
+ cert_types.data = (uint8_t*)pdata; // Need casting to get rid of 'discards const qualifier' warning
+ cert_types.size = data_size;
+
+ // Store the client certificate types in our session
+ _gnutls_hello_ext_set_datum(session,
+ GNUTLS_EXTENSION_CLIENT_CERT_TYPE,
+ &cert_types);
+
+ /* We receive a list of supported certificate types that the client
+ * is able to provide when requested via a client certificate
+ * request. This list is sorted by order of preference. We now check
+ * in this order of preference whether we support any of these
+ * certificate types.
+ */
+ for (i = 0; i < cert_types.size; i++) {
+ // Convert to internal representation
+ cert_type = IANA2cert_type(cert_types.data[i]);
+
+ // If we have an invalid cert id then continue to the next
+ if (cert_type == GNUTLS_CRT_UNKNOWN)
+ continue;
+
+ _gnutls_handshake_log("EXT[%p]: Checking compatibility of a %s client certificate type that was received from the client.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ // Check for support of this cert type
+ if (_gnutls_session_is_cert_type_supported(session, cert_type, false, GNUTLS_CTYPE_CLIENT) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ // We found a matching ctype, we pick this one
+ if (found) {
+ _gnutls_session_client_cert_type_set(session, cert_type);
+ ret = GNUTLS_E_SUCCESS;
+ } else {
+ /* If no supported certificate type can be found we terminate
+ * with a fatal alert of type "unsupported_certificate"
+ * (according to specification rfc7250).
+ */
+ _gnutls_handshake_log
+ ("EXT[%p]: No supported client certificate type was found. "
+ "Aborting connection.\n", session);
+ ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+
+ return ret;
+ }
+}
+
+static int _gnutls_client_cert_type_send_params(gnutls_session_t session,
+ gnutls_buffer_st* data)
+{
+ int ret;
+ uint8_t cert_type_IANA; // Holds an IANA cert type ID
+ gnutls_certificate_type_t cert_type;
+
+ /* Only activate this extension if we have cert credentials set
+ * and alternative cert types are allowed */
+ if (!are_alternative_cert_types_allowed(session) ||
+ (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
+ return 0;
+
+ if (!IS_SERVER(session)) { // Client mode
+ uint8_t cert_types[GNUTLS_CRT_MAX]; // The list with supported (IANA) cert types. Inv: 0 <= cert type Id < 256
+ size_t i, num_cert_types = 0;
+ priority_st* cert_priorities;
+ gnutls_datum_t tmp_cert_types; // For type conversion
+
+ // For brevity
+ cert_priorities =
+ &session->internals.priorities->client_ctype;
+
+ /* Retrieve client certificate type priorities if any. If no
+ * priorities are set then the default client certificate type
+ * initialization values apply. This default is currently set to
+ * x.509 in which case we don't enable this extension.
+ */
+ if (cert_priorities->num_priorities > 0) { // Priorities are explicitly set
+ /* If the certificate priority is explicitly set to only
+ * X.509 (default) then, according to spec we don't send
+ * this extension. We check this here to avoid further work in
+ * this routine. We also check it below after pruning supported
+ * types.
+ */
+ if (cert_priorities->num_priorities == 1 &&
+ cert_priorities->priorities[0] == DEFAULT_CERT_TYPE) {
+ _gnutls_handshake_log
+ ("EXT[%p]: Client certificate type was set to default cert type (%s). "
+ "We therefore do not send this extension.\n",
+ session,
+ gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
+
+ // Explicitly set but default ctype, so don't send anything
+ return 0;
+ }
+
+ /* We are only allowed to send certificate types that we support,
+ * i.e. have credentials for. Therefore we check this here and
+ * prune our original list.
+ */
+ for (i = 0; i < cert_priorities->num_priorities; i++) {
+ cert_type = cert_priorities->priorities[i];
+
+ if (_gnutls_session_is_cert_type_supported(session, cert_type,
+ true, GNUTLS_CTYPE_CLIENT) == 0) {
+ /* Check whether we are allowed to store another cert type
+ * in our buffer. In other words, prevent a possible buffer
+ * overflow. This situation can occur when a user sets
+ * duplicate cert types in the priority strings. */
+ if (num_cert_types >= GNUTLS_CRT_MAX)
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+ // Convert to IANA representation
+ ret = cert_type2IANA(cert_type);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ cert_type_IANA = ret; // For readability
+
+ // Add this cert type to our list with supported types
+ cert_types[num_cert_types] = cert_type_IANA;
+ num_cert_types++;
+
+ _gnutls_handshake_log
+ ("EXT[%p]: Client certificate type %s (%d) was queued.\n",
+ session,
+ gnutls_certificate_type_get_name(cert_type),
+ cert_type_IANA);
+ }
+ }
+
+ /* Check whether there are any supported certificate types left
+ * after the previous pruning step. If not, we do not send this
+ * extension. Also, if the only supported type is the default type
+ * we do not send this extension (according to RFC7250).
+ */
+ if (num_cert_types == 0) {
+ _gnutls_handshake_log
+ ("EXT[%p]: Client certificate types were set but none of them is supported. "
+ "You might want to check your credentials or your priorities. "
+ "We do not send this extension.\n",
+ session);
+
+ return 0;
+ } else if (num_cert_types == 1 &&
+ IANA2cert_type(cert_types[0]) == DEFAULT_CERT_TYPE) {
+ _gnutls_handshake_log
+ ("EXT[%p]: The only supported client certificate type is (%s) which is the default. "
+ "We therefore do not send this extension.\n",
+ session,
+ gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
+
+ return 0;
+ }
+
+ /* We have data to send and store a copy internally. We convert
+ * our list with supported cert types to a datum_t in order to
+ * be able to make the ..._set_datum call.
+ */
+ tmp_cert_types.data = cert_types;
+ tmp_cert_types.size = num_cert_types;
+
+ _gnutls_hello_ext_set_datum(session,
+ GNUTLS_EXTENSION_CLIENT_CERT_TYPE,
+ &tmp_cert_types);
+
+ /* Serialize the certificate types into a sequence of octets
+ * uint8: length of sequence of cert types (1 octet)
+ * uint8: cert types (0 <= #octets <= 255)
+ */
+ ret = _gnutls_buffer_append_data_prefix(data, 8,
+ cert_types,
+ num_cert_types);
+
+ // Check for errors
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ } else {
+ // Number of bytes we are sending
+ return num_cert_types + 1;
+ }
+ }
+ } else { // Server mode
+ const version_entry_st* vers = get_version(session);
+ /* TLS 1.2:
+ * Check whether we are going to send a certificate request,
+ * otherwise omit the response. This is conform spec.
+ * (RFC7250, 4.2 case 3.).
+ *
+ * TLS 1.3:
+ * TLS 1.3 supports post-handshake authentication for the client.
+ * It means that a server can ask for a client certificate anytime
+ * after the handshake. In order for this to work we must always
+ * complete the certificate type negotiation and therefore respond
+ * with a cert type message.
+ */
+ if (session->internals.send_cert_req != 0 ||
+ vers->tls13_sem) {
+ /* Retrieve negotiated client certificate type and send it to
+ * the client.
+ * The scenario where we want to send a certificate request but
+ * do not have a matching certificate does not occur because we
+ * already terminate the connection at reception of this extension
+ * when we cannot find a matching client certificate. This is conform
+ * spec (RFC7250, 4.2 case 2.).
+ */
+ cert_type = get_certificate_type(session, GNUTLS_CTYPE_CLIENT);
+ ret = cert_type2IANA(cert_type);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ cert_type_IANA = ret; // For readability
+
+ _gnutls_handshake_log("EXT[%p]: Confirming to use a %s client certificate type.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ ret = gnutls_buffer_append_data(data, &cert_type_IANA, 1);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 1; // sent one byte
+ }
+ }
+
+ // In all other cases don't enable this extension
+ return 0;
+}
+
+
+/** Extension interface **/
+
+/* The interface is defined in state.c:
+ * Public:
+ * - gnutls_certificate_type_get2
+ *
+ * Private:
+ * - _gnutls_session_client_cert_type_set
+ */
diff --git a/lib/ext/client_cert_type.h b/lib/ext/client_cert_type.h
new file mode 100644
index 0000000..7e89ca8
--- /dev/null
+++ b/lib/ext/client_cert_type.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 - 2018 ARPA2 project
+ *
+ * Author: Tom Vrancken (dev@tomvrancken.nl)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ * This file is part of the client_certificate_type extension as
+ * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
+ *
+ * The client_certificate_type extension in the client hello indicates
+ * the certificate types the client is able to provide to the server,
+ * when requested using a certificate_request message.
+ */
+
+#ifndef GNUTLS_LIB_EXT_CLIENT_CERT_TYPE_H
+#define GNUTLS_LIB_EXT_CLIENT_CERT_TYPE_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_client_cert_type;
+
+#endif /* GNUTLS_LIB_EXT_CLIENT_CERT_TYPE_H */
diff --git a/lib/ext/compress_certificate.c b/lib/ext/compress_certificate.c
new file mode 100644
index 0000000..8f8d75c
--- /dev/null
+++ b/lib/ext/compress_certificate.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Zoltan Fridrich
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "errors.h"
+#include "gnutls_int.h"
+#include "hello_ext_lib.h"
+#include "num.h"
+#include <ext/compress_certificate.h>
+
+/* Check whether certificate compression method is valid, ie. supported by gnutls */
+static inline int
+is_valid_method(gnutls_compression_method_t method)
+{
+ switch (method) {
+#ifdef HAVE_LIBZ
+ case GNUTLS_COMP_ZLIB:
+ return 1;
+#endif
+#ifdef HAVE_LIBBROTLI
+ case GNUTLS_COMP_BROTLI:
+ return 1;
+#endif
+#ifdef HAVE_LIBZSTD
+ case GNUTLS_COMP_ZSTD:
+ return 1;
+#endif
+ default:
+ return 0;
+ }
+}
+
+/* Converts compression algorithm number established in RFC8879 to internal compression method type */
+gnutls_compression_method_t
+_gnutls_compress_certificate_num2method(uint16_t num)
+{
+ switch (num) {
+ case 1:
+ return GNUTLS_COMP_ZLIB;
+ case 2:
+ return GNUTLS_COMP_BROTLI;
+ case 3:
+ return GNUTLS_COMP_ZSTD;
+ default:
+ return GNUTLS_COMP_UNKNOWN;
+ }
+}
+
+/* Converts compression method type to compression algorithm number established in RFC8879 */
+int
+_gnutls_compress_certificate_method2num(gnutls_compression_method_t method)
+{
+ switch (method) {
+ case GNUTLS_COMP_ZLIB:
+ return 1;
+ case GNUTLS_COMP_BROTLI:
+ return 2;
+ case GNUTLS_COMP_ZSTD:
+ return 3;
+ default:
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+}
+
+/**
+ * gnutls_compress_certificate_get_selected_method:
+ * @session: is a #gnutls_session_t type.
+ *
+ * This function returns the certificate compression method that has been
+ * selected to compress the certificate before sending it to the peer.
+ * The selection is done based on the local list of supported compression
+ * methods and the peer's requested compression methods.
+ *
+ * Returns: selected certificate compression method.
+ *
+ * Since 3.7.4
+ **/
+gnutls_compression_method_t
+gnutls_compress_certificate_get_selected_method(gnutls_session_t session)
+{
+ return session->internals.compress_certificate_method;
+}
+
+/**
+ * gnutls_compress_certificate_set_methods:
+ * @session: is a #gnutls_session_t type.
+ * @methods: is a list of supported compression methods.
+ * @methods_len: number of compression methods in @methods
+ *
+ * This function sets the supported compression methods for certificate compression
+ * for the given session. The list of supported compression methods will be used
+ * for a) requesting the compression of peer's certificate and b) selecting the
+ * method to compress the local certificate before sending it to the peer.
+ * The order of compression methods inside the list does matter as the method
+ * that appears earlier in the list will be preffered before the later ones.
+ * Note that even if you set the list of supported compression methods, the
+ * compression might not be used if the peer does not support any of your chosen
+ * compression methods.
+ *
+ * The list of supported compression methods must meet the following criteria:
+ * Argument @methods must be an array of valid compression methods of type
+ * #gnutls_compression_method_t. Argument @methods_len must contain the number of
+ * compression methods stored in the @methods array and must be within range <1, 127>.
+ * The length constraints are defined by %MIN_COMPRESS_CERTIFICATE_METHODS
+ * and %MAX_COMPRESS_CERTIFICATE_METHODS macros located in the header file
+ * compress_certificate.h.
+ *
+ * If either @methods or @methods_len is equal to 0, current list of supported
+ * compression methods will be unset.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since 3.7.4
+ **/
+int
+gnutls_compress_certificate_set_methods(gnutls_session_t session,
+ const gnutls_compression_method_t * methods,
+ size_t methods_len)
+{
+ unsigned i;
+ compress_certificate_ext_st *priv;
+
+ if (methods == NULL || methods_len == 0) {
+ _gnutls_hello_ext_unset_priv(session, GNUTLS_EXTENSION_COMPRESS_CERTIFICATE);
+ return 0;
+ }
+
+ if (methods_len > MAX_COMPRESS_CERTIFICATE_METHODS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ for (i = 0; i < methods_len; ++i)
+ if (!is_valid_method(methods[i]))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ priv = gnutls_malloc(sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ priv->methods_len = methods_len;
+ memcpy(priv->methods, methods, methods_len * sizeof(*methods));
+ _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_COMPRESS_CERTIFICATE, priv);
+
+ return 0;
+}
+
+int
+_gnutls_compress_certificate_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size)
+{
+ int ret;
+ unsigned i, j;
+ uint16_t num;
+ uint8_t bytes_len;
+ size_t methods_len;
+ gnutls_compression_method_t methods[MAX_COMPRESS_CERTIFICATE_METHODS];
+ gnutls_compression_method_t method = GNUTLS_COMP_UNKNOWN;
+ compress_certificate_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret = _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_COMPRESS_CERTIFICATE, &epriv);
+ if (ret < 0)
+ return 0;
+ priv = epriv;
+
+ DECR_LEN(data_size, 1);
+ bytes_len = *data;
+
+ if (bytes_len < 2 || bytes_len > 254 || bytes_len % 2 == 1)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ DECR_LEN(data_size, bytes_len);
+ methods_len = bytes_len / 2;
+
+ for (i = 0; i < methods_len; ++i) {
+ num = _gnutls_read_uint16(data + i + i + 1);
+ methods[i] = _gnutls_compress_certificate_num2method(num);
+ if (methods[i] == GNUTLS_COMP_UNKNOWN)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+
+ for (i = 0; i < methods_len; ++i)
+ for (j = 0; j < priv->methods_len; ++j)
+ if (methods[i] == priv->methods[j]) {
+ method = methods[i];
+ goto endloop;
+ }
+endloop:
+ session->internals.compress_certificate_method = method;
+
+ return 0;
+}
+
+int
+_gnutls_compress_certificate_send_params(gnutls_session_t session,
+ gnutls_buffer_st * data)
+{
+ int ret, num;
+ unsigned i;
+ uint8_t bytes_len;
+ uint8_t bytes[2 * MAX_COMPRESS_CERTIFICATE_METHODS];
+ compress_certificate_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret = _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_COMPRESS_CERTIFICATE, &epriv);
+ if (ret < 0)
+ return 0;
+ priv = epriv;
+
+ bytes_len = 2 * priv->methods_len;
+ for (i = 0; i < priv->methods_len; ++i) {
+ num = _gnutls_compress_certificate_method2num(priv->methods[i]);
+ _gnutls_write_uint16(num, bytes + i + i);
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(data, 8, bytes, bytes_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return bytes_len + 1;
+}
+
+const hello_ext_entry_st ext_mod_compress_certificate = {
+ .name = "Compress Certificate",
+ .tls_id = 27,
+ .gid = GNUTLS_EXTENSION_COMPRESS_CERTIFICATE,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
+ GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .recv_func = _gnutls_compress_certificate_recv_params,
+ .send_func = _gnutls_compress_certificate_send_params,
+ .deinit_func = _gnutls_hello_ext_default_deinit
+};
diff --git a/lib/ext/compress_certificate.h b/lib/ext/compress_certificate.h
new file mode 100644
index 0000000..b708374
--- /dev/null
+++ b/lib/ext/compress_certificate.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Zoltan Fridrich
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_COMPRESS_CERTIFICATE_H
+#define GNUTLS_LIB_EXT_COMPRESS_CERTIFICATE_H
+
+#include <hello_ext.h>
+
+#define MIN_COMPRESS_CERTIFICATE_METHODS 1
+#define MAX_COMPRESS_CERTIFICATE_METHODS 127
+
+typedef struct {
+ gnutls_compression_method_t methods[MAX_COMPRESS_CERTIFICATE_METHODS];
+ size_t methods_len;
+} compress_certificate_ext_st;
+
+extern const hello_ext_entry_st ext_mod_compress_certificate;
+
+gnutls_compression_method_t _gnutls_compress_certificate_num2method(uint16_t num);
+int _gnutls_compress_certificate_method2num(gnutls_compression_method_t method);
+
+int
+_gnutls_compress_certificate_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+int
+_gnutls_compress_certificate_send_params(gnutls_session_t session,
+ gnutls_buffer_st * data);
+
+#endif /* GNUTLS_LIB_EXT_COMPRESS_CERTIFICATE_H */
diff --git a/lib/ext/cookie.c b/lib/ext/cookie.c
new file mode 100644
index 0000000..b4608f3
--- /dev/null
+++ b/lib/ext/cookie.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Max Record Size TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include "hello_ext_lib.h"
+#include <ext/cookie.h>
+
+static int cookie_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int cookie_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_cookie = {
+ .name = "Cookie",
+ .tls_id = 44,
+ .gid = GNUTLS_EXTENSION_COOKIE,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_HRR | GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST,
+ .client_parse_point = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */
+ .server_parse_point = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */
+ .recv_func = cookie_recv_params,
+ .send_func = cookie_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 0
+};
+
+/* Only client sends this extension. */
+static int
+cookie_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ size_t csize;
+ int ret;
+ gnutls_datum_t tmp;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ /* we don't support it */
+ return 0;
+ } else { /* client */
+ if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
+ DECR_LEN(data_size, 2);
+
+ csize = _gnutls_read_uint16(data);
+ data += 2;
+
+ DECR_LEN(data_size, csize);
+
+ if (data_size != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ tmp.data = (void*)data;
+ tmp.size = csize;
+
+ ret = _gnutls_hello_ext_set_datum(session, GNUTLS_EXTENSION_COOKIE, &tmp);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+ }
+
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+cookie_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ gnutls_datum_t tmp;
+ int ret;
+
+ /* this function sends the client extension data (dnsname) */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ ret = _gnutls_hello_ext_get_datum(session, GNUTLS_EXTENSION_COOKIE, &tmp);
+ if (ret < 0)
+ return 0;
+
+ ret = _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/lib/ext/cookie.h b/lib/ext/cookie.h
new file mode 100644
index 0000000..13ea7c7
--- /dev/null
+++ b/lib/ext/cookie.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_COOKIE_H
+#define GNUTLS_LIB_EXT_COOKIE_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_cookie;
+
+#endif /* GNUTLS_LIB_EXT_COOKIE_H */
diff --git a/lib/ext/dumbfw.c b/lib/ext/dumbfw.c
new file mode 100644
index 0000000..dfd2ee0
--- /dev/null
+++ b/lib/ext/dumbfw.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "auth.h"
+#include "errors.h"
+#include "num.h"
+#include <ext/dumbfw.h>
+
+/* This extension adds additional padding data in the TLS client hello.
+ * There is an issue with some firewalls [0] rejecting TLS client hello
+ * data that are between 256 and 511 bytes, and this extension will
+ * make sure that client hello isn't in this range.
+ *
+ * [0]. https://www.ietf.org/mail-archive/web/tls/current/msg10423.html
+ */
+
+static int _gnutls_dumbfw_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_dumbfw = {
+ .name = "ClientHello Padding",
+ .tls_id = 21,
+ .gid = GNUTLS_EXTENSION_DUMBFW,
+ .client_parse_point = GNUTLS_EXT_APPLICATION,
+ .server_parse_point = GNUTLS_EXT_APPLICATION,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .recv_func = NULL,
+ .send_func = _gnutls_dumbfw_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 0
+};
+
+static int
+_gnutls_dumbfw_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ int total_size = 0, ret;
+ uint8_t pad[257];
+ unsigned pad_size;
+ ssize_t len = extdata->length - sizeof(mbuffer_st);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER ||
+ session->internals.dumbfw == 0 ||
+ IS_DTLS(session) != 0 ||
+ (len < 256 || len >= 512)) {
+ return 0;
+ } else {
+ /* 256 <= extdata->length < 512 */
+ pad_size = 512 - len;
+ memset(pad, 0, pad_size);
+
+ ret =
+ gnutls_buffer_append_data(extdata, pad,
+ pad_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ total_size += pad_size;
+ }
+
+ return total_size;
+}
+
diff --git a/lib/ext/dumbfw.h b/lib/ext/dumbfw.h
new file mode 100644
index 0000000..87bb072
--- /dev/null
+++ b/lib/ext/dumbfw.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_DUMBFW_H
+#define GNUTLS_LIB_EXT_DUMBFW_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_dumbfw;
+
+#endif /* GNUTLS_LIB_EXT_DUMBFW_H */
diff --git a/lib/ext/early_data.c b/lib/ext/early_data.c
new file mode 100644
index 0000000..28c3182
--- /dev/null
+++ b/lib/ext/early_data.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Early Data TLS 1.3 extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include "hello_ext_lib.h"
+#include <ext/early_data.h>
+
+static int early_data_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int early_data_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_early_data = {
+ .name = "Early Data",
+ .tls_id = 42,
+ .gid = GNUTLS_EXTENSION_EARLY_DATA,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE,
+ .client_parse_point = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */
+ .server_parse_point = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */
+ .recv_func = early_data_recv_params,
+ .send_func = early_data_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 0
+};
+
+static int
+early_data_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ const version_entry_st *vers = get_version(session);
+
+ if (!vers || !vers->tls13_sem)
+ return gnutls_assert_val(0);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ /* Whether to accept early data is decided during processing the
+ * pre_shared_key extension in the later phase.
+ */
+ session->internals.hsk_flags |= HSK_EARLY_DATA_IN_FLIGHT;
+ } else {
+ if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_EE)
+ session->internals.hsk_flags |= HSK_EARLY_DATA_ACCEPTED;
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+early_data_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED)
+ return GNUTLS_E_INT_RET_0;
+ } else {
+ /* early data is enabled and resuming a TLS 1.3 session */
+ if (session->internals.flags & GNUTLS_ENABLE_EARLY_DATA &&
+ !(session->internals.resumption_requested == 0 &&
+ session->internals.premaster_set == 0) &&
+ session->internals.resumed_security_parameters.pversion &&
+ session->internals.resumed_security_parameters.pversion->tls13_sem) {
+ session->internals.hsk_flags |= HSK_EARLY_DATA_IN_FLIGHT;
+ return GNUTLS_E_INT_RET_0;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_record_get_max_early_data_size:
+ * @session: is a #gnutls_session_t type.
+ *
+ * This function returns the maximum early data size in this connection.
+ * This property can only be set to servers. The client may be
+ * provided with the maximum allowed size through the "early_data"
+ * extension of the NewSessionTicket handshake message.
+ *
+ * Returns: The maximum early data size in this connection.
+ *
+ * Since: 3.6.5
+ **/
+size_t
+gnutls_record_get_max_early_data_size(gnutls_session_t session)
+{
+ return session->security_parameters.max_early_data_size;
+}
+
+/**
+ * gnutls_record_set_max_early_data_size:
+ * @session: is a #gnutls_session_t type.
+ * @size: is the new size
+ *
+ * This function sets the maximum early data size in this connection.
+ * This property can only be set to servers. The client may be
+ * provided with the maximum allowed size through the "early_data"
+ * extension of the NewSessionTicket handshake message.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since: 3.6.4
+ **/
+int
+gnutls_record_set_max_early_data_size(gnutls_session_t session,
+ size_t size)
+{
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ /* Reject zero as well, as it is useless. */
+ if (size == 0 || size > UINT32_MAX)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ session->security_parameters.max_early_data_size = (uint32_t) size;
+
+ return 0;
+}
diff --git a/lib/ext/early_data.h b/lib/ext/early_data.h
new file mode 100644
index 0000000..d7178e8
--- /dev/null
+++ b/lib/ext/early_data.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_EARLY_DATA_H
+#define GNUTLS_LIB_EXT_EARLY_DATA_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_early_data;
+
+#endif /* GNUTLS_LIB_EXT_EARLY_DATA_H */
diff --git a/lib/ext/ec_point_formats.c b/lib/ext/ec_point_formats.c
new file mode 100644
index 0000000..d426580
--- /dev/null
+++ b/lib/ext/ec_point_formats.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Elliptic Curve Point Formats extension.
+ */
+
+#include "ext/ec_point_formats.h"
+#include "str.h"
+#include "state.h"
+#include <gnutls/gnutls.h>
+
+
+static int _gnutls_supported_ec_point_formats_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_supported_ec_point_formats_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+
+const hello_ext_entry_st ext_mod_supported_ec_point_formats = {
+ .name = "Supported EC Point Formats",
+ .tls_id = 11,
+ .gid = GNUTLS_EXTENSION_SUPPORTED_EC_POINT_FORMATS,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
+ GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_supported_ec_point_formats_recv_params,
+ .send_func = _gnutls_supported_ec_point_formats_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL
+};
+
+
+/* Receive point formats
+ */
+static int
+_gnutls_supported_ec_point_formats_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size)
+{
+ size_t len, i;
+ int uncompressed = 0;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (data_size < 1)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+
+ len = data[0];
+ if (len < 1)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+
+ DECR_LEN(data_size, len + 1);
+
+ for (i = 1; i <= len; i++)
+ if (data[i] == 0) { /* uncompressed */
+ uncompressed = 1;
+ break;
+ }
+
+ if (uncompressed == 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+ } else {
+ /* only sanity check here. We only support uncompressed points
+ * and a client must support it thus nothing to check.
+ */
+ if (data_size < 1)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_supported_ec_point_formats_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ const uint8_t p[2] = { 0x01, 0x00 }; /* only support uncompressed point format */
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER
+ && !_gnutls_session_is_ecc(session))
+ return 0;
+
+ if (session->internals.priorities->groups.size > 0) {
+ ret = _gnutls_buffer_append_data(extdata, p, 2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 2;
+ }
+ return 0;
+}
diff --git a/lib/ext/ec_point_formats.h b/lib/ext/ec_point_formats.h
new file mode 100644
index 0000000..cc65c04
--- /dev/null
+++ b/lib/ext/ec_point_formats.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_EC_POINT_FORMATS_H
+#define GNUTLS_LIB_EXT_EC_POINT_FORMATS_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_supported_ec_point_formats;
+
+#endif /* GNUTLS_LIB_EXT_EC_POINT_FORMATS_H */
diff --git a/lib/ext/etm.c b/lib/ext/etm.c
new file mode 100644
index 0000000..273a31a
--- /dev/null
+++ b/lib/ext/etm.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Max Record Size TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/etm.h>
+
+static int _gnutls_ext_etm_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_ext_etm_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_etm = {
+ .name = "Encrypt-then-MAC",
+ .tls_id = 22,
+ .gid = GNUTLS_EXTENSION_ETM,
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_ext_etm_recv_params,
+ .send_func = _gnutls_ext_etm_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+/*
+ * In case of a server: if an EXT_MASTER_SECRET extension type is received then it
+ * sets a flag into the session security parameters.
+ *
+ */
+static int
+_gnutls_ext_etm_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ ssize_t data_size = _data_size;
+
+ if (data_size != 0) {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->internals.no_etm != 0)
+ return 0;
+
+ epriv = (void*)(intptr_t)1;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_ETM,
+ epriv);
+
+ /* don't decide now, decide on send */
+ return 0;
+ } else { /* client */
+ const gnutls_cipher_suite_entry_st *e =
+ session->security_parameters.cs;
+ if (e != NULL) {
+ const cipher_entry_st *c;
+ c = cipher_to_entry(e->block_algorithm);
+ if (c == NULL || (c->type == CIPHER_AEAD || c->type == CIPHER_STREAM))
+ return 0;
+
+ session->security_parameters.etm = 1;
+ }
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_ext_etm_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ if (session->internals.no_etm != 0)
+ return 0;
+
+ /* this function sends the client extension data */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (session->internals.priorities->have_cbc != 0)
+ return GNUTLS_E_INT_RET_0;
+ else
+ return 0;
+ } else { /* server side */
+ const gnutls_cipher_suite_entry_st *e;
+ const cipher_entry_st *c;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+
+ e = session->security_parameters.cs;
+ if (e != NULL) {
+ c = cipher_to_entry(e->block_algorithm);
+ if (c == NULL || (c->type == CIPHER_AEAD || c->type == CIPHER_STREAM))
+ return 0;
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_ETM,
+ &epriv);
+ if (ret < 0 || ((intptr_t)epriv) == 0)
+ return 0;
+
+ session->security_parameters.etm = 1;
+ return GNUTLS_E_INT_RET_0;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_session_etm_status:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Get the status of the encrypt-then-mac extension negotiation.
+ * This is in accordance to rfc7366
+ *
+ * Returns: Non-zero if the negotiation was successful or zero otherwise.
+ **/
+unsigned gnutls_session_etm_status(gnutls_session_t session)
+{
+ return session->security_parameters.etm;
+}
diff --git a/lib/ext/etm.h b/lib/ext/etm.h
new file mode 100644
index 0000000..76f9dd5
--- /dev/null
+++ b/lib/ext/etm.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_ETM_H
+#define GNUTLS_LIB_EXT_ETM_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_etm;
+
+#endif /* GNUTLS_LIB_EXT_ETM_H */
diff --git a/lib/ext/ext_master_secret.c b/lib/ext/ext_master_secret.c
new file mode 100644
index 0000000..bc704e6
--- /dev/null
+++ b/lib/ext/ext_master_secret.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014-2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the RFC7627 (ext master secret) TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/ext_master_secret.h>
+
+static int _gnutls_ext_master_secret_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_ext_master_secret_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_ext_master_secret = {
+ .name = "Extended Master Secret",
+ .tls_id = 23,
+ .gid = GNUTLS_EXTENSION_EXT_MASTER_SECRET,
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .validity = GNUTLS_EXT_FLAG_TLS|GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_ext_master_secret_recv_params,
+ .send_func = _gnutls_ext_master_secret_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+#ifdef ENABLE_SSL3
+static inline unsigned have_only_ssl3_enabled(gnutls_session_t session)
+{
+ if (session->internals.priorities->protocol.num_priorities == 1 &&
+ session->internals.priorities->protocol.priorities[0] == GNUTLS_SSL3)
+ return 1;
+ return 0;
+}
+#endif
+
+/*
+ * In case of a server: if an EXT_MASTER_SECRET extension type is received then it
+ * sets a flag into the session security parameters.
+ *
+ */
+static int
+_gnutls_ext_master_secret_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ ssize_t data_size = _data_size;
+
+ if ((session->internals.flags & GNUTLS_NO_EXTENSIONS) ||
+ session->internals.priorities->no_extensions ||
+ session->internals.no_ext_master_secret != 0) {
+ return 0;
+ }
+
+ if (data_size != 0) {
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+
+#ifdef ENABLE_SSL3
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ const version_entry_st *ver = get_version(session);
+
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ if (ver->id != GNUTLS_SSL3)
+ session->security_parameters.ext_master_secret = 1;
+ /* do not enable ext master secret if SSL 3.0 is the only protocol supported by server */
+ } else if (!have_only_ssl3_enabled(session))
+#endif
+ session->security_parameters.ext_master_secret = 1;
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_ext_master_secret_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ if ((session->internals.flags & GNUTLS_NO_EXTENSIONS) ||
+ session->internals.priorities->no_extensions != 0 ||
+ session->internals.no_ext_master_secret != 0) {
+ session->security_parameters.ext_master_secret = 0;
+ return 0;
+ }
+
+ /* this function sends the client extension data */
+#ifdef ENABLE_SSL3
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (have_only_ssl3_enabled(session))
+ return 0; /* this extension isn't available for SSL 3.0 */
+
+ return GNUTLS_E_INT_RET_0;
+ } else { /* server side */
+ const version_entry_st *ver = get_version(session);
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ if (ver->id != GNUTLS_SSL3 && session->security_parameters.ext_master_secret != 0)
+ return GNUTLS_E_INT_RET_0;
+ }
+
+
+ return 0;
+#else
+ if (session->security_parameters.entity == GNUTLS_CLIENT ||
+ session->security_parameters.ext_master_secret != 0)
+ return GNUTLS_E_INT_RET_0;
+ return 0;
+#endif
+}
+
+/**
+ * gnutls_session_ext_master_secret_status:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Get the status of the extended master secret extension negotiation.
+ * This is in accordance to RFC7627. That information is also
+ * available to the more generic gnutls_session_get_flags().
+ *
+ * Returns: Non-zero if the negotiation was successful or zero otherwise.
+ **/
+unsigned gnutls_session_ext_master_secret_status(gnutls_session_t session)
+{
+ return session->security_parameters.ext_master_secret;
+}
+
diff --git a/lib/ext/ext_master_secret.h b/lib/ext/ext_master_secret.h
new file mode 100644
index 0000000..419335b
--- /dev/null
+++ b/lib/ext/ext_master_secret.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_EXT_MASTER_SECRET_H
+#define GNUTLS_LIB_EXT_EXT_MASTER_SECRET_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_ext_master_secret;
+
+#endif /* GNUTLS_LIB_EXT_EXT_MASTER_SECRET_H */
diff --git a/lib/ext/heartbeat.c b/lib/ext/heartbeat.c
new file mode 100644
index 0000000..5d9e9f4
--- /dev/null
+++ b/lib/ext/heartbeat.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2012,2013 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file implements the TLS heartbeat extension.
+ */
+
+#include "errors.h"
+#include "gnutls_int.h"
+#include <dtls.h>
+#include <record.h>
+#include <ext/heartbeat.h>
+#include <hello_ext.h>
+#include <random.h>
+
+#ifdef ENABLE_HEARTBEAT
+/**
+ * gnutls_heartbeat_enable:
+ * @session: is a #gnutls_session_t type.
+ * @type: one of the GNUTLS_HB_* flags
+ *
+ * If this function is called with the %GNUTLS_HB_PEER_ALLOWED_TO_SEND
+ * @type, GnuTLS will allow heartbeat messages to be received. Moreover it also
+ * request the peer to accept heartbeat messages. This function
+ * must be called prior to TLS handshake.
+ *
+ * If the @type used is %GNUTLS_HB_LOCAL_ALLOWED_TO_SEND, then the peer
+ * will be asked to accept heartbeat messages but not send ones.
+ *
+ * The function gnutls_heartbeat_allowed() can be used to test Whether
+ * locally generated heartbeat messages can be accepted by the peer.
+ *
+ * Since: 3.1.2
+ **/
+void gnutls_heartbeat_enable(gnutls_session_t session, unsigned int type)
+{
+ gnutls_ext_priv_data_t epriv;
+
+ epriv = (void*)(intptr_t)type;
+ _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_HEARTBEAT,
+ epriv);
+}
+
+/**
+ * gnutls_heartbeat_allowed:
+ * @session: is a #gnutls_session_t type.
+ * @type: one of %GNUTLS_HB_LOCAL_ALLOWED_TO_SEND and %GNUTLS_HB_PEER_ALLOWED_TO_SEND
+ *
+ * This function will check whether heartbeats are allowed
+ * to be sent or received in this session.
+ *
+ * Returns: Non zero if heartbeats are allowed.
+ *
+ * Since: 3.1.2
+ **/
+unsigned gnutls_heartbeat_allowed(gnutls_session_t session, unsigned int type)
+{
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->internals.handshake_in_progress != 0)
+ return 0; /* not allowed */
+
+ if (_gnutls_hello_ext_get_priv
+ (session, GNUTLS_EXTENSION_HEARTBEAT, &epriv) < 0)
+ return 0; /* Not enabled */
+
+ if (type == GNUTLS_HB_LOCAL_ALLOWED_TO_SEND) {
+ if (((intptr_t)epriv) & LOCAL_ALLOWED_TO_SEND)
+ return 1;
+ } else if (((intptr_t)epriv) & GNUTLS_HB_PEER_ALLOWED_TO_SEND)
+ return 1;
+
+ return 0;
+}
+
+#define DEFAULT_PADDING_SIZE 16
+
+/*
+ * Sends heartbeat data.
+ */
+static int
+heartbeat_send_data(gnutls_session_t session, const void *data,
+ size_t data_size, uint8_t type)
+{
+ int ret, pos;
+ uint8_t *response;
+
+ response = gnutls_malloc(1 + 2 + data_size + DEFAULT_PADDING_SIZE);
+ if (response == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ pos = 0;
+ response[pos++] = type;
+
+ _gnutls_write_uint16(data_size, &response[pos]);
+ pos += 2;
+
+ memcpy(&response[pos], data, data_size);
+ pos += data_size;
+
+ ret =
+ gnutls_rnd(GNUTLS_RND_NONCE, &response[pos],
+ DEFAULT_PADDING_SIZE);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ pos += DEFAULT_PADDING_SIZE;
+
+ ret =
+ _gnutls_send_int(session, GNUTLS_HEARTBEAT, -1,
+ EPOCH_WRITE_CURRENT, response, pos,
+ MBUFFER_FLUSH);
+
+ cleanup:
+ gnutls_free(response);
+ return ret;
+}
+
+/**
+ * gnutls_heartbeat_ping:
+ * @session: is a #gnutls_session_t type.
+ * @data_size: is the length of the ping payload.
+ * @max_tries: if flags is %GNUTLS_HEARTBEAT_WAIT then this sets the number of retransmissions. Use zero for indefinite (until timeout).
+ * @flags: if %GNUTLS_HEARTBEAT_WAIT then wait for pong or timeout instead of returning immediately.
+ *
+ * This function sends a ping to the peer. If the @flags is set
+ * to %GNUTLS_HEARTBEAT_WAIT then it waits for a reply from the peer.
+ *
+ * Note that it is highly recommended to use this function with the
+ * flag %GNUTLS_HEARTBEAT_WAIT, or you need to handle retransmissions
+ * and timeouts manually.
+ *
+ * The total TLS data transmitted as part of the ping message are given by
+ * the following formula: MAX(16, @data_size)+gnutls_record_overhead_size()+3.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.1.2
+ **/
+int
+gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size,
+ unsigned int max_tries, unsigned int flags)
+{
+ int ret;
+ unsigned int retries = 1, diff;
+ struct timespec now;
+
+ if (data_size > MAX_HEARTBEAT_LENGTH)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (gnutls_heartbeat_allowed
+ (session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND) == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ /* resume previous call if interrupted */
+ if (session->internals.record_send_buffer.byte_length > 0 &&
+ session->internals.record_send_buffer.head != NULL &&
+ session->internals.record_send_buffer.head->type ==
+ GNUTLS_HEARTBEAT)
+ return _gnutls_io_write_flush(session);
+
+ switch (session->internals.hb_state) {
+ case SHB_SEND1:
+ if (data_size > DEFAULT_PADDING_SIZE)
+ data_size -= DEFAULT_PADDING_SIZE;
+ else
+ data_size = 0;
+
+ _gnutls_buffer_reset(&session->internals.hb_local_data);
+
+ ret =
+ _gnutls_buffer_resize(&session->internals.
+ hb_local_data, data_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ gnutls_rnd(GNUTLS_RND_NONCE,
+ session->internals.hb_local_data.data,
+ data_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ gnutls_gettime(&session->internals.hb_ping_start);
+ session->internals.hb_local_data.length = data_size;
+ session->internals.hb_state = SHB_SEND2;
+
+ FALLTHROUGH;
+ case SHB_SEND2:
+ session->internals.hb_actual_retrans_timeout_ms =
+ session->internals.hb_retrans_timeout_ms;
+ retry:
+ ret =
+ heartbeat_send_data(session,
+ session->internals.hb_local_data.
+ data,
+ session->internals.hb_local_data.
+ length, HEARTBEAT_REQUEST);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ gnutls_gettime(&session->internals.hb_ping_sent);
+
+ if (!(flags & GNUTLS_HEARTBEAT_WAIT)) {
+ session->internals.hb_state = SHB_SEND1;
+ break;
+ }
+
+ session->internals.hb_state = SHB_RECV;
+ FALLTHROUGH;
+
+ case SHB_RECV:
+ ret =
+ _gnutls_recv_int(session, GNUTLS_HEARTBEAT,
+ NULL, 0, NULL,
+ session->internals.
+ hb_actual_retrans_timeout_ms);
+ if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
+ session->internals.hb_state = SHB_SEND1;
+ break;
+ } else if (ret == GNUTLS_E_TIMEDOUT) {
+ retries++;
+ if (max_tries > 0 && retries > max_tries) {
+ session->internals.hb_state = SHB_SEND1;
+ return gnutls_assert_val(ret);
+ }
+
+ gnutls_gettime(&now);
+ diff =
+ timespec_sub_ms(&now,
+ &session->internals.
+ hb_ping_start);
+ if (diff > session->internals.hb_total_timeout_ms) {
+ session->internals.hb_state = SHB_SEND1;
+ return
+ gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ }
+
+ session->internals.hb_actual_retrans_timeout_ms *=
+ 2;
+ session->internals.hb_actual_retrans_timeout_ms %=
+ MAX_DTLS_TIMEOUT;
+
+ session->internals.hb_state = SHB_SEND2;
+ goto retry;
+ } else if (ret < 0) {
+ session->internals.hb_state = SHB_SEND1;
+ return gnutls_assert_val(ret);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_heartbeat_pong:
+ * @session: is a #gnutls_session_t type.
+ * @flags: should be zero
+ *
+ * This function replies to a ping by sending a pong to the peer.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.1.2
+ **/
+int gnutls_heartbeat_pong(gnutls_session_t session, unsigned int flags)
+{
+ int ret;
+
+ if (session->internals.record_send_buffer.byte_length > 0 &&
+ session->internals.record_send_buffer.head != NULL &&
+ session->internals.record_send_buffer.head->type ==
+ GNUTLS_HEARTBEAT)
+ return _gnutls_io_write_flush(session);
+
+ if (session->internals.hb_remote_data.length == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret =
+ heartbeat_send_data(session,
+ session->internals.hb_remote_data.data,
+ session->internals.hb_remote_data.length,
+ HEARTBEAT_RESPONSE);
+
+ _gnutls_buffer_reset(&session->internals.hb_remote_data);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+/*
+ * Processes a heartbeat message.
+ */
+int _gnutls_heartbeat_handle(gnutls_session_t session, mbuffer_st * bufel)
+{
+ int ret;
+ unsigned type;
+ unsigned pos;
+ uint8_t *msg = _mbuffer_get_udata_ptr(bufel);
+ size_t hb_len, len = _mbuffer_get_udata_size(bufel);
+
+ if (gnutls_heartbeat_allowed
+ (session, GNUTLS_HB_PEER_ALLOWED_TO_SEND) == 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+
+ if (len < 3 + DEFAULT_PADDING_SIZE)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ pos = 0;
+ type = msg[pos++];
+
+ hb_len = _gnutls_read_uint16(&msg[pos]);
+ if (hb_len > len - 3 - DEFAULT_PADDING_SIZE)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ pos += 2;
+
+ switch (type) {
+ case HEARTBEAT_REQUEST:
+ _gnutls_buffer_reset(&session->internals.hb_remote_data);
+
+ ret =
+ _gnutls_buffer_resize(&session->internals.
+ hb_remote_data, hb_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (hb_len > 0)
+ memcpy(session->internals.hb_remote_data.data,
+ &msg[pos], hb_len);
+ session->internals.hb_remote_data.length = hb_len;
+
+ return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PING_RECEIVED);
+
+ case HEARTBEAT_RESPONSE:
+
+ if (hb_len != session->internals.hb_local_data.length)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+
+ if (hb_len > 0 &&
+ memcmp(&msg[pos],
+ session->internals.hb_local_data.data,
+ hb_len) != 0) {
+ if (IS_DTLS(session))
+ return gnutls_assert_val(GNUTLS_E_AGAIN); /* ignore it */
+ else
+ return
+ gnutls_assert_val
+ (GNUTLS_E_UNEXPECTED_PACKET);
+ }
+
+ _gnutls_buffer_reset(&session->internals.hb_local_data);
+
+ return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PONG_RECEIVED);
+ default:
+ _gnutls_record_log
+ ("REC[%p]: HB: received unknown type %u\n", session,
+ type);
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+ }
+}
+
+/**
+ * gnutls_heartbeat_get_timeout:
+ * @session: is a #gnutls_session_t type.
+ *
+ * This function will return the milliseconds remaining
+ * for a retransmission of the previously sent ping
+ * message. This function is useful when ping is used in
+ * non-blocking mode, to estimate when to call gnutls_heartbeat_ping()
+ * if no packets have been received.
+ *
+ * Returns: the remaining time in milliseconds.
+ *
+ * Since: 3.1.2
+ **/
+unsigned int gnutls_heartbeat_get_timeout(gnutls_session_t session)
+{
+ struct timespec now;
+ unsigned int diff;
+
+ gnutls_gettime(&now);
+ diff = timespec_sub_ms(&now, &session->internals.hb_ping_sent);
+ if (diff >= session->internals.hb_actual_retrans_timeout_ms)
+ return 0;
+ else
+ return session->internals.hb_actual_retrans_timeout_ms -
+ diff;
+}
+
+/**
+ * gnutls_heartbeat_set_timeouts:
+ * @session: is a #gnutls_session_t type.
+ * @retrans_timeout: The time at which a retransmission will occur in milliseconds
+ * @total_timeout: The time at which the connection will be aborted, in milliseconds.
+ *
+ * This function will override the timeouts for the DTLS heartbeat
+ * protocol. The retransmission timeout is the time after which a
+ * message from the peer is not received, the previous request will
+ * be retransmitted. The total timeout is the time after which the
+ * handshake will be aborted with %GNUTLS_E_TIMEDOUT.
+ *
+ * Since: 3.1.2
+ **/
+void gnutls_heartbeat_set_timeouts(gnutls_session_t session,
+ unsigned int retrans_timeout,
+ unsigned int total_timeout)
+{
+ session->internals.hb_retrans_timeout_ms = retrans_timeout;
+ session->internals.hb_total_timeout_ms = total_timeout;
+}
+
+
+static int
+_gnutls_heartbeat_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ unsigned policy;
+ gnutls_ext_priv_data_t epriv;
+
+ if (_gnutls_hello_ext_get_priv
+ (session, GNUTLS_EXTENSION_HEARTBEAT, &epriv) < 0) {
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ return 0; /* Not enabled */
+ }
+
+ if (_data_size == 0)
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+
+ policy = (intptr_t)epriv;
+
+ if (data[0] == 1)
+ policy |= LOCAL_ALLOWED_TO_SEND;
+ else if (data[0] == 2)
+ policy |= LOCAL_NOT_ALLOWED_TO_SEND;
+ else
+ return
+ gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ epriv = (void*)(intptr_t)policy;
+ _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_HEARTBEAT,
+ epriv);
+
+ return 0;
+}
+
+static int
+_gnutls_heartbeat_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ gnutls_ext_priv_data_t epriv;
+ uint8_t p;
+
+ if (_gnutls_hello_ext_get_priv
+ (session, GNUTLS_EXTENSION_HEARTBEAT, &epriv) < 0)
+ return 0; /* nothing to send - not enabled */
+
+ if (((intptr_t)epriv) & GNUTLS_HB_PEER_ALLOWED_TO_SEND)
+ p = 1;
+ else /*if (epriv.num & GNUTLS_HB_PEER_NOT_ALLOWED_TO_SEND) */
+ p = 2;
+
+ if (_gnutls_buffer_append_data(extdata, &p, 1) < 0)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ return 1;
+}
+
+static int
+_gnutls_heartbeat_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
+{
+ int ret;
+
+ BUFFER_APPEND_NUM(ps, (intptr_t)epriv);
+
+ return 0;
+
+}
+
+static int
+_gnutls_heartbeat_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv)
+{
+ gnutls_ext_priv_data_t epriv;
+ int ret;
+
+ BUFFER_POP_CAST_NUM(ps, epriv);
+
+ *_priv = epriv;
+
+ ret = 0;
+ error:
+ return ret;
+}
+
+const hello_ext_entry_st ext_mod_heartbeat = {
+ .name = "Heartbeat",
+ .tls_id = 15,
+ .gid = GNUTLS_EXTENSION_HEARTBEAT,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_heartbeat_recv_params,
+ .send_func = _gnutls_heartbeat_send_params,
+ .pack_func = _gnutls_heartbeat_pack,
+ .unpack_func = _gnutls_heartbeat_unpack,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+#else
+void gnutls_heartbeat_enable(gnutls_session_t session, unsigned int type)
+{
+}
+
+unsigned gnutls_heartbeat_allowed(gnutls_session_t session, unsigned int type)
+{
+ return 0;
+}
+
+int
+gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size,
+ unsigned int max_tries, unsigned int flags)
+{
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+}
+
+int gnutls_heartbeat_pong(gnutls_session_t session, unsigned int flags)
+{
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+}
+
+unsigned int gnutls_heartbeat_get_timeout(gnutls_session_t session)
+{
+ return 0;
+}
+
+void gnutls_heartbeat_set_timeouts(gnutls_session_t session,
+ unsigned int retrans_timeout,
+ unsigned int total_timeout)
+{
+ return;
+}
+#endif
diff --git a/lib/ext/heartbeat.h b/lib/ext/heartbeat.h
new file mode 100644
index 0000000..1a21004
--- /dev/null
+++ b/lib/ext/heartbeat.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_HEARTBEAT_H
+#define GNUTLS_LIB_EXT_HEARTBEAT_H
+
+#include <hello_ext.h>
+
+#define HEARTBEAT_REQUEST 1
+#define HEARTBEAT_RESPONSE 2
+
+#define MAX_HEARTBEAT_LENGTH DEFAULT_MAX_RECORD_SIZE
+
+#define LOCAL_ALLOWED_TO_SEND (1<<2)
+#define LOCAL_NOT_ALLOWED_TO_SEND (1<<3)
+
+#define HEARTBEAT_DEFAULT_POLICY PEER_NOT_ALLOWED_TO_SEND
+
+extern const hello_ext_entry_st ext_mod_heartbeat;
+
+int _gnutls_heartbeat_handle(gnutls_session_t session, mbuffer_st * bufel);
+int _gnutls_heartbeat_enabled(gnutls_session_t session, int local);
+
+#endif /* GNUTLS_LIB_EXT_HEARTBEAT_H */
diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c
new file mode 100644
index 0000000..a4db3af
--- /dev/null
+++ b/lib/ext/key_share.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code the Key Share TLS 1.3 extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include "ext/supported_groups.h"
+#include <state.h>
+#include <num.h>
+#include <algorithms.h>
+#include "auth/psk.h"
+#include "auth/cert.h"
+#include "handshake.h"
+#include "../ecc.h"
+#include "../algorithms.h"
+#include "pk.h"
+
+static int key_share_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int key_share_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_key_share = {
+ .name = "Key Share",
+ .tls_id = 51,
+ .gid = GNUTLS_EXTENSION_KEY_SHARE,
+ .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
+ .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO |
+ GNUTLS_EXT_FLAG_HRR,
+ .recv_func = key_share_recv_params,
+ .send_func = key_share_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+/*
+ * Generates key exchange parameters, and stores them in
+ * session->key.kshare_*_params.
+ *
+ * struct {
+ * NamedGroup group;
+ * opaque key_exchange<1..2^16-1>;
+ * } KeyShareEntry;
+ *
+ */
+static int client_gen_key_share(gnutls_session_t session, const gnutls_group_entry_st *group, gnutls_buffer_st *extdata)
+{
+ gnutls_datum_t tmp = {NULL, 0};
+ int ret;
+
+ if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
+ group->pk != GNUTLS_PK_ECDH_X448 &&
+ group->pk != GNUTLS_PK_DH) {
+ _gnutls_debug_log("Cannot send key share for group %s!\n", group->name);
+ return GNUTLS_E_INT_RET_0;
+ }
+
+ _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session, group->name);
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (group->pk == GNUTLS_PK_EC) {
+ gnutls_pk_params_release(&session->key.kshare.ecdh_params);
+ gnutls_pk_params_init(&session->key.kshare.ecdh_params);
+
+ ret = _gnutls_pk_generate_keys(group->pk, group->curve,
+ &session->key.kshare.ecdh_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_ecc_ansi_x962_export(group->curve,
+ session->key.kshare.ecdh_params.params[ECC_X],
+ session->key.kshare.ecdh_params.params[ECC_Y],
+ &tmp);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ session->key.kshare.ecdh_params.algo = group->pk;
+ session->key.kshare.ecdh_params.curve = group->curve;
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
+ group->pk == GNUTLS_PK_ECDH_X448) {
+ gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
+ gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
+
+ ret = _gnutls_pk_generate_keys(group->pk, group->curve,
+ &session->key.kshare.ecdhx_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 16,
+ session->key.kshare.ecdhx_params.raw_pub.data,
+ session->key.kshare.ecdhx_params.raw_pub.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ session->key.kshare.ecdhx_params.algo = group->pk;
+ session->key.kshare.ecdhx_params.curve = group->curve;
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_DH) {
+ /* we need to initialize the group parameters first */
+ gnutls_pk_params_release(&session->key.kshare.dh_params);
+ gnutls_pk_params_init(&session->key.kshare.dh_params);
+
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_G],
+ group->generator->data, group->generator->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_P],
+ group->prime->data, group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_Q],
+ group->q->data, group->q->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ session->key.kshare.dh_params.algo = group->pk;
+ session->key.kshare.dh_params.dh_group = group->id; /* no curve in FFDH, we write the group */
+ session->key.kshare.dh_params.qbits = *group->q_bits;
+ session->key.kshare.dh_params.params_nr = 3;
+
+ ret = _gnutls_pk_generate_keys(group->pk, 0, &session->key.kshare.dh_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_buffer_append_fixed_mpi(extdata, session->key.kshare.dh_params.params[DH_Y],
+ group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = 0;
+ }
+
+ cleanup:
+ gnutls_free(tmp.data);
+ return ret;
+}
+
+/*
+ * Sends server key exchange parameters
+ *
+ */
+static int server_gen_key_share(gnutls_session_t session, const gnutls_group_entry_st *group, gnutls_buffer_st *extdata)
+{
+ gnutls_datum_t tmp = {NULL, 0};
+ int ret;
+
+ if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
+ group->pk != GNUTLS_PK_ECDH_X448 &&
+ group->pk != GNUTLS_PK_DH) {
+ _gnutls_debug_log("Cannot send key share for group %s!\n", group->name);
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+ _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session, group->name);
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (group->pk == GNUTLS_PK_EC) {
+ ret = _gnutls_ecc_ansi_x962_export(group->curve,
+ session->key.kshare.ecdh_params.params[ECC_X],
+ session->key.kshare.ecdh_params.params[ECC_Y],
+ &tmp);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
+ group->pk == GNUTLS_PK_ECDH_X448) {
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 16,
+ session->key.kshare.ecdhx_params.raw_pub.data,
+ session->key.kshare.ecdhx_params.raw_pub.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_DH) {
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_buffer_append_fixed_mpi(extdata, session->key.kshare.dh_params.params[DH_Y],
+ group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = 0;
+ }
+
+ cleanup:
+ gnutls_free(tmp.data);
+ return ret;
+}
+
+/* Generates shared key and stores it in session->key.key
+ */
+static int
+server_use_key_share(gnutls_session_t session, const gnutls_group_entry_st *group,
+ const uint8_t * data, size_t data_size)
+{
+ const gnutls_ecc_curve_entry_st *curve;
+ int ret;
+
+ if (group->pk == GNUTLS_PK_EC) {
+ gnutls_pk_params_st pub;
+
+ gnutls_pk_params_release(&session->key.kshare.ecdh_params);
+ gnutls_pk_params_init(&session->key.kshare.ecdh_params);
+
+ curve = _gnutls_ecc_curve_get_params(group->curve);
+
+ gnutls_pk_params_init(&pub);
+
+ if (curve->size*2+1 != data_size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* generate our key */
+ ret = _gnutls_pk_generate_keys(curve->pk, curve->id, &session->key.kshare.ecdh_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* read the public key */
+ ret = _gnutls_ecc_ansi_x962_import(data, data_size,
+ &pub.params[ECC_X],
+ &pub.params[ECC_Y]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ pub.algo = group->pk;
+ pub.curve = curve->id;
+ pub.params_nr = 2;
+
+ /* generate shared */
+ ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdh_params, &pub);
+ gnutls_pk_params_release(&pub);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
+ group->pk == GNUTLS_PK_ECDH_X448) {
+ gnutls_pk_params_st pub;
+
+ gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
+ gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
+
+ curve = _gnutls_ecc_curve_get_params(group->curve);
+
+ if (curve->size != data_size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* generate our key */
+ ret = _gnutls_pk_generate_keys(curve->pk, curve->id, &session->key.kshare.ecdhx_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* read the public key and generate shared */
+ gnutls_pk_params_init(&pub);
+
+ pub.algo = group->pk;
+ pub.curve = curve->id;
+
+ pub.raw_pub.data = (void*)data;
+ pub.raw_pub.size = data_size;
+
+ /* We don't mask the MSB in the final byte as required
+ * by RFC7748. This will be done internally by nettle 3.3 or later.
+ */
+ ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdhx_params, &pub);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_DH) {
+ gnutls_pk_params_st pub;
+
+ /* we need to initialize the group parameters first */
+ gnutls_pk_params_release(&session->key.kshare.dh_params);
+ gnutls_pk_params_init(&session->key.kshare.dh_params);
+
+ if (data_size != group->prime->size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* set group params */
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_G],
+ group->generator->data, group->generator->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_P],
+ group->prime->data, group->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_Q],
+ group->q->data, group->q->size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ session->key.kshare.dh_params.algo = GNUTLS_PK_DH;
+ session->key.kshare.dh_params.qbits = *group->q_bits;
+ session->key.kshare.dh_params.params_nr = 3;
+
+ /* generate our keys */
+ ret = _gnutls_pk_generate_keys(group->pk, 0, &session->key.kshare.dh_params, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* read the public key and generate shared */
+ gnutls_pk_params_init(&pub);
+
+ ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y],
+ data, data_size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ pub.algo = group->pk;
+
+ /* generate shared key */
+ ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key, &session->key.kshare.dh_params, &pub);
+ _gnutls_mpi_release(&pub.params[DH_Y]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = 0;
+ } else {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+
+ _gnutls_debug_log("EXT[%p]: server generated %s shared key\n", session, group->name);
+
+ return ret;
+}
+
+/* Generates shared key and stores it in session->key.key
+ */
+static int
+client_use_key_share(gnutls_session_t session, const gnutls_group_entry_st *group,
+ const uint8_t * data, size_t data_size)
+{
+ const gnutls_ecc_curve_entry_st *curve;
+ int ret;
+
+ if (group->pk == GNUTLS_PK_EC) {
+ gnutls_pk_params_st pub;
+
+ curve = _gnutls_ecc_curve_get_params(group->curve);
+
+ gnutls_pk_params_init(&pub);
+
+ if (session->key.kshare.ecdh_params.algo != group->pk || session->key.kshare.ecdh_params.curve != curve->id)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ if (curve->size*2+1 != data_size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* read the server's public key */
+ ret = _gnutls_ecc_ansi_x962_import(data, data_size,
+ &pub.params[ECC_X],
+ &pub.params[ECC_Y]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ pub.algo = group->pk;
+ pub.curve = curve->id;
+ pub.params_nr = 2;
+
+ /* generate shared key */
+ ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdh_params, &pub);
+ gnutls_pk_params_release(&pub);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
+ group->pk == GNUTLS_PK_ECDH_X448) {
+ gnutls_pk_params_st pub;
+
+ curve = _gnutls_ecc_curve_get_params(group->curve);
+
+ if (session->key.kshare.ecdhx_params.algo != group->pk || session->key.kshare.ecdhx_params.curve != curve->id)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ if (curve->size != data_size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* read the public key and generate shared */
+ gnutls_pk_params_init(&pub);
+
+ pub.algo = group->pk;
+ pub.curve = curve->id;
+
+ pub.raw_pub.data = (void*)data;
+ pub.raw_pub.size = data_size;
+
+ /* We don't mask the MSB in the final byte as required
+ * by RFC7748. This will be done internally by nettle 3.3 or later.
+ */
+ ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdhx_params, &pub);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = 0;
+
+ } else if (group->pk == GNUTLS_PK_DH) {
+ gnutls_pk_params_st pub;
+
+ if (session->key.kshare.dh_params.algo != group->pk || session->key.kshare.dh_params.dh_group != group->id)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ if (data_size != group->prime->size)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* read the public key and generate shared */
+ gnutls_pk_params_init(&pub);
+
+ ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y],
+ data, data_size);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ pub.algo = group->pk;
+
+ /* generate shared key */
+ ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key, &session->key.kshare.dh_params, &pub);
+ _gnutls_mpi_release(&pub.params[DH_Y]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = 0;
+ } else {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+
+ _gnutls_debug_log("EXT[%p]: client generated %s shared key\n", session, group->name);
+
+ return ret;
+}
+
+static int
+key_share_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ int ret;
+ size_t size;
+ unsigned gid;
+ const version_entry_st *ver;
+ const gnutls_group_entry_st *group;
+ unsigned used_share = 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ ver = get_version(session);
+ if (ver == NULL || ver->key_shares == 0)
+ return gnutls_assert_val(0);
+
+ DECR_LEN(data_size, 2);
+ size = _gnutls_read_uint16(data);
+ data += 2;
+
+ if (data_size != size)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ /* if we do PSK without DH ignore that share */
+ if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
+ (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK)) {
+ reset_cand_groups(session);
+ return 0;
+ }
+
+ while(data_size > 0) {
+ DECR_LEN(data_size, 2);
+ gid = _gnutls_read_uint16(data);
+ data += 2;
+
+ DECR_LEN(data_size, 2);
+ size = _gnutls_read_uint16(data);
+ data += 2;
+
+ DECR_LEN(data_size, size);
+
+ /* at this point we have already negotiated a group;
+ * find the group's share. */
+ group = _gnutls_tls_id_to_group(gid);
+
+ if (group != NULL)
+ _gnutls_handshake_log("EXT[%p]: Received key share for %s\n", session, group->name);
+
+ if (group != NULL && group == session->internals.cand_group) {
+ _gnutls_session_group_set(session, group);
+
+ ret = server_use_key_share(session, group, data, size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ used_share = 1;
+ break;
+
+ }
+
+ data += size;
+ continue;
+ }
+
+ /* we utilize GNUTLS_E_NO_COMMON_KEY_SHARE for:
+ * 1. signal for hello-retry-request in the handshake
+ * layer during first client hello parsing (server side - here).
+ * This does not result to error code being
+ * propagated to app layer.
+ * 2. Propagate to application error code that no
+ * common key share was found after an HRR was
+ * received (client side)
+ * 3. Propagate to application error code that no
+ * common key share was found after an HRR was
+ * sent (server side).
+ * In cases (2,3) the error is translated to illegal
+ * parameter alert.
+ */
+ if (used_share == 0) {
+ return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
+ }
+
+ session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
+ } else { /* Client */
+ ver = get_version(session);
+ if (unlikely(ver == NULL || ver->key_shares == 0))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
+ if (unlikely(!(session->internals.hsk_flags & HSK_HRR_RECEIVED)))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ DECR_LEN(data_size, 2);
+ gid = _gnutls_read_uint16(data);
+
+ group = _gnutls_tls_id_to_group(gid);
+ if (group == NULL)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ _gnutls_handshake_log("EXT[%p]: HRR key share with %s\n", session, group->name);
+
+ /* check if we support it */
+ ret = _gnutls_session_supports_group(session, group->id);
+ if (ret < 0) {
+ _gnutls_handshake_log("EXT[%p]: received share for %s which is disabled\n", session, group->name);
+ return gnutls_assert_val(ret);
+ }
+
+ _gnutls_session_group_set(session, group);
+
+ return 0;
+ }
+ /* else */
+
+ DECR_LEN(data_size, 2);
+ gid = _gnutls_read_uint16(data);
+ data += 2;
+
+ DECR_LEN(data_size, 2);
+ size = _gnutls_read_uint16(data);
+ data+=2;
+
+ if (data_size != size)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ group = _gnutls_tls_id_to_group(gid);
+ if (group == NULL)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* check if we support it */
+ ret = _gnutls_session_supports_group(session, group->id);
+ if (ret < 0) {
+ _gnutls_handshake_log("EXT[%p]: received share for %s which is disabled\n", session, group->name);
+ return gnutls_assert_val(ret);
+ }
+
+ _gnutls_session_group_set(session, group);
+ session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
+
+ ret = client_use_key_share(session, group, data, size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ return 0;
+}
+
+static inline bool
+pk_type_is_ecdhx(gnutls_pk_algorithm_t pk)
+{
+ return pk == GNUTLS_PK_ECDH_X25519 || pk == GNUTLS_PK_ECDH_X448;
+}
+
+static inline bool
+pk_type_equal(gnutls_pk_algorithm_t a, gnutls_pk_algorithm_t b)
+{
+ return a == b || (pk_type_is_ecdhx(a) && pk_type_is_ecdhx(b));
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+key_share_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ unsigned i;
+ int ret;
+ unsigned int generated = 0;
+ const gnutls_group_entry_st *group;
+ const version_entry_st *ver;
+
+ /* this extension is only being sent on client side */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ unsigned int length_pos;
+
+ ver = _gnutls_version_max(session);
+ if (unlikely(ver == NULL || ver->key_shares == 0))
+ return 0;
+
+ if (!have_creds_for_tls13(session))
+ return 0;
+
+ length_pos = extdata->length;
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (session->internals.hsk_flags & HSK_HRR_RECEIVED) { /* we know the group */
+ group = get_group(session);
+ if (unlikely(group == NULL))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = client_gen_key_share(session, group, extdata);
+ if (ret == GNUTLS_E_INT_RET_0)
+ return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ } else {
+ gnutls_pk_algorithm_t selected_groups[3];
+ unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */
+
+ if (session->internals.flags & GNUTLS_KEY_SHARE_TOP)
+ max_groups = 1;
+ else if (session->internals.flags & GNUTLS_KEY_SHARE_TOP3)
+ max_groups = 3;
+
+ assert(max_groups <= sizeof(selected_groups)/sizeof(selected_groups[0]));
+
+ /* generate key shares for out top-(max_groups) groups
+ * if they are of different PK type. */
+ for (i = 0; i < session->internals.priorities->groups.size; i++) {
+ unsigned int j;
+
+ group = session->internals.priorities->groups.entry[i];
+
+ for (j = 0; j < generated; j++) {
+ if (pk_type_equal(group->pk, selected_groups[j])) {
+ break;
+ }
+ }
+ if (j < generated) {
+ continue;
+ }
+
+ selected_groups[generated] = group->pk;
+
+ ret = client_gen_key_share(session, group, extdata);
+ if (ret == GNUTLS_E_INT_RET_0)
+ continue; /* no key share for this algorithm */
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ generated++;
+
+ if (generated >= max_groups)
+ break;
+ }
+ }
+
+ /* copy actual length */
+ _gnutls_write_uint16(extdata->length - length_pos - 2,
+ &extdata->data[length_pos]);
+
+ } else { /* server */
+ ver = get_version(session);
+ if (unlikely(ver == NULL || ver->key_shares == 0))
+ return gnutls_assert_val(0);
+
+ if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
+ group = session->internals.cand_group;
+
+ if (group == NULL)
+ return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
+
+ _gnutls_session_group_set(session, group);
+
+ _gnutls_handshake_log("EXT[%p]: requesting retry with group %s\n", session, group->name);
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ } else {
+ /* if we are negotiating PSK without DH, do not send a key share */
+ if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
+ (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK))
+ return gnutls_assert_val(0);
+
+ group = get_group(session);
+ if (unlikely(group == NULL))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = server_gen_key_share(session, group, extdata);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ session->internals.hsk_flags |= HSK_KEY_SHARE_SENT;
+ }
+
+ return 0;
+}
diff --git a/lib/ext/key_share.h b/lib/ext/key_share.h
new file mode 100644
index 0000000..ed9aa16
--- /dev/null
+++ b/lib/ext/key_share.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_KEY_SHARE_H
+#define GNUTLS_LIB_EXT_KEY_SHARE_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_key_share;
+
+#endif /* GNUTLS_LIB_EXT_KEY_SHARE_H */
diff --git a/lib/ext/max_record.c b/lib/ext/max_record.c
new file mode 100644
index 0000000..87302cb
--- /dev/null
+++ b/lib/ext/max_record.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Max Record Size TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/max_record.h>
+
+static int _gnutls_max_record_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_max_record_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+/* Maps record size to numbers according to the
+ * extensions draft.
+ */
+static int _gnutls_mre_num2record(int num);
+static int _gnutls_mre_record2num(uint16_t record_size);
+
+
+const hello_ext_entry_st ext_mod_max_record_size = {
+ .name = "Maximum Record Size",
+ .tls_id = 1,
+ .gid = GNUTLS_EXTENSION_MAX_RECORD_SIZE,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_max_record_recv_params,
+ .send_func = _gnutls_max_record_send_params
+};
+
+/*
+ * In case of a server: if a MAX_RECORD_SIZE extension type is received then it stores
+ * into the session the new value. The server may use gnutls_get_max_record_size(),
+ * in order to access it.
+ *
+ * In case of a client: If a different max record size (than the default) has
+ * been specified then it sends the extension.
+ *
+ */
+
+static int
+_gnutls_max_record_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ ssize_t new_size;
+
+ if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (data_size > 0) {
+ DECR_LEN(data_size, 1);
+
+ new_size = _gnutls_mre_num2record(data[0]);
+
+ if (new_size < 0) {
+ gnutls_assert();
+ return new_size;
+ }
+
+ session->security_parameters.max_record_send_size =
+ new_size;
+ session->security_parameters.max_record_recv_size =
+ new_size;
+ }
+ } else { /* CLIENT SIDE - we must check if the sent record size is the right one
+ */
+ if (data_size > 0) {
+ if (data_size != 1) {
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ new_size = _gnutls_mre_num2record(data[0]);
+
+ if (new_size < 0) {
+ gnutls_assert();
+ return new_size;
+ }
+
+ if (new_size != session->security_parameters.
+ max_user_record_send_size) {
+ gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ } else {
+ session->security_parameters.
+ max_record_send_size = new_size;
+ session->security_parameters.
+ max_record_recv_size = new_size;
+ }
+
+ }
+
+
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_max_record_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ uint8_t p;
+ int ret;
+
+ /* this function sends the client extension data (dnsname) */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ /* if the user limits for sending and receiving are
+ * different, that means the programmer had chosen to
+ * use record_size_limit instead */
+ if (session->security_parameters.max_user_record_send_size !=
+ session->security_parameters.max_user_record_recv_size)
+ return 0;
+
+ if (session->security_parameters.max_user_record_send_size !=
+ DEFAULT_MAX_RECORD_SIZE) {
+ ret = _gnutls_mre_record2num
+ (session->security_parameters.
+ max_user_record_send_size);
+
+ /* it's not an error, as long as we send the
+ * record_size_limit extension with that value */
+ if (ret < 0)
+ return 0;
+
+ p = (uint8_t) ret;
+ ret = _gnutls_buffer_append_data(extdata, &p, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 1;
+ }
+
+ } else { /* server side */
+
+ if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_SENT)
+ return 0;
+
+ if (session->security_parameters.max_record_recv_size !=
+ DEFAULT_MAX_RECORD_SIZE) {
+ ret = _gnutls_mre_record2num
+ (session->security_parameters.
+ max_record_recv_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ p = (uint8_t) ret;
+ ret = _gnutls_buffer_append_data(extdata, &p, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Maps numbers to record sizes according to the
+ * extensions draft.
+ */
+static int _gnutls_mre_num2record(int num)
+{
+ switch (num) {
+ case 1:
+ return 512;
+ case 2:
+ return 1024;
+ case 3:
+ return 2048;
+ case 4:
+ return 4096;
+ default:
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+}
+
+/* Maps record size to numbers according to the
+ * extensions draft.
+ */
+static int _gnutls_mre_record2num(uint16_t record_size)
+{
+ switch (record_size) {
+ case 512:
+ return 1;
+ case 1024:
+ return 2;
+ case 2048:
+ return 3;
+ case 4096:
+ return 4;
+ default:
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+}
+
+/**
+ * gnutls_record_get_max_size:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Get the record size. The maximum record size is negotiated by the
+ * client after the first handshake message.
+ *
+ * Returns: The maximum record packet size in this connection.
+ **/
+size_t gnutls_record_get_max_size(gnutls_session_t session)
+{
+ /* Recv will hold the negotiated max record size
+ * always.
+ */
+ return session->security_parameters.max_record_recv_size;
+}
+
+
+/**
+ * gnutls_record_set_max_size:
+ * @session: is a #gnutls_session_t type.
+ * @size: is the new size
+ *
+ * This function sets the maximum amount of plaintext sent and
+ * received in a record in this connection.
+ *
+ * Prior to 3.6.4, this function was implemented using a TLS extension
+ * called 'max fragment length', which limits the acceptable values to
+ * 512(=2^9), 1024(=2^10), 2048(=2^11) and 4096(=2^12).
+ *
+ * Since 3.6.4, the limit is also negotiated through a new TLS
+ * extension called 'record size limit', which doesn't have the
+ * limitation, as long as the value ranges between 512 and 16384.
+ * Note that while the 'record size limit' extension is preferred, not
+ * all TLS implementations use or even understand the extension.
+ *
+ * Deprecated: if the client can assume that the 'record size limit'
+ * extension is supported by the server, we recommend using
+ * gnutls_record_set_max_recv_size() instead.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ **/
+ssize_t gnutls_record_set_max_size(gnutls_session_t session, size_t size)
+{
+ if (size < MIN_RECORD_SIZE || size > DEFAULT_MAX_RECORD_SIZE)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ if (session->internals.handshake_in_progress)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ session->security_parameters.max_user_record_send_size = size;
+ session->security_parameters.max_user_record_recv_size = size;
+
+ return 0;
+}
+
+/**
+ * gnutls_record_set_max_recv_size:
+ * @session: is a #gnutls_session_t type.
+ * @size: is the new size
+ *
+ * This function sets the maximum amount of plaintext received in a
+ * record in this connection.
+ *
+ * The limit is also negotiated through a TLS extension called 'record
+ * size limit'. Note that while the 'record size limit' extension is
+ * preferred, not all TLS implementations use or even understand the
+ * extension.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since: 3.6.8
+ **/
+ssize_t gnutls_record_set_max_recv_size(gnutls_session_t session, size_t size)
+{
+ if (size <
+ (session->internals.allow_small_records ?
+ MIN_RECORD_SIZE_SMALL : MIN_RECORD_SIZE) ||
+ size > DEFAULT_MAX_RECORD_SIZE)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ if (session->internals.handshake_in_progress)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ session->security_parameters.max_user_record_recv_size = size;
+
+ return 0;
+}
diff --git a/lib/ext/max_record.h b/lib/ext/max_record.h
new file mode 100644
index 0000000..758c8e1
--- /dev/null
+++ b/lib/ext/max_record.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_MAX_RECORD_H
+#define GNUTLS_LIB_EXT_MAX_RECORD_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_max_record_size;
+
+#endif /* GNUTLS_LIB_EXT_MAX_RECORD_H */
diff --git a/lib/ext/post_handshake.c b/lib/ext/post_handshake.c
new file mode 100644
index 0000000..27fe1e7
--- /dev/null
+++ b/lib/ext/post_handshake.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Post-Handshake TLS 1.3 extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/post_handshake.h>
+#include "auth/cert.h"
+
+static int _gnutls_post_handshake_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_post_handshake_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_post_handshake = {
+ .name = "Post Handshake Auth",
+ .tls_id = 49,
+ .gid = GNUTLS_EXTENSION_POST_HANDSHAKE,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .recv_func = _gnutls_post_handshake_recv_params,
+ .send_func = _gnutls_post_handshake_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+static int
+_gnutls_post_handshake_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t _data_size)
+{
+ const version_entry_st *vers;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ vers = get_version(session);
+ if (unlikely(vers == NULL))
+ return 0;
+
+ if ((session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH) &&
+ vers->post_handshake_auth)
+ session->security_parameters.post_handshake_auth = 1;
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_post_handshake_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ gnutls_certificate_credentials_t cred;
+ const version_entry_st *max;
+
+ if (session->security_parameters.entity != GNUTLS_CLIENT ||
+ !(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)) {
+ /* not sent on server side */
+ return 0;
+ }
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) /* no certificate authentication */
+ return gnutls_assert_val(0);
+
+ max = _gnutls_version_max(session);
+ if (unlikely(max == NULL))
+ return gnutls_assert_val(0);
+
+ if (max->post_handshake_auth)
+ return GNUTLS_E_INT_RET_0;
+ else
+ return 0;
+}
diff --git a/lib/ext/post_handshake.h b/lib/ext/post_handshake.h
new file mode 100644
index 0000000..7a1cc7a
--- /dev/null
+++ b/lib/ext/post_handshake.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_POST_HANDSHAKE_H
+#define GNUTLS_LIB_EXT_POST_HANDSHAKE_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_post_handshake;
+
+#endif /* GNUTLS_LIB_EXT_POST_HANDSHAKE_H */
diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c
new file mode 100644
index 0000000..8dff2b4
--- /dev/null
+++ b/lib/ext/pre_shared_key.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (C) 2017-2018 Free Software Foundation, Inc.
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Ander Juaristi, Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "auth/psk.h"
+#include "handshake.h"
+#include "kx.h"
+#include "secrets.h"
+#include "tls13/anti_replay.h"
+#include "tls13/psk_ext_parser.h"
+#include "tls13/finished.h"
+#include "tls13/session_ticket.h"
+#include "auth/psk_passwd.h"
+#include <ext/session_ticket.h>
+#include <ext/pre_shared_key.h>
+#include <assert.h>
+
+static int
+compute_psk_from_ticket(const tls13_ticket_st *ticket, gnutls_datum_t *key)
+{
+ int ret;
+
+ if (unlikely(ticket->prf == NULL || ticket->prf->output_size == 0))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ key->data = gnutls_malloc(ticket->prf->output_size);
+ if (!key->data) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ key->size = ticket->prf->output_size;
+
+ ret = _tls13_expand_secret2(ticket->prf,
+ RESUMPTION_LABEL, sizeof(RESUMPTION_LABEL)-1,
+ ticket->nonce, ticket->nonce_size,
+ ticket->resumption_master_secret,
+ key->size,
+ key->data);
+ if (ret < 0)
+ gnutls_assert();
+
+ return ret;
+}
+
+static int
+compute_binder_key(const mac_entry_st *prf,
+ const uint8_t *key, size_t keylen,
+ bool resuming,
+ void *out)
+{
+ int ret;
+ const char ext_label[] = EXT_BINDER_LABEL;
+ const size_t ext_label_len = sizeof(ext_label) - 1;
+ const char res_label[] = RES_BINDER_LABEL;
+ const size_t res_label_len = sizeof(res_label) - 1;
+ const char *label = resuming ? res_label : ext_label;
+ size_t label_len = resuming ? res_label_len : ext_label_len;
+ uint8_t tmp_key[MAX_HASH_SIZE];
+
+ /* Compute HKDF-Extract(0, psk) */
+ ret = _tls13_init_secret2(prf, key, keylen, tmp_key);
+ if (ret < 0)
+ return ret;
+
+ /* Compute Derive-Secret(secret, label, transcript_hash) */
+ ret = _tls13_derive_secret2(prf, label, label_len,
+ NULL, 0, tmp_key, out);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+compute_psk_binder(gnutls_session_t session,
+ const mac_entry_st *prf, unsigned binders_length,
+ int exts_length, int ext_offset,
+ const gnutls_datum_t *psk, const gnutls_datum_t *client_hello,
+ bool resuming, void *out)
+{
+ int ret;
+ unsigned client_hello_pos, extensions_len_pos;
+ gnutls_buffer_st handshake_buf;
+ uint8_t binder_key[MAX_HASH_SIZE];
+
+ _gnutls_buffer_init(&handshake_buf);
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (session->internals.hsk_flags & HSK_HRR_RECEIVED) {
+ ret = gnutls_buffer_append_data(&handshake_buf,
+ (const void *) session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer.length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ }
+
+ client_hello_pos = handshake_buf.length;
+ ret = gnutls_buffer_append_data(&handshake_buf, client_hello->data,
+ client_hello->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ /* This is a ClientHello message */
+ handshake_buf.data[client_hello_pos] = GNUTLS_HANDSHAKE_CLIENT_HELLO;
+
+ /* At this point we have not yet added the binders to the ClientHello,
+ * but we have to overwrite the size field, pretending as if binders
+ * of the correct length were present.
+ */
+ _gnutls_write_uint24(handshake_buf.length - client_hello_pos + binders_length - 2, &handshake_buf.data[client_hello_pos + 1]);
+ _gnutls_write_uint16(handshake_buf.length - client_hello_pos + binders_length - ext_offset,
+ &handshake_buf.data[client_hello_pos + ext_offset]);
+ extensions_len_pos = handshake_buf.length - client_hello_pos - exts_length - 2;
+ _gnutls_write_uint16(exts_length + binders_length + 2,
+ &handshake_buf.data[client_hello_pos + extensions_len_pos]);
+ } else {
+ if (session->internals.hsk_flags & HSK_HRR_SENT) {
+ if (unlikely(session->internals.handshake_hash_buffer.length <= client_hello->size)) {
+ ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ goto error;
+ }
+
+ ret = gnutls_buffer_append_data(&handshake_buf,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer.length - client_hello->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ }
+
+ if (unlikely(client_hello->size <= binders_length)) {
+ ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ goto error;
+ }
+
+ ret = gnutls_buffer_append_data(&handshake_buf,
+ (const void *) client_hello->data,
+ client_hello->size - binders_length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ }
+
+ ret = compute_binder_key(prf,
+ psk->data, psk->size, resuming,
+ binder_key);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _gnutls13_compute_finished(prf, binder_key,
+ &handshake_buf,
+ out);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = 0;
+error:
+ _gnutls_buffer_clear(&handshake_buf);
+ return ret;
+}
+
+static int
+generate_early_secrets(gnutls_session_t session,
+ const mac_entry_st *prf)
+{
+ int ret;
+
+ ret = _tls13_derive_secret2(prf, EARLY_TRAFFIC_LABEL, sizeof(EARLY_TRAFFIC_LABEL)-1,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer_client_hello_len,
+ session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.e_ckey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_call_keylog_func(session, "CLIENT_EARLY_TRAFFIC_SECRET",
+ session->key.proto.tls13.e_ckey,
+ prf->output_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _tls13_derive_secret2(prf, EARLY_EXPORTER_MASTER_LABEL, sizeof(EARLY_EXPORTER_MASTER_LABEL)-1,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer_client_hello_len,
+ session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.ap_expkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_call_keylog_func(session, "EARLY_EXPORTER_SECRET",
+ session->key.proto.tls13.ap_expkey,
+ prf->output_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+/* Calculate TLS 1.3 Early Secret and the derived secrets from the
+ * selected PSK. */
+int
+_gnutls_generate_early_secrets_for_psk(gnutls_session_t session)
+{
+ const uint8_t *psk;
+ size_t psk_size;
+ const mac_entry_st *prf;
+ int ret;
+
+ psk = session->key.binders[0].psk.data;
+ psk_size = session->key.binders[0].psk.size;
+ prf = session->key.binders[0].prf;
+
+ if (unlikely(psk_size == 0))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _tls13_init_secret2(prf, psk, psk_size,
+ session->key.proto.tls13.temp_secret);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->key.proto.tls13.temp_secret_size = prf->output_size;
+
+ ret = generate_early_secrets(session, session->key.binders[0].prf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+static int
+client_send_params(gnutls_session_t session,
+ gnutls_buffer_t extdata,
+ const gnutls_psk_client_credentials_t cred)
+{
+ int ret, ext_offset = 0;
+ uint8_t binder_value[MAX_HASH_SIZE];
+ size_t spos;
+ gnutls_datum_t username = {NULL, 0};
+ gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0};
+ unsigned client_hello_len;
+ unsigned next_idx;
+ const mac_entry_st *prf_res = NULL;
+ const mac_entry_st *prf_psk = NULL;
+ struct timespec cur_time;
+ uint32_t ticket_age, ob_ticket_age;
+ int free_username = 0;
+ psk_auth_info_t info = NULL;
+ unsigned psk_id_len = 0;
+ unsigned binders_len, binders_pos;
+ tls13_ticket_st *ticket = &session->internals.tls13_ticket;
+
+ if (((session->internals.flags & GNUTLS_NO_TICKETS) ||
+ session->internals.tls13_ticket.ticket.data == NULL) &&
+ (!cred || !_gnutls_have_psk_credentials(cred, session))) {
+
+ return 0;
+ }
+
+ binders_len = 0;
+
+ /* placeholder to be filled later */
+ spos = extdata->length;
+ ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* First, let's see if we have a session ticket to send */
+ if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
+ ticket->ticket.data != NULL) {
+
+ /* We found a session ticket */
+ if (unlikely(ticket->prf == NULL)) {
+ tls13_ticket_deinit(ticket);
+ ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ goto cleanup;
+ }
+
+ prf_res = ticket->prf;
+
+ gnutls_gettime(&cur_time);
+ if (unlikely(_gnutls_timespec_cmp(&cur_time,
+ &ticket->arrival_time) < 0)) {
+ gnutls_assert();
+ tls13_ticket_deinit(ticket);
+ goto ignore_ticket;
+ }
+
+ /* Check whether the ticket is stale */
+ ticket_age = timespec_sub_ms(&cur_time, &ticket->arrival_time);
+ if (ticket_age / 1000 > ticket->lifetime) {
+ tls13_ticket_deinit(ticket);
+ goto ignore_ticket;
+ }
+
+ ret = compute_psk_from_ticket(ticket, &rkey);
+ if (ret < 0) {
+ tls13_ticket_deinit(ticket);
+ goto ignore_ticket;
+ }
+
+ /* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */
+ ob_ticket_age = ticket_age + ticket->age_add;
+
+ if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
+ ticket->ticket.data,
+ ticket->ticket.size)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Now append the obfuscated ticket age */
+ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ psk_id_len += 6 + ticket->ticket.size;
+ binders_len += 1 + _gnutls_mac_get_algo_len(prf_res);
+ }
+
+ ignore_ticket:
+ if (cred && _gnutls_have_psk_credentials(cred, session)) {
+ gnutls_datum_t tkey;
+
+ if (cred->binder_algo == NULL) {
+ gnutls_assert();
+ ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
+ goto cleanup;
+ }
+
+ prf_psk = cred->binder_algo;
+
+ ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (username.size == 0 || username.size > UINT16_MAX) {
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD);
+ goto cleanup;
+ }
+
+ if (!free_username) {
+ /* we need to copy the key */
+ ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ } else {
+ user_key.data = tkey.data;
+ user_key.size = tkey.size;
+ }
+
+ ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
+ assert(info != NULL);
+
+ ret = _gnutls_copy_psk_username(info, username);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+
+ if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
+ username.data,
+ username.size)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Now append the obfuscated ticket age */
+ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ psk_id_len += 6 + username.size;
+ binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk);
+ }
+
+ /* if no tickets or identities to be sent */
+ if (psk_id_len == 0) {
+ /* reset extensions buffer */
+ extdata->length = spos;
+ return 0;
+ }
+
+ _gnutls_write_uint16(psk_id_len, &extdata->data[spos]);
+
+ binders_pos = extdata->length-spos;
+ ext_offset = _gnutls_ext_get_extensions_offset(session);
+
+ /* Compute the binders. extdata->data points to the start
+ * of this client hello. */
+ assert(extdata->length >= sizeof(mbuffer_st));
+ assert(ext_offset >= (ssize_t)sizeof(mbuffer_st));
+ ext_offset -= sizeof(mbuffer_st);
+ client_hello_len = extdata->length-sizeof(mbuffer_st);
+
+ next_idx = 0;
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len);
+ if (ret < 0) {
+ gnutls_assert_val(ret);
+ goto cleanup;
+ }
+
+ if (prf_res && rkey.size > 0) {
+ gnutls_datum_t client_hello;
+
+ client_hello.data = extdata->data+sizeof(mbuffer_st);
+ client_hello.size = client_hello_len;
+
+ ret = compute_psk_binder(session, prf_res,
+ binders_len, binders_pos,
+ ext_offset, &rkey, &client_hello, 1,
+ binder_value);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Associate the selected pre-shared key with the session */
+ gnutls_free(session->key.binders[next_idx].psk.data);
+ session->key.binders[next_idx].psk.data = rkey.data;
+ session->key.binders[next_idx].psk.size = rkey.size;
+ rkey.data = NULL;
+
+ session->key.binders[next_idx].prf = prf_res;
+ session->key.binders[next_idx].resumption = 1;
+ session->key.binders[next_idx].idx = next_idx;
+
+ _gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx);
+
+ next_idx++;
+
+ /* Add the binder */
+ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
+ }
+
+ if (prf_psk && user_key.size > 0 && info) {
+ gnutls_datum_t client_hello;
+
+ client_hello.data = extdata->data+sizeof(mbuffer_st);
+ client_hello.size = client_hello_len;
+
+ ret = compute_psk_binder(session, prf_psk,
+ binders_len, binders_pos,
+ ext_offset, &user_key, &client_hello, 0,
+ binder_value);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Associate the selected pre-shared key with the session */
+ gnutls_free(session->key.binders[next_idx].psk.data);
+ session->key.binders[next_idx].psk.data = user_key.data;
+ session->key.binders[next_idx].psk.size = user_key.size;
+ user_key.data = NULL;
+
+ session->key.binders[next_idx].prf = prf_psk;
+ session->key.binders[next_idx].resumption = 0;
+ session->key.binders[next_idx].idx = next_idx;
+
+ _gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx);
+
+ next_idx++;
+
+ /* Add the binder */
+ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ if (free_username)
+ _gnutls_free_datum(&username);
+
+ _gnutls_free_temp_key_datum(&user_key);
+ _gnutls_free_temp_key_datum(&rkey);
+
+ return ret;
+}
+
+static int
+server_send_params(gnutls_session_t session, gnutls_buffer_t extdata)
+{
+ int ret;
+
+ if (!(session->internals.hsk_flags & HSK_PSK_SELECTED))
+ return 0;
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16,
+ session->key.binders[0].idx);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 2;
+}
+
+static int server_recv_params(gnutls_session_t session,
+ const unsigned char *data, size_t len,
+ const gnutls_psk_server_credentials_t pskcred)
+{
+ int ret;
+ const mac_entry_st *prf;
+ gnutls_datum_t full_client_hello;
+ uint8_t binder_value[MAX_HASH_SIZE];
+ uint16_t psk_index, i;
+ gnutls_datum_t binder_recvd = { NULL, 0 };
+ gnutls_datum_t key = {NULL, 0};
+ psk_ext_parser_st psk_parser;
+ psk_ext_iter_st psk_iter;
+ struct psk_st psk;
+ psk_auth_info_t info;
+ tls13_ticket_st ticket_data;
+ /* These values should be set properly when session ticket is accepted. */
+ uint32_t ticket_age = UINT32_MAX;
+ struct timespec ticket_creation_time = { 0, 0 };
+ bool resuming;
+ bool refuse_early_data = false;
+
+ ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len);
+ if (ret < 0) {
+ /* No PSKs advertised by client */
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ return 0;
+ return gnutls_assert_val(ret);
+ }
+
+ _gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
+ for (psk_index = 0; ; psk_index++) {
+ ret = _gnutls13_psk_ext_iter_next_identity(&psk_iter, &psk);
+ if (ret < 0) {
+ /* We couldn't find any usable PSK */
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ return 0;
+ return gnutls_assert_val(ret);
+ }
+
+ /* This will unpack the session ticket if it is well
+ * formed and has the expected name */
+ if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
+ _gnutls13_unpack_session_ticket(session, &psk.identity, &ticket_data) == 0) {
+ prf = ticket_data.prf;
+
+ session->internals.resumption_requested = 1;
+
+ /* Check whether ticket is stale or not */
+ ticket_age = psk.ob_ticket_age - ticket_data.age_add;
+ if (ticket_age / 1000 > ticket_data.lifetime) {
+ gnutls_assert();
+ tls13_ticket_deinit(&ticket_data);
+ continue;
+ }
+
+ ret = compute_psk_from_ticket(&ticket_data, &key);
+ if (ret < 0) {
+ gnutls_assert();
+ tls13_ticket_deinit(&ticket_data);
+ continue;
+ }
+
+ memcpy(&ticket_creation_time,
+ &ticket_data.creation_time,
+ sizeof(struct timespec));
+
+ tls13_ticket_deinit(&ticket_data);
+
+ resuming = 1;
+ break;
+ } else if (pskcred &&
+ psk.ob_ticket_age == 0 &&
+ psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) {
+ prf = pskcred->binder_algo;
+
+ /* this fails only on configuration errors; as such we always
+ * return its error code in that case */
+ ret = _gnutls_psk_pwd_find_entry(session, (char *) psk.identity.data, psk.identity.size, &key);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ resuming = 0;
+ break;
+ }
+ }
+
+ _gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
+ for (i = 0; i <= psk_index; i++) {
+ ret = _gnutls13_psk_ext_iter_next_binder(&psk_iter, &binder_recvd);
+ if (ret < 0) {
+ gnutls_assert();
+ /* We couldn't extract binder */
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto fail;
+ }
+ }
+
+ /* Get full ClientHello */
+ if (!_gnutls_ext_get_full_client_hello(session, &full_client_hello)) {
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ gnutls_assert();
+ goto fail;
+ }
+
+ /* Compute the binder value for this PSK */
+ ret = compute_psk_binder(session, prf, psk_parser.binders_len+2, 0, 0,
+ &key, &full_client_hello, resuming,
+ binder_value);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size ||
+ gnutls_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto fail;
+ }
+
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)
+ _gnutls_handshake_log("EXT[%p]: selected DHE-PSK mode\n", session);
+ else {
+ reset_cand_groups(session);
+ _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session);
+ }
+
+ /* save the username in psk_auth_info to make it available
+ * using gnutls_psk_server_get_username() */
+ if (!resuming) {
+ assert(psk.identity.size <= MAX_USERNAME_SIZE);
+
+ ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
+ assert(info != NULL);
+
+ ret = _gnutls_copy_psk_username(info, psk.identity);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ _gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index);
+
+ /* We currently only support early data in resuming connection,
+ * due to lack of API function to associate encryption
+ * parameters with external PSK.
+ */
+ refuse_early_data = true;
+ } else {
+ if (session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT) {
+ if (session->internals.anti_replay) {
+ ret = _gnutls_anti_replay_check(session->internals.anti_replay,
+ ticket_age,
+ &ticket_creation_time,
+ &binder_recvd);
+ if (ret < 0) {
+ refuse_early_data = true;
+ _gnutls_handshake_log("EXT[%p]: replay detected; rejecting early data\n",
+ session);
+ }
+ } else {
+ refuse_early_data = true;
+ _gnutls_handshake_log("EXT[%p]: anti-replay is not enabled; rejecting early data\n",
+ session);
+ }
+ }
+
+ session->internals.resumed = true;
+ _gnutls_handshake_log("EXT[%p]: selected resumption PSK identity (%d)\n", session, psk_index);
+ }
+
+ session->internals.hsk_flags |= HSK_PSK_SELECTED;
+
+ if ((session->internals.flags & GNUTLS_ENABLE_EARLY_DATA) &&
+ (session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT) &&
+ !refuse_early_data &&
+ !(session->internals.hsk_flags & HSK_HRR_SENT)) {
+ session->internals.hsk_flags |= HSK_EARLY_DATA_ACCEPTED;
+ _gnutls_handshake_log("EXT[%p]: early data accepted\n",
+ session);
+ }
+
+ /* Reference the selected pre-shared key */
+ session->key.binders[0].psk.data = key.data;
+ session->key.binders[0].psk.size = key.size;
+
+ session->key.binders[0].idx = psk_index;
+ session->key.binders[0].prf = prf;
+ session->key.binders[0].resumption = resuming;
+
+ ret = _gnutls_generate_early_secrets_for_psk(session);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ gnutls_free(key.data);
+ return ret;
+}
+
+/*
+ * Return values for this function:
+ * - 0 : Not applicable.
+ * - >0 : Ok. Return size of extension data.
+ * - GNUTLS_E_INT_RET_0 : Size of extension data is zero.
+ * - <0 : There's been an error.
+ *
+ * In the client, generates the PskIdentity and PskBinderEntry messages.
+ *
+ * PskIdentity identities<7..2^16-1>;
+ * PskBinderEntry binders<33..2^16-1>;
+ *
+ * struct {
+ * opaque identity<1..2^16-1>;
+ * uint32 obfuscated_ticket_age;
+ * } PskIdentity;
+ *
+ * opaque PskBinderEntry<32..255>;
+ *
+ * The server sends the selected identity, which is a zero-based index
+ * of the PSKs offered by the client:
+ *
+ * struct {
+ * uint16 selected_identity;
+ * } PreSharedKeyExtension;
+ */
+static int _gnutls_psk_send_params(gnutls_session_t session,
+ gnutls_buffer_t extdata)
+{
+ gnutls_psk_client_credentials_t cred = NULL;
+ const version_entry_st *vers;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ vers = _gnutls_version_max(session);
+
+ if (!vers || !vers->tls13_sem)
+ return 0;
+
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODES_SENT) {
+ cred = (gnutls_psk_client_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ }
+
+ if ((session->internals.flags & GNUTLS_NO_TICKETS) && !session->internals.priorities->have_psk)
+ return 0;
+
+ return client_send_params(session, extdata, cred);
+ } else {
+ vers = get_version(session);
+
+ if (!vers || !vers->tls13_sem)
+ return 0;
+
+ if ((session->internals.flags & GNUTLS_NO_TICKETS) && !session->internals.priorities->have_psk)
+ return 0;
+
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED)
+ return server_send_params(session, extdata);
+ else
+ return 0;
+ }
+}
+
+static void swap_binders(gnutls_session_t session)
+{
+ struct binder_data_st tmp;
+
+ memcpy(&tmp, &session->key.binders[0], sizeof(struct binder_data_st));
+ memcpy(&session->key.binders[0], &session->key.binders[1], sizeof(struct binder_data_st));
+ memcpy(&session->key.binders[1], &tmp, sizeof(struct binder_data_st));
+}
+
+/*
+ * Return values for this function:
+ * - 0 : Not applicable.
+ * - >0 : Ok. Return size of extension data.
+ * - <0 : There's been an error.
+ */
+static int _gnutls_psk_recv_params(gnutls_session_t session,
+ const unsigned char *data, size_t len)
+{
+ unsigned i;
+ gnutls_psk_server_credentials_t pskcred;
+ const version_entry_st *vers = get_version(session);
+ int ret;
+
+ if (!vers || !vers->tls13_sem)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODES_SENT) {
+ uint16_t selected_identity = _gnutls_read_uint16(data);
+
+ for (i=0;i<sizeof(session->key.binders)/sizeof(session->key.binders[0]);i++) {
+ if (session->key.binders[i].prf != NULL && session->key.binders[i].idx == selected_identity) {
+ if (session->key.binders[i].resumption) {
+ session->internals.resumed = true;
+ _gnutls_handshake_log("EXT[%p]: selected PSK-resumption mode\n", session);
+ } else {
+ _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session);
+ }
+
+ /* different PSK is selected, than the one we calculated early secrets */
+ if (i != 0) {
+ /* ensure that selected binder is set on (our) index zero */
+ swap_binders(session);
+
+ ret = _gnutls_generate_early_secrets_for_psk(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ session->internals.hsk_flags |= HSK_PSK_SELECTED;
+ }
+ }
+
+ return 0;
+ } else {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+ } else {
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED) {
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID) {
+ /* We received a "psk_ke_modes" extension, but with a value we don't support */
+ return 0;
+ }
+
+ pskcred = (gnutls_psk_server_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+
+ /* If there are no PSK credentials, this extension is not applicable,
+ * so we return zero. */
+ if (pskcred == NULL && (session->internals.flags & GNUTLS_NO_TICKETS))
+ return 0;
+
+ return server_recv_params(session, data, len, pskcred);
+ } else {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+ }
+}
+
+const hello_ext_entry_st ext_mod_pre_shared_key = {
+ .name = "Pre Shared Key",
+ .tls_id = PRE_SHARED_KEY_TLS_ID,
+ .gid = GNUTLS_EXTENSION_PRE_SHARED_KEY,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
+ .send_func = _gnutls_psk_send_params,
+ .recv_func = _gnutls_psk_recv_params
+};
diff --git a/lib/ext/pre_shared_key.h b/lib/ext/pre_shared_key.h
new file mode 100644
index 0000000..f1ea62c
--- /dev/null
+++ b/lib/ext/pre_shared_key.h
@@ -0,0 +1,23 @@
+#ifndef GNUTLS_LIB_EXT_PRE_SHARED_KEY_H
+#define GNUTLS_LIB_EXT_PRE_SHARED_KEY_H
+
+#include "auth/psk.h"
+#include <hello_ext.h>
+#include "tls13/session_ticket.h"
+
+#define PRE_SHARED_KEY_TLS_ID 41
+
+extern const hello_ext_entry_st ext_mod_pre_shared_key;
+
+inline static
+unsigned _gnutls_have_psk_credentials(const gnutls_psk_client_credentials_t cred, gnutls_session_t session)
+{
+ if ((cred->get_function || cred->username.data) && session->internals.priorities->have_psk)
+ return 1;
+ else
+ return 0;
+}
+
+int _gnutls_generate_early_secrets_for_psk(gnutls_session_t session);
+
+#endif /* GNUTLS_LIB_EXT_PRE_SHARED_KEY_H */
diff --git a/lib/ext/psk_ke_modes.c b/lib/ext/psk_ke_modes.c
new file mode 100644
index 0000000..cc28536
--- /dev/null
+++ b/lib/ext/psk_ke_modes.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * Author: Ander Juaristi
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "ext/psk_ke_modes.h"
+#include "ext/pre_shared_key.h"
+#include <assert.h>
+
+#define PSK_KE 0
+#define PSK_DHE_KE 1
+
+static int
+psk_ke_modes_send_params(gnutls_session_t session,
+ gnutls_buffer_t extdata)
+{
+ int ret;
+ const version_entry_st *vers;
+ uint8_t data[2];
+ unsigned pos, i;
+ unsigned have_dhpsk = 0;
+ unsigned have_psk = 0;
+
+ /* Server doesn't send psk_key_exchange_modes */
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ return 0;
+
+ /* If session ticket is disabled and no PSK key exchange is
+ * enabled, don't send the extension */
+ if ((session->internals.flags & GNUTLS_NO_TICKETS) &&
+ !session->internals.priorities->have_psk)
+ return 0;
+
+ vers = _gnutls_version_max(session);
+ if (!vers || !vers->tls13_sem)
+ return 0;
+
+ /* We send the list prioritized according to our preferences as a convention
+ * (used throughout the protocol), even if the protocol doesn't mandate that
+ * for this particular message. That way we can keep the TLS 1.2 semantics/
+ * prioritization when negotiating PSK or DHE-PSK. Receiving servers would
+ * very likely respect our prioritization if they parse the message serially. */
+ pos = 0;
+ for (i=0;i<session->internals.priorities->_kx.num_priorities;i++) {
+ if (session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_PSK && !have_psk) {
+ assert(pos <= 1);
+ data[pos++] = PSK_KE;
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ have_psk = 1;
+ } else if ((session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_DHE_PSK ||
+ session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_ECDHE_PSK) && !have_dhpsk) {
+ assert(pos <= 1);
+ data[pos++] = PSK_DHE_KE;
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
+ have_dhpsk = 1;
+ }
+
+ if (have_psk && have_dhpsk)
+ break;
+ }
+
+ /* For session resumption we need to send at least one */
+ if (pos == 0) {
+ if (session->internals.flags & GNUTLS_NO_TICKETS)
+ return 0;
+
+ data[pos++] = PSK_DHE_KE;
+ data[pos++] = PSK_KE;
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
+
+ return 0;
+}
+
+#define MAX_POS INT_MAX
+
+/*
+ * Since we only support ECDHE-authenticated PSKs, the server
+ * just verifies that a "psk_key_exchange_modes" extension was received,
+ * and that it contains the value one.
+ */
+static int
+psk_ke_modes_recv_params(gnutls_session_t session,
+ const unsigned char *data, size_t len)
+{
+ uint8_t ke_modes_len;
+ const version_entry_st *vers = get_version(session);
+ gnutls_psk_server_credentials_t cred;
+ int dhpsk_pos = MAX_POS;
+ int psk_pos = MAX_POS;
+ int cli_psk_pos = MAX_POS;
+ int cli_dhpsk_pos = MAX_POS;
+ unsigned i;
+
+ /* Client doesn't receive psk_key_exchange_modes */
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+
+ /* we set hsk_flags to HSK_PSK_KE_MODE_INVALID on failure to ensure that
+ * when we parse the pre-shared key extension we detect PSK_KE_MODES as
+ * received. */
+ if (!vers || !vers->tls13_sem) {
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
+ return gnutls_assert_val(0);
+ }
+
+ cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ if (cred == NULL && (session->internals.flags & GNUTLS_NO_TICKETS)) {
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
+ return gnutls_assert_val(0);
+ }
+
+ DECR_LEN(len, 1);
+ ke_modes_len = *(data++);
+
+ for (i=0;i<session->internals.priorities->_kx.num_priorities;i++) {
+ if (session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_PSK && psk_pos == MAX_POS) {
+ psk_pos = i;
+ } else if ((session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_DHE_PSK ||
+ session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_ECDHE_PSK) &&
+ dhpsk_pos == MAX_POS) {
+ dhpsk_pos = i;
+ }
+
+ if (dhpsk_pos != MAX_POS && psk_pos != MAX_POS)
+ break;
+ }
+
+ if (psk_pos == MAX_POS && dhpsk_pos == MAX_POS) {
+ if (!(session->internals.flags & GNUTLS_NO_TICKETS))
+ dhpsk_pos = 0;
+ else if (session->internals.priorities->groups.size == 0)
+ return gnutls_assert_val(0);
+ }
+
+ for (i=0;i<ke_modes_len;i++) {
+ DECR_LEN(len, 1);
+ if (data[i] == PSK_DHE_KE)
+ cli_dhpsk_pos = i;
+ else if (data[i] == PSK_KE)
+ cli_psk_pos = i;
+
+ _gnutls_handshake_log("EXT[%p]: PSK KE mode %.2x received\n",
+ session, (unsigned)data[i]);
+ if (cli_psk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS)
+ break;
+ }
+
+ if (session->internals.priorities->server_precedence) {
+ if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && (dhpsk_pos < psk_pos || cli_psk_pos == MAX_POS))
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
+ else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && (psk_pos < dhpsk_pos || cli_dhpsk_pos == MAX_POS))
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ } else {
+ if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && (cli_dhpsk_pos < cli_psk_pos || psk_pos == MAX_POS))
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
+ else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && (cli_psk_pos < cli_dhpsk_pos || dhpsk_pos == MAX_POS))
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ }
+
+ if ((session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) ||
+ (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)) {
+
+ return 0;
+ } else {
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
+ return gnutls_assert_val(0);
+ }
+}
+
+const hello_ext_entry_st ext_mod_psk_ke_modes = {
+ .name = "PSK Key Exchange Modes",
+ .tls_id = 45,
+ .gid = GNUTLS_EXTENSION_PSK_KE_MODES,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
+ .send_func = psk_ke_modes_send_params,
+ .recv_func = psk_ke_modes_recv_params
+};
diff --git a/lib/ext/psk_ke_modes.h b/lib/ext/psk_ke_modes.h
new file mode 100644
index 0000000..56876a9
--- /dev/null
+++ b/lib/ext/psk_ke_modes.h
@@ -0,0 +1,8 @@
+#ifndef GNUTLS_LIB_EXT_PSK_KE_MODES_H
+#define GNUTLS_LIB_EXT_PSK_KE_MODES_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_psk_ke_modes;
+
+#endif /* GNUTLS_LIB_EXT_PSK_KE_MODES_H */
diff --git a/lib/ext/record_size_limit.c b/lib/ext/record_size_limit.c
new file mode 100644
index 0000000..9398b18
--- /dev/null
+++ b/lib/ext/record_size_limit.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Record Size Limit TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/record_size_limit.h>
+
+static int _gnutls_record_size_limit_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_record_size_limit_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_record_size_limit = {
+ .name = "Record Size Limit",
+ .tls_id = 28,
+ .gid = GNUTLS_EXTENSION_RECORD_SIZE_LIMIT,
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_record_size_limit_recv_params,
+ .send_func = _gnutls_record_size_limit_send_params
+};
+
+static int
+_gnutls_record_size_limit_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ ssize_t new_size;
+ const version_entry_st *vers;
+
+ DECR_LEN(data_size, 2);
+ if (data_size != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ new_size = _gnutls_read_uint16(data);
+
+ /* protocol error */
+ if (new_size < 64)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_RECEIVED;
+
+ /* we do not want to accept sizes outside of our supported range */
+ if (new_size <
+ (session->internals.allow_small_records ?
+ MIN_RECORD_SIZE_SMALL : MIN_RECORD_SIZE)) {
+ /* for server, reject it by omitting the extension in the reply */
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ _gnutls_handshake_log("EXT[%p]: client requested too small record_size_limit %u; ignoring\n",
+ session, (unsigned)new_size);
+ return gnutls_assert_val(0);
+ } else {
+ _gnutls_handshake_log("EXT[%p]: server requested too small record_size_limit %u; closing the connection\n",
+ session, (unsigned)new_size);
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+ }
+
+ session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_NEGOTIATED;
+
+ /* client uses the reception of this extension as an
+ * indication of the request was accepted by the server */
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ session->security_parameters.max_record_recv_size =
+ session->security_parameters.max_user_record_recv_size;
+
+ _gnutls_handshake_log("EXT[%p]: record_size_limit %u negotiated\n",
+ session, (unsigned)new_size);
+
+ /* subtract 1 octet for content type */
+ vers = get_version(session);
+ if (unlikely(vers == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ session->security_parameters.max_record_send_size =
+ MIN(new_size - vers->tls13_sem,
+ session->security_parameters.max_user_record_send_size);
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_record_size_limit_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ int ret;
+ uint16_t send_size;
+
+ assert(session->security_parameters.max_user_record_recv_size >= 64 &&
+ session->security_parameters.max_user_record_recv_size <=
+ DEFAULT_MAX_RECORD_SIZE);
+
+ send_size = session->security_parameters.max_user_record_recv_size;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ const version_entry_st *vers;
+
+ /* if we had received the extension and rejected, don't send it */
+ if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_RECEIVED &&
+ !(session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED))
+ return gnutls_assert_val(0);
+
+ /* add 1 octet for content type */
+ vers = get_version(session);
+ if (unlikely(vers == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ session->security_parameters.max_record_recv_size =
+ send_size;
+
+ send_size += vers->tls13_sem;
+ } else {
+ const version_entry_st *vers;
+
+ /* add 1 octet for content type */
+ vers = _gnutls_version_max(session);
+ if (unlikely(vers == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ send_size += vers->tls13_sem;
+ }
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, send_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_SENT;
+
+ return 2;
+}
diff --git a/lib/ext/record_size_limit.h b/lib/ext/record_size_limit.h
new file mode 100644
index 0000000..da7cade
--- /dev/null
+++ b/lib/ext/record_size_limit.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_RECORD_SIZE_LIMIT_H
+#define GNUTLS_LIB_EXT_RECORD_SIZE_LIMIT_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_record_size_limit;
+
+#endif /* GNUTLS_LIB_EXT_RECORD_SIZE_LIMIT_H */
diff --git a/lib/ext/safe_renegotiation.c b/lib/ext/safe_renegotiation.c
new file mode 100644
index 0000000..f76895d
--- /dev/null
+++ b/lib/ext/safe_renegotiation.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ *
+ * Author: Steve Dispensa (<dispensa@phonefactor.com>)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include <ext/safe_renegotiation.h>
+#include "errors.h"
+
+
+static int _gnutls_sr_recv_params(gnutls_session_t state,
+ const uint8_t * data, size_t data_size);
+static int _gnutls_sr_send_params(gnutls_session_t state,
+ gnutls_buffer_st *);
+static void _gnutls_sr_deinit_data(gnutls_ext_priv_data_t priv);
+
+const hello_ext_entry_st ext_mod_sr = {
+ .name = "Safe Renegotiation",
+ .tls_id = 65281,
+ .gid = GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .recv_func = _gnutls_sr_recv_params,
+ .send_func = _gnutls_sr_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = _gnutls_sr_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+int
+_gnutls_ext_sr_finished(gnutls_session_t session, void *vdata,
+ size_t vdata_size, int dir)
+{
+ int ret;
+ sr_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->internals.priorities->sr == SR_DISABLED ||
+ session->internals.priorities->no_extensions) {
+ return 0;
+ }
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0) {
+ gnutls_assert();
+ /* if a client didn't advertise safe renegotiation, we treat
+ * it as disabled. */
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ return 0;
+ return ret;
+ }
+ priv = epriv;
+
+ /* Save data for safe renegotiation.
+ */
+ if (vdata_size > MAX_VERIFY_DATA_SIZE) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ if ((session->security_parameters.entity == GNUTLS_CLIENT
+ && dir == 0)
+ || (session->security_parameters.entity == GNUTLS_SERVER
+ && dir == 1)) {
+ priv->client_verify_data_len = vdata_size;
+ memcpy(priv->client_verify_data, vdata, vdata_size);
+ } else {
+ priv->server_verify_data_len = vdata_size;
+ memcpy(priv->server_verify_data, vdata, vdata_size);
+ }
+
+ return 0;
+}
+
+int _gnutls_ext_sr_verify(gnutls_session_t session)
+{
+ int ret;
+ sr_ext_st *priv = NULL;
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->internals.priorities->sr == SR_DISABLED) {
+ gnutls_assert();
+ return 0;
+ }
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret >= 0)
+ priv = epriv;
+
+ /* Safe renegotiation */
+
+ if (priv && priv->safe_renegotiation_received) {
+ if ((priv->ri_extension_data_len <
+ priv->client_verify_data_len)
+ ||
+ (memcmp
+ (priv->ri_extension_data, priv->client_verify_data,
+ priv->client_verify_data_len))) {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Safe renegotiation failed [1]\n",
+ session);
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if ((priv->ri_extension_data_len !=
+ priv->client_verify_data_len +
+ priv->server_verify_data_len)
+ || memcmp(priv->ri_extension_data +
+ priv->client_verify_data_len,
+ priv->server_verify_data,
+ priv->server_verify_data_len) != 0) {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Safe renegotiation failed [2]\n",
+ session);
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+ } else { /* Make sure there are 0 extra bytes */
+
+ if (priv->ri_extension_data_len !=
+ priv->client_verify_data_len) {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Safe renegotiation failed [3]\n",
+ session);
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+ }
+
+ _gnutls_handshake_log
+ ("HSK[%p]: Safe renegotiation succeeded\n", session);
+ } else { /* safe renegotiation not received... */
+
+ if (priv && priv->connection_using_safe_renegotiation) {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Peer previously asked for safe renegotiation\n",
+ session);
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+
+ /* Clients can't tell if it's an initial negotiation */
+ if (session->internals.initial_negotiation_completed) {
+ if (session->internals.priorities->sr < SR_PARTIAL) {
+ _gnutls_handshake_log
+ ("HSK[%p]: Allowing unsafe (re)negotiation\n",
+ session);
+ } else {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Denying unsafe (re)negotiation\n",
+ session);
+ return
+ GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED;
+ }
+ } else {
+ if (session->internals.priorities->sr < SR_SAFE) {
+ _gnutls_handshake_log
+ ("HSK[%p]: Allowing unsafe initial negotiation\n",
+ session);
+ } else {
+ gnutls_assert();
+ _gnutls_handshake_log
+ ("HSK[%p]: Denying unsafe initial negotiation\n",
+ session);
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* if a server received the special ciphersuite.
+ */
+int _gnutls_ext_sr_recv_cs(gnutls_session_t session)
+{
+ int ret, set = 0;
+ sr_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0) {
+ set = 1;
+ }
+
+ if (set != 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+ } else
+ priv = epriv;
+
+ priv->safe_renegotiation_received = 1;
+ priv->connection_using_safe_renegotiation = 1;
+ _gnutls_hello_ext_save_sr(session);
+
+ if (set != 0)
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ epriv);
+
+ return 0;
+}
+
+int _gnutls_ext_sr_send_cs(gnutls_session_t session)
+{
+ int ret, set = 0;
+ sr_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0) {
+ set = 1;
+ }
+
+ if (set != 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ epriv);
+ }
+
+ return 0;
+}
+
+static int
+_gnutls_sr_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ unsigned int len;
+ sr_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ int set = 0, ret;
+
+ if (data_size == 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ len = data[0];
+ DECR_LEN(data_size,
+ len + 1 /* count the first byte and payload */ );
+
+ if (session->internals.priorities->sr == SR_DISABLED) {
+ gnutls_assert();
+ return 0;
+ }
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0
+ && session->security_parameters.entity == GNUTLS_SERVER) {
+ set = 1;
+ } else if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (set != 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ epriv);
+ } else {
+ priv = epriv;
+ }
+
+ /* It is not legal to receive this extension on a renegotiation and
+ * not receive it on the initial negotiation.
+ */
+ if (session->internals.initial_negotiation_completed != 0 &&
+ priv->connection_using_safe_renegotiation == 0) {
+ gnutls_assert();
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+
+ if (len > sizeof(priv->ri_extension_data)) {
+ gnutls_assert();
+ return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+ }
+
+ if (len > 0)
+ memcpy(priv->ri_extension_data, &data[1], len);
+ priv->ri_extension_data_len = len;
+
+ /* "safe renegotiation received" means on *this* handshake; "connection using
+ * safe renegotiation" means that the initial hello received on the connection
+ * indicated safe renegotiation.
+ */
+ priv->safe_renegotiation_received = 1;
+ priv->connection_using_safe_renegotiation = 1;
+
+ return 0;
+}
+
+static int
+_gnutls_sr_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ /* The format of this extension is a one-byte length of verify data followed
+ * by the verify data itself. Note that the length byte does not include
+ * itself; IOW, empty verify data is represented as a length of 0. That means
+ * the minimum extension is one byte: 0x00.
+ */
+ sr_ext_st *priv;
+ int ret, set = 0, len;
+ gnutls_ext_priv_data_t epriv;
+ size_t init_length = extdata->length;
+
+ if (session->internals.priorities->sr == SR_DISABLED) {
+ gnutls_assert();
+ return 0;
+ }
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0) {
+ set = 1;
+ }
+
+ if (set != 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ epriv);
+ } else
+ priv = epriv;
+
+ /* Always offer the extension if we're a client */
+ if (priv->connection_using_safe_renegotiation ||
+ session->security_parameters.entity == GNUTLS_CLIENT) {
+ len = priv->client_verify_data_len;
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ len += priv->server_verify_data_len;
+
+ ret = _gnutls_buffer_append_prefix(extdata, 8, len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_buffer_append_data(extdata,
+ priv->client_verify_data,
+ priv->
+ client_verify_data_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ ret =
+ _gnutls_buffer_append_data(extdata,
+ priv->
+ server_verify_data,
+ priv->
+ server_verify_data_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ } else
+ return 0;
+
+ return extdata->length - init_length;
+}
+
+static void _gnutls_sr_deinit_data(gnutls_ext_priv_data_t priv)
+{
+ gnutls_free(priv);
+}
+
+/**
+ * gnutls_safe_renegotiation_status:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Can be used to check whether safe renegotiation is being used
+ * in the current session.
+ *
+ * Returns: 0 when safe renegotiation is not used and non (0) when
+ * safe renegotiation is used.
+ *
+ * Since: 2.10.0
+ **/
+unsigned gnutls_safe_renegotiation_status(gnutls_session_t session)
+{
+ int ret;
+ sr_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+ &epriv);
+ if (ret < 0) {
+ gnutls_assert();
+ return 0;
+ }
+ priv = epriv;
+
+ return priv->connection_using_safe_renegotiation;
+}
diff --git a/lib/ext/safe_renegotiation.h b/lib/ext/safe_renegotiation.h
new file mode 100644
index 0000000..bc2024a
--- /dev/null
+++ b/lib/ext/safe_renegotiation.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ *
+ * Author: Steve Dispensa (<dispensa@phonefactor.com>)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SAFE_RENEGOTIATION_H
+#define GNUTLS_LIB_EXT_SAFE_RENEGOTIATION_H
+
+#include <hello_ext.h>
+
+typedef struct {
+ uint8_t client_verify_data[MAX_VERIFY_DATA_SIZE];
+ size_t client_verify_data_len;
+ uint8_t server_verify_data[MAX_VERIFY_DATA_SIZE];
+ size_t server_verify_data_len;
+ uint8_t ri_extension_data[MAX_VERIFY_DATA_SIZE * 2]; /* max signal is 72 bytes in s->c sslv3 */
+ size_t ri_extension_data_len;
+
+ unsigned int safe_renegotiation_received:1;
+ unsigned int initial_negotiation_completed:1;
+ unsigned int connection_using_safe_renegotiation:1;
+} sr_ext_st;
+
+extern const hello_ext_entry_st ext_mod_sr;
+
+int _gnutls_ext_sr_finished(gnutls_session_t session, void *vdata,
+ size_t vdata_size, int dir);
+int _gnutls_ext_sr_recv_cs(gnutls_session_t session);
+int _gnutls_ext_sr_verify(gnutls_session_t session);
+int _gnutls_ext_sr_send_cs(gnutls_session_t);
+
+#endif /* GNUTLS_LIB_EXT_SAFE_RENEGOTIATION_H */
diff --git a/lib/ext/server_cert_type.c b/lib/ext/server_cert_type.c
new file mode 100644
index 0000000..6db2a1f
--- /dev/null
+++ b/lib/ext/server_cert_type.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2016 - 2018 ARPA2 project
+ *
+ * Author: Tom Vrancken (dev@tomvrancken.nl)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ * This file is part of the server_certificate_type extension as
+ * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
+ *
+ * The server_certificate_type extension in the client hello indicates
+ * the types of certificates the client is able to process when provided
+ * by the server in a subsequent certificate payload.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls/gnutls.h>
+#include "ext/cert_types.h"
+#include "ext/server_cert_type.h"
+#include "hello_ext.h"
+#include "hello_ext_lib.h"
+#include "errors.h"
+#include "state.h"
+#include "datum.h"
+
+
+static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
+ const uint8_t* data,
+ size_t data_size);
+static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
+ gnutls_buffer_st* data);
+
+
+const hello_ext_entry_st ext_mod_server_cert_type = {
+ .name = "Server Certificate Type",
+ .tls_id = 20,
+ .gid = GNUTLS_EXTENSION_SERVER_CERT_TYPE,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS |
+ GNUTLS_EXT_FLAG_DTLS |
+ GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
+ GNUTLS_EXT_FLAG_EE,
+ .recv_func = _gnutls_server_cert_type_recv_params,
+ .send_func = _gnutls_server_cert_type_send_params,
+ .pack_func = _gnutls_hello_ext_default_pack,
+ .unpack_func = _gnutls_hello_ext_default_unpack,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 1
+};
+
+
+static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
+ const uint8_t* data,
+ size_t data_size)
+{
+ int ret;
+ gnutls_certificate_type_t cert_type;
+ size_t i;
+ bool found = false;
+ const uint8_t* pdata = data;
+
+ /* Only activate this extension if we have cert credentials set
+ * and alternative cert types are allowed */
+ if (!are_alternative_cert_types_allowed(session) ||
+ (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
+ return 0;
+
+ if (!IS_SERVER(session)) { // client mode
+ gnutls_datum_t sent_cert_types; // Holds the previously sent cert types
+
+ /* Compare packet length with expected packet length. For the
+ * client this is a single byte. */
+ if (data_size != 1) {
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+
+ /* The server picked one of the offered cert types if he supports
+ * at least one of them. If both parties play by the rules then we
+ * may only receive a cert type that we offered, i.e. one that we
+ * support. Because the world isn't as beautiful as it may seem,
+ * we're going to check it nevertheless. */
+ cert_type = IANA2cert_type(pdata[0]);
+
+ _gnutls_handshake_log("EXT[%p]: Received a %s server certificate type confirmation from the server.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ // Check validity of cert type
+ if (cert_type == GNUTLS_CRT_UNKNOWN) {
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
+ }
+
+ /* Get the cert types that we sent to the server (they were stored
+ * in IANA representation.
+ */
+ ret = _gnutls_hello_ext_get_datum(session,
+ GNUTLS_EXTENSION_SERVER_CERT_TYPE,
+ &sent_cert_types);
+ if (ret < 0) {
+ /* This should not happen and indicate a memory corruption!
+ * Assertion are always on in production code so execution
+ * will halt here. */
+ assert(false);
+ }
+
+ // Check whether what we got back is actually offered by us
+ for (i = 0; i < sent_cert_types.size; i++) {
+ if (IANA2cert_type(sent_cert_types.data[i]) == cert_type)
+ found = true;
+ }
+
+ if (found) {
+ // Everything OK, now set the server certificate type
+ _gnutls_session_server_cert_type_set(session, cert_type);
+ ret = GNUTLS_E_SUCCESS;
+ } else {
+ // No valid cert type found
+ ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+
+ return ret;
+
+ } else { // server mode
+ gnutls_datum_t cert_types; // Holds the received cert types
+
+ // Compare packet length with expected packet length.
+ DECR_LEN(data_size, 1);
+ if (data[0] != data_size) {
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+ pdata += 1;
+
+ // Assign the contents of our data buffer to a gnutls_datum_t
+ cert_types.data = (uint8_t*)pdata; // Need casting to get rid of 'discards const qualifier' warning
+ cert_types.size = data_size;
+
+ // Store the server certificate types in our session
+ _gnutls_hello_ext_set_datum(session,
+ GNUTLS_EXTENSION_SERVER_CERT_TYPE,
+ &cert_types);
+
+ /* We receive a list of supported certificate types that the client
+ * is able to process when offered by the server via a subsequent
+ * Certificate message. This list is sorted by order of preference.
+ * We now check in this order of preference whether we support any
+ * of these certificate types.
+ */
+ for (i = 0; i < cert_types.size; i++) {
+ // Convert to internal representation
+ cert_type = IANA2cert_type(cert_types.data[i]);
+
+ // If we have an invalid cert id then continue to the next
+ if (cert_type == GNUTLS_CRT_UNKNOWN)
+ continue;
+
+ _gnutls_handshake_log("EXT[%p]: Checking compatibility of a %s server certificate type that was received from the client.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ // Check for support of this cert type
+ if (_gnutls_session_is_cert_type_supported(session, cert_type, true, GNUTLS_CTYPE_SERVER) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ // We found a matching ctype, we pick this one
+ if (found) {
+ _gnutls_session_server_cert_type_set(session, cert_type);
+ ret = GNUTLS_E_SUCCESS;
+ } else {
+ /* If no supported certificate type can be found we terminate
+ * with a fatal alert of type "unsupported_certificate"
+ * (according to specification rfc7250).
+ */
+ ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+
+ return ret;
+ }
+}
+
+static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
+ gnutls_buffer_st* data)
+{
+ int ret;
+ uint8_t cert_type_IANA; // Holds an IANA cert type ID
+ gnutls_certificate_type_t cert_type;
+
+ /* Only activate this extension if we have cert credentials set
+ * and alternative cert types are allowed */
+ if (!are_alternative_cert_types_allowed(session) ||
+ (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
+ return 0;
+
+ if (!IS_SERVER(session)) { // Client mode
+ uint8_t cert_types[GNUTLS_CRT_MAX]; // The list with supported (IANA) cert types. Inv: 0 <= cert type Id < 256
+ size_t i, num_cert_types = 0;
+ priority_st* cert_priorities;
+ gnutls_datum_t tmp_cert_types; // For type conversion
+
+ // For brevity
+ cert_priorities = &session->internals.priorities->server_ctype;
+
+ /* Retrieve server certificate type priorities if any. If no
+ * priorities are set then the default server certificate type
+ * initialization values apply. This default is currently set to
+ * X.509 in which case we don't enable this extension.
+ */
+ if (cert_priorities->num_priorities > 0) { // Priorities are explicitly set
+ /* If the certificate priority is explicitly set to only
+ * X.509 (default) then, according to spec we don't send
+ * this extension. We check this here to avoid further work in
+ * this routine. We also check it below after pruning supported
+ * types.
+ */
+ if (cert_priorities->num_priorities == 1 &&
+ cert_priorities->priorities[0] == DEFAULT_CERT_TYPE) {
+ _gnutls_handshake_log
+ ("EXT[%p]: Server certificate type was set to default cert type (%s). "
+ "We therefore do not send this extension.\n",
+ session,
+ gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
+
+ // Explicitly set but default ctype, so don't send anything
+ return 0;
+ }
+
+ /* We are only allowed to send certificate types that we support.
+ * Therefore we check this here and prune our original list.
+ * This check might seem redundant now because we don't check for
+ * credentials (they are not needed for a client) and only check the
+ * priorities over which we already iterate. In the future,
+ * additional checks might be necessary and they can be easily
+ * added in the ..type_supported() routine without modifying the
+ * structure of the code here.
+ */
+ for (i = 0; i < cert_priorities->num_priorities; i++) {
+
+ cert_type = cert_priorities->priorities[i];
+
+ if (_gnutls_session_is_cert_type_supported(session, cert_type,
+ false, GNUTLS_CTYPE_SERVER) == 0) {
+ /* Check whether we are allowed to store another cert type
+ * in our buffer. In other words, prevent a possible buffer
+ * overflow. This situation can occur when a user sets
+ * duplicate cert types in the priority strings. */
+ if (num_cert_types >= GNUTLS_CRT_MAX)
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+ // Convert to IANA representation
+ ret = cert_type2IANA(cert_type);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ cert_type_IANA = ret; // For readability
+
+ // Add this cert type to our list with supported types
+ cert_types[num_cert_types] = cert_type_IANA;
+ num_cert_types++;
+
+ _gnutls_handshake_log
+ ("EXT[%p]: Server certificate type %s (%d) was queued.\n",
+ session,
+ gnutls_certificate_type_get_name(cert_type),
+ cert_type_IANA);
+ }
+ }
+
+ /* Check whether there are any supported certificate types left
+ * after the previous pruning step. If not, we do not send this
+ * extension. Also, if the only supported type is the default type
+ * we do not send this extension (according to RFC7250).
+ */
+ if (num_cert_types == 0) { // For now, this should not occur since we only check priorities while pruning.
+ _gnutls_handshake_log
+ ("EXT[%p]: Server certificate types were set but none of them is supported. "
+ "We do not send this extension.\n",
+ session);
+
+ return 0;
+ } else if (num_cert_types == 1 &&
+ IANA2cert_type(cert_types[0]) == DEFAULT_CERT_TYPE) {
+ _gnutls_handshake_log
+ ("EXT[%p]: The only supported server certificate type is (%s) which is the default. "
+ "We therefore do not send this extension.\n",
+ session,
+ gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
+
+ return 0;
+ }
+
+ /* We have data to send and store a copy internally. We convert
+ * our list with supported cert types to a datum_t in order to
+ * be able to make the ..._set_datum call.
+ */
+ tmp_cert_types.data = cert_types;
+ tmp_cert_types.size = num_cert_types;
+
+ _gnutls_hello_ext_set_datum(session,
+ GNUTLS_EXTENSION_SERVER_CERT_TYPE,
+ &tmp_cert_types);
+
+ /* Serialize the certificate types into a sequence of octets
+ * uint8: length of sequence of cert types (1 octet)
+ * uint8: cert types (0 <= #octets <= 255)
+ */
+ ret = _gnutls_buffer_append_data_prefix(data, 8,
+ cert_types,
+ num_cert_types);
+
+ // Check for errors and cleanup in case of error
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ } else {
+ // Number of bytes we are sending
+ return num_cert_types + 1;
+ }
+ }
+ } else { // Server mode
+ // Retrieve negotiated server certificate type and send it
+ cert_type = get_certificate_type(session, GNUTLS_CTYPE_SERVER);
+ ret = cert_type2IANA(cert_type);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ cert_type_IANA = ret; // For readability
+
+ _gnutls_handshake_log("EXT[%p]: Confirming to use a %s server certificate type.\n",
+ session, gnutls_certificate_type_get_name(cert_type));
+
+ ret = gnutls_buffer_append_data(data, &cert_type_IANA, 1);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 1; // sent one byte
+ }
+
+ // In all other cases don't enable this extension
+ return 0;
+}
+
+
+/** Extension interface **/
+
+/* The interface is defined in state.c:
+ * Public:
+ * - gnutls_certificate_type_get2
+ *
+ * Private:
+ * - _gnutls_session_server_cert_type_set
+ */
diff --git a/lib/ext/server_cert_type.h b/lib/ext/server_cert_type.h
new file mode 100644
index 0000000..3c15b0b
--- /dev/null
+++ b/lib/ext/server_cert_type.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 - 2018 ARPA2 project
+ *
+ * Author: Tom Vrancken (dev@tomvrancken.nl)
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ * This file is part of the server_certificate_type extension as
+ * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
+ *
+ * The server_certificate_type extension in the client hello indicates
+ * the certificate types the client is able to process from the server
+ * in order to authenticate the server.
+ */
+
+#ifndef GNUTLS_LIB_EXT_SERVER_CERT_TYPE_H
+#define GNUTLS_LIB_EXT_SERVER_CERT_TYPE_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_server_cert_type;
+
+#endif /* GNUTLS_LIB_EXT_SERVER_CERT_TYPE_H */
diff --git a/lib/ext/server_name.c b/lib/ext/server_name.c
new file mode 100644
index 0000000..d52c8d0
--- /dev/null
+++ b/lib/ext/server_name.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2002-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "auth.h"
+#include "errors.h"
+#include "num.h"
+#include "str.h"
+#include <ext/server_name.h>
+#include "hello_ext_lib.h"
+
+static int _gnutls_server_name_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_server_name_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+int
+_gnutls_server_name_set_raw(gnutls_session_t session,
+ gnutls_server_name_type_t type,
+ const void *name, size_t name_length);
+
+const hello_ext_entry_st ext_mod_server_name = {
+ .name = "Server Name Indication",
+ .tls_id = 0,
+ .gid = GNUTLS_EXTENSION_SERVER_NAME,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ .server_parse_point = GNUTLS_EXT_MANDATORY,
+ .recv_func = _gnutls_server_name_recv_params,
+ .send_func = _gnutls_server_name_send_params,
+ .pack_func = _gnutls_hello_ext_default_pack,
+ .unpack_func = _gnutls_hello_ext_default_unpack,
+ .deinit_func = _gnutls_hello_ext_default_deinit,
+ .cannot_be_overriden = 1
+};
+
+/*
+ * In case of a server: if a NAME_DNS extension type is received then
+ * it stores into the session the value of NAME_DNS. The server may
+ * use gnutls_ext_get_server_name(), in order to access it.
+ *
+ * In case of a client: If a proper NAME_DNS extension type is found
+ * in the session then it sends the extension to the peer.
+ *
+ */
+static int
+_gnutls_server_name_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ const unsigned char *p;
+ uint16_t len, type;
+ gnutls_datum_t name;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ len = _gnutls_read_uint16(data);
+ if (len == 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (len != data_size) {
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ p = data + 2;
+
+ while (data_size > 0) {
+ DECR_LEN(data_size, 1);
+ type = *p;
+ p++;
+
+ DECR_LEN(data_size, 2);
+ len = _gnutls_read_uint16(p);
+ p += 2;
+
+ if (len == 0) {
+ _gnutls_handshake_log
+ ("HSK[%p]: Received server name size of zero\n",
+ session);
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+
+ DECR_LEN(data_size, len);
+
+ if (type == 0) { /* NAME_DNS */
+ if (!_gnutls_dnsname_is_valid((char*)p, len)) {
+ _gnutls_handshake_log
+ ("HSK[%p]: Server name is not acceptable: '%.*s'\n",
+ session, (int) len, p);
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_DISALLOWED_NAME);
+ }
+
+ name.data = (void*)p;
+ name.size = len;
+
+ _gnutls_hello_ext_unset_priv(session, GNUTLS_EXTENSION_SERVER_NAME);
+ return _gnutls_hello_ext_set_datum(session,
+ GNUTLS_EXTENSION_SERVER_NAME,
+ &name);
+ }
+ p += len;
+
+ }
+
+
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_server_name_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ int total_size = 0, ret;
+ gnutls_datum_t name;
+
+ ret =
+ _gnutls_hello_ext_get_datum(session, GNUTLS_EXTENSION_SERVER_NAME,
+ &name);
+ if (ret < 0)
+ return 0;
+
+ /* this function sends the client extension data (dnsname)
+ */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (name.size == 0)
+ return 0;
+
+ /* uint8_t + uint16_t + size
+ */
+ total_size = 2 + 1 + 2 + name.size;
+
+ /* UINT16: write total size of all names
+ */
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ total_size - 2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* UINT8: type of this extension
+ * UINT16: size of the first name
+ * LEN: the actual server name.
+ */
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 8, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_debug_log("HSK[%p]: sent server name: '%.*s'\n", session, name.size, name.data);
+
+ ret =
+ _gnutls_buffer_append_data_prefix
+ (extdata, 16,
+ name.data, name.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ } else {
+ return 0;
+ }
+
+ return total_size;
+}
+
+/**
+ * gnutls_server_name_get:
+ * @session: is a #gnutls_session_t type.
+ * @data: will hold the data
+ * @data_length: will hold the data length. Must hold the maximum size of data.
+ * @type: will hold the server name indicator type
+ * @indx: is the index of the server_name
+ *
+ * This function will allow you to get the name indication (if any), a
+ * client has sent. The name indication may be any of the enumeration
+ * gnutls_server_name_type_t.
+ *
+ * If @type is GNUTLS_NAME_DNS, then this function is to be used by
+ * servers that support virtual hosting, and the data will be a null
+ * terminated IDNA ACE string (prior to GnuTLS 3.4.0 it was a UTF-8 string).
+ *
+ * If @data has not enough size to hold the server name
+ * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will
+ * hold the required size.
+ *
+ * @indx is used to retrieve more than one server names (if sent by
+ * the client). The first server name has an index of 0, the second 1
+ * and so on. If no name with the given index exists
+ * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, on UTF-8
+ * decoding error %GNUTLS_E_IDNA_ERROR is returned, otherwise a negative
+ * error code is returned.
+ **/
+int
+gnutls_server_name_get(gnutls_session_t session, void *data,
+ size_t * data_length,
+ unsigned int *type, unsigned int indx)
+{
+ char *_data = data;
+ gnutls_datum_t name;
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (indx != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+
+ ret =
+ _gnutls_hello_ext_get_datum(session, GNUTLS_EXTENSION_SERVER_NAME, &name);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (name.size == 0) {
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ *type = GNUTLS_NAME_DNS;
+
+ if (*data_length > name.size) { /* greater since we need one extra byte for the null */
+ *data_length = name.size;
+ memcpy(data, name.data, *data_length);
+
+ /* null terminate */
+ _data[(*data_length)] = 0;
+
+ } else {
+ *data_length = name.size + 1;
+ ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+/* This does not do any conversion not perform any check */
+int
+_gnutls_server_name_set_raw(gnutls_session_t session,
+ gnutls_server_name_type_t type,
+ const void *name, size_t name_length)
+{
+ int ret;
+ gnutls_datum_t dname;
+
+ if (name_length >= MAX_SERVER_NAME_SIZE) {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ _gnutls_hello_ext_unset_priv(session, GNUTLS_EXTENSION_SERVER_NAME);
+
+ dname.data = (void*)name;
+ dname.size = name_length;
+
+ ret = _gnutls_hello_ext_set_datum(session, GNUTLS_EXTENSION_SERVER_NAME, &dname);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+/**
+ * gnutls_server_name_set:
+ * @session: is a #gnutls_session_t type.
+ * @type: specifies the indicator type
+ * @name: is a string that contains the server name.
+ * @name_length: holds the length of name excluding the terminating null byte
+ *
+ * This function is to be used by clients that want to inform (via a
+ * TLS extension mechanism) the server of the name they connected to.
+ * This should be used by clients that connect to servers that do
+ * virtual hosting.
+ *
+ * The value of @name depends on the @type type. In case of
+ * %GNUTLS_NAME_DNS, a UTF-8 null-terminated domain name string,
+ * without the trailing dot, is expected.
+ *
+ * IPv4 or IPv6 addresses are not permitted to be set by this function.
+ * If the function is called with a name of @name_length zero it will clear
+ * all server names set.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ **/
+int
+gnutls_server_name_set(gnutls_session_t session,
+ gnutls_server_name_type_t type,
+ const void *name, size_t name_length)
+{
+ int ret;
+ gnutls_datum_t idn_name = {NULL,0};
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (name_length == 0) { /* unset extension */
+ _gnutls_hello_ext_unset_priv(session, GNUTLS_EXTENSION_SERVER_NAME);
+ return 0;
+ }
+
+ ret = gnutls_idna_map(name, name_length, &idn_name, 0);
+ if (ret < 0) {
+ _gnutls_debug_log("unable to convert name %s to IDNA2008 format\n", (char*)name);
+ return ret;
+ }
+
+ name = idn_name.data;
+ name_length = idn_name.size;
+
+ ret = _gnutls_server_name_set_raw(session, type, name, name_length);
+ gnutls_free(idn_name.data);
+
+ return ret;
+}
+
+unsigned _gnutls_server_name_matches_resumed(gnutls_session_t session)
+{
+ gnutls_datum_t name1, name2;
+ int ret;
+
+ ret =
+ _gnutls_hello_ext_get_datum(session,
+ GNUTLS_EXTENSION_SERVER_NAME,
+ &name1);
+ if (ret < 0) { /* no server name in this session */
+ name1.data = NULL;
+ name1.size = 0;
+ }
+
+ ret =
+ _gnutls_hello_ext_get_resumed_datum(session,
+ GNUTLS_EXTENSION_SERVER_NAME,
+ &name2);
+ if (ret < 0) { /* no server name in this session */
+ name2.data = NULL;
+ name2.size = 0;
+ }
+
+ if (name1.data == NULL || name2.data == NULL) {
+ if (name1.data == name2.data)
+ return 1;
+ else
+ return 0;
+ }
+
+ if (name1.size != name2.size)
+ return 0;
+
+ if (memcmp(name1.data, name2.data, name1.size) != 0)
+ return 0;
+
+ return 1;
+}
diff --git a/lib/ext/server_name.h b/lib/ext/server_name.h
new file mode 100644
index 0000000..b5cdd0e
--- /dev/null
+++ b/lib/ext/server_name.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SERVER_NAME_H
+#define GNUTLS_LIB_EXT_SERVER_NAME_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_server_name;
+
+unsigned _gnutls_server_name_matches_resumed(gnutls_session_t);
+
+#endif /* GNUTLS_LIB_EXT_SERVER_NAME_H */
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c
new file mode 100644
index 0000000..87d9069
--- /dev/null
+++ b/lib/ext/session_ticket.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2009-2018 Free Software Foundation, Inc.
+ *
+ * Author: Daiki Ueno, Ander Juaristi
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file implements the TLS session ticket extension.
+ *
+ * Note that the extension is only used in TLS 1.2. For TLS 1.3, session
+ * tickets are sent as part of pre_shared_key extension (see pre_shared_key.c).
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include <fips.h>
+#include <datum.h>
+#include <algorithms.h>
+#include <handshake.h>
+#include <num.h>
+#include <constate.h>
+#include <session_pack.h>
+#include <random.h>
+#include <ext/session_ticket.h>
+#include <mbuffers.h>
+#include <hello_ext.h>
+#include <constate.h>
+#include <dtls.h>
+#include "stek.h"
+#include "db.h"
+
+static int session_ticket_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int session_ticket_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+static int session_ticket_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv);
+static int session_ticket_pack(gnutls_ext_priv_data_t _priv,
+ gnutls_buffer_st * ps);
+static void session_ticket_deinit_data(gnutls_ext_priv_data_t priv);
+
+const hello_ext_entry_st ext_mod_session_ticket = {
+ .name = "Session Ticket",
+ .tls_id = 35,
+ .gid = GNUTLS_EXTENSION_SESSION_TICKET,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ /* This extension must be parsed on session resumption as well; see
+ * https://gitlab.com/gnutls/gnutls/issues/841 */
+ .client_parse_point = GNUTLS_EXT_MANDATORY,
+ /* on server side we want this parsed after normal handshake resumption
+ * actions are complete */
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .recv_func = session_ticket_recv_params,
+ .send_func = session_ticket_send_params,
+ .pack_func = session_ticket_pack,
+ .unpack_func = session_ticket_unpack,
+ .deinit_func = session_ticket_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+typedef struct {
+ uint8_t *session_ticket;
+ int session_ticket_len;
+} session_ticket_ext_st;
+
+static void
+deinit_ticket(struct ticket_st *ticket)
+{
+ free(ticket->encrypted_state);
+}
+
+static int
+unpack_ticket(const gnutls_datum_t *ticket_data, struct ticket_st *ticket)
+{
+ const uint8_t * data = ticket_data->data;
+ size_t data_size = ticket_data->size;
+ const uint8_t *encrypted_state;
+
+ /* Format:
+ * Key name
+ * IV
+ * data length
+ * encrypted data
+ * MAC
+ */
+ DECR_LEN(data_size, TICKET_KEY_NAME_SIZE);
+ memcpy(ticket->key_name, data, TICKET_KEY_NAME_SIZE);
+ data += TICKET_KEY_NAME_SIZE;
+
+ DECR_LEN(data_size, TICKET_IV_SIZE);
+ memcpy(ticket->IV, data, TICKET_IV_SIZE);
+ data += TICKET_IV_SIZE;
+
+ DECR_LEN(data_size, 2);
+ ticket->encrypted_state_len = _gnutls_read_uint16(data);
+ data += 2;
+
+ encrypted_state = data;
+
+ DECR_LEN(data_size, ticket->encrypted_state_len);
+ data += ticket->encrypted_state_len;
+
+ DECR_LEN(data_size, TICKET_MAC_SIZE);
+ memcpy(ticket->mac, data, TICKET_MAC_SIZE);
+
+ ticket->encrypted_state =
+ gnutls_malloc(ticket->encrypted_state_len);
+ if (!ticket->encrypted_state) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ memcpy(ticket->encrypted_state, encrypted_state,
+ ticket->encrypted_state_len);
+
+ return 0;
+}
+
+static void
+pack_ticket(const struct ticket_st *ticket, gnutls_datum_t *ticket_data)
+{
+ uint8_t *p;
+
+ p = ticket_data->data;
+
+ memcpy(p, ticket->key_name, TICKET_KEY_NAME_SIZE);
+ p += TICKET_KEY_NAME_SIZE;
+
+ memcpy(p, ticket->IV, TICKET_IV_SIZE);
+ p += TICKET_IV_SIZE;
+
+ _gnutls_write_uint16(ticket->encrypted_state_len, p);
+ p += 2;
+
+ /* We use memmove instead of memcpy here because
+ * ticket->encrypted_state is allocated from
+ * ticket_data->data, and thus both memory areas may overlap.
+ */
+ memmove(p, ticket->encrypted_state, ticket->encrypted_state_len);
+ p += ticket->encrypted_state_len;
+
+ memcpy(p, ticket->mac, TICKET_MAC_SIZE);
+}
+
+static
+int digest_ticket(const gnutls_datum_t * key, struct ticket_st *ticket,
+ uint8_t * digest)
+{
+ mac_hd_st digest_hd;
+ uint16_t length16;
+ int ret;
+
+ ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO),
+ key->data, key->size);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ _gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE);
+ _gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE);
+ length16 = _gnutls_conv_uint16(ticket->encrypted_state_len);
+ _gnutls_mac(&digest_hd, &length16, 2);
+ _gnutls_mac(&digest_hd, ticket->encrypted_state,
+ ticket->encrypted_state_len);
+ _gnutls_mac_deinit(&digest_hd, digest);
+
+ return 0;
+}
+
+int
+_gnutls_decrypt_session_ticket(gnutls_session_t session,
+ const gnutls_datum_t *ticket_data,
+ gnutls_datum_t *state)
+{
+ cipher_hd_st cipher_hd;
+ gnutls_datum_t IV;
+ gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key;
+ uint8_t cmac[TICKET_MAC_SIZE];
+ struct ticket_st ticket;
+ int ret;
+
+ /* Retrieve ticket decryption keys */
+ if (_gnutls_get_session_ticket_decryption_key(session,
+ ticket_data,
+ &stek_key_name,
+ &stek_mac_key,
+ &stek_cipher_key) < 0)
+ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+
+ ret = unpack_ticket(ticket_data, &ticket);
+ if (ret < 0)
+ return ret;
+
+ /* If the key name of the ticket does not match the one that is currently active,
+ issue a new ticket. */
+ if (memcmp
+ (ticket.key_name, stek_key_name.data,
+ stek_key_name.size)) {
+ ret = GNUTLS_E_DECRYPTION_FAILED;
+ goto cleanup;
+ }
+
+ /* Check the integrity of ticket */
+ ret = digest_ticket(&stek_mac_key, &ticket, cmac);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) {
+ ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+ goto cleanup;
+ }
+
+ if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) {
+ ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+ goto cleanup;
+ }
+
+ /* Decrypt encrypted_state */
+ IV.data = ticket.IV;
+ IV.size = TICKET_IV_SIZE;
+ ret =
+ _gnutls_cipher_init(&cipher_hd,
+ cipher_to_entry(TICKET_CIPHER),
+ &stek_cipher_key, &IV, 0);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ gnutls_assert();
+ goto cleanup;
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+
+ ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state,
+ ticket.encrypted_state_len);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup2;
+ }
+
+ state->data = ticket.encrypted_state;
+ state->size = ticket.encrypted_state_len;
+
+ ticket.encrypted_state = NULL;
+
+ ret = 0;
+
+cleanup2:
+ _gnutls_cipher_deinit(&cipher_hd);
+
+cleanup:
+ deinit_ticket(&ticket);
+
+ return ret;
+
+}
+
+int
+_gnutls_encrypt_session_ticket(gnutls_session_t session,
+ const gnutls_datum_t *state,
+ gnutls_datum_t *ticket_data)
+{
+ cipher_hd_st cipher_hd;
+ gnutls_datum_t IV;
+ gnutls_datum_t encrypted_state;
+ gnutls_datum_t result = { NULL, 0 };
+ uint8_t iv[TICKET_IV_SIZE];
+ gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name;
+ struct ticket_st ticket;
+ int ret;
+
+ encrypted_state.size = ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) * TICKET_BLOCK_SIZE;
+ result.size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 +
+ encrypted_state.size + TICKET_MAC_SIZE;
+ result.data = gnutls_calloc(1, result.size);
+ if (!result.data) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ encrypted_state.data = result.data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2;
+ memcpy(encrypted_state.data, state->data, state->size);
+
+ /* Retrieve ticket encryption keys */
+ if (_gnutls_get_session_ticket_encryption_key(session,
+ &stek_key_name,
+ &stek_mac_key,
+ &stek_cipher_key) < 0) {
+ ret = GNUTLS_E_ENCRYPTION_FAILED;
+ goto cleanup;
+ }
+
+ /* Encrypt state */
+ IV.data = iv;
+ IV.size = TICKET_IV_SIZE;
+
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret =
+ _gnutls_cipher_init(&cipher_hd,
+ cipher_to_entry(TICKET_CIPHER),
+ &stek_cipher_key, &IV, 1);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ gnutls_assert();
+ goto cleanup;
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+
+ ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
+ encrypted_state.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup2;
+ }
+
+
+ /* Fill the ticket structure to compute MAC. */
+ memcpy(ticket.key_name, stek_key_name.data, stek_key_name.size);
+ memcpy(ticket.IV, IV.data, IV.size);
+ ticket.encrypted_state_len = encrypted_state.size;
+ ticket.encrypted_state = encrypted_state.data;
+
+ ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup2;
+ }
+
+ pack_ticket(&ticket, &result);
+ ticket_data->data = result.data;
+ ticket_data->size = result.size;
+ result.data = NULL;
+
+cleanup2:
+ _gnutls_cipher_deinit(&cipher_hd);
+
+cleanup:
+ _gnutls_free_datum(&result);
+
+ return ret;
+}
+
+static int
+unpack_session(gnutls_session_t session, const gnutls_datum_t *state)
+{
+ int ret;
+
+ if (unlikely(!state))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ ret = _gnutls_session_unpack(session, state);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_check_resumed_params(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.resumed = true;
+ return 0;
+}
+
+static int
+session_ticket_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ gnutls_datum_t ticket_data;
+ gnutls_datum_t state;
+ int ret;
+
+ if (session->internals.flags & (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12))
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ /* The client requested a new session ticket. */
+ if (data_size == 0) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+
+ ticket_data.data = (void *)data;
+ ticket_data.size = data_size;
+ if ((ret = _gnutls_decrypt_session_ticket(session, &ticket_data, &state)) == 0) {
+ ret = unpack_session(session, &state);
+
+ _gnutls_free_datum(&state);
+ }
+
+ if (ret < 0) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+ } else { /* Client */
+
+ if (data_size == 0) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* returns a positive number if we send the extension data, (0) if we
+ do not want to send it, and a negative number on failure.
+ */
+static int
+session_ticket_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ session_ticket_ext_st *priv = NULL;
+ gnutls_ext_priv_data_t epriv;
+ int ret;
+
+ if (session->internals.flags & (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12))
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (session->internals.session_ticket_renew) {
+ return GNUTLS_E_INT_RET_0;
+ }
+ } else {
+ ret =
+ _gnutls_hello_ext_get_resumed_priv(session,
+ GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret >= 0)
+ priv = epriv;
+
+ /* no previous data. Just advertise it */
+ if (ret < 0)
+ return GNUTLS_E_INT_RET_0;
+
+ /* previous data had session tickets disabled. Don't advertise. Ignore. */
+ if (session->internals.flags & GNUTLS_NO_TICKETS)
+ return 0;
+
+ if (priv->session_ticket_len > 0) {
+ ret =
+ _gnutls_buffer_append_data(extdata,
+ priv->
+ session_ticket,
+ priv->
+ session_ticket_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return priv->session_ticket_len;
+ }
+ }
+ return 0;
+}
+
+
+static void session_ticket_deinit_data(gnutls_ext_priv_data_t epriv)
+{
+ session_ticket_ext_st *priv = epriv;
+
+ gnutls_free(priv->session_ticket);
+ gnutls_free(priv);
+}
+
+static int
+session_ticket_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
+{
+ session_ticket_ext_st *priv = epriv;
+ int ret;
+
+ BUFFER_APPEND_PFX4(ps, priv->session_ticket,
+ priv->session_ticket_len);
+
+ return 0;
+}
+
+static int
+session_ticket_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
+{
+ session_ticket_ext_st *priv = NULL;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+ gnutls_datum_t ticket;
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ BUFFER_POP_DATUM(ps, &ticket);
+ priv->session_ticket = ticket.data;
+ priv->session_ticket_len = ticket.size;
+
+ epriv = priv;
+ *_priv = epriv;
+
+ return 0;
+
+ error:
+ gnutls_free(priv);
+ return ret;
+}
+
+
+
+/**
+ * gnutls_session_ticket_key_generate:
+ * @key: is a pointer to a #gnutls_datum_t which will contain a newly
+ * created key.
+ *
+ * Generate a random key to encrypt security parameters within
+ * SessionTicket.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int gnutls_session_ticket_key_generate(gnutls_datum_t * key)
+{
+ if (_gnutls_fips_mode_enabled()) {
+ int ret;
+ /* in FIPS140-2 mode gnutls_key_generate imposes
+ * some limits on allowed key size, thus it is not
+ * used. These limits do not affect this function as
+ * it does not generate a "key" but rather key material
+ * that includes nonces and other stuff. */
+ key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
+ if (key->data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ key->size = TICKET_MASTER_KEY_SIZE;
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
+ if (ret < 0) {
+ gnutls_free(key->data);
+ return ret;
+ }
+ return 0;
+ } else {
+ return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
+ }
+}
+
+/**
+ * gnutls_session_ticket_enable_client:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Request that the client should attempt session resumption using
+ * SessionTicket. This call is typically unnecessary as session
+ * tickets are enabled by default.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int gnutls_session_ticket_enable_client(gnutls_session_t session)
+{
+ if (!session) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ session->internals.flags &= ~GNUTLS_NO_TICKETS;
+
+ return 0;
+}
+
+/**
+ * gnutls_session_ticket_enable_server:
+ * @session: is a #gnutls_session_t type.
+ * @key: key to encrypt session parameters.
+ *
+ * Request that the server should attempt session resumption using
+ * session tickets, i.e., by delegating storage to the client.
+ * @key must be initialized using gnutls_session_ticket_key_generate().
+ * To avoid leaking that key, use gnutls_memset() prior to
+ * releasing it.
+ *
+ * The default ticket expiration time can be overridden using
+ * gnutls_db_set_cache_expiration().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int
+gnutls_session_ticket_enable_server(gnutls_session_t session,
+ const gnutls_datum_t * key)
+{
+ int ret;
+
+ if (!session || !key || key->size != TICKET_MASTER_KEY_SIZE || !key->data) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = _gnutls_initialize_session_ticket_key_rotation(session, key);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.flags &= ~GNUTLS_NO_TICKETS;
+
+ return 0;
+}
+
+/*
+ * Return zero if session tickets haven't been enabled.
+ */
+int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
+{
+ mbuffer_st *bufel = NULL;
+ uint8_t *data = NULL, *p;
+ int data_size = 0;
+ int ret;
+ gnutls_datum_t state = { NULL, 0 };
+ uint16_t epoch_saved = session->security_parameters.epoch_write;
+ gnutls_datum_t ticket_data;
+
+ if (again == 0) {
+ if (session->internals.flags & (GNUTLS_NO_TICKETS |
+ GNUTLS_NO_TICKETS_TLS12)) {
+ return 0;
+ }
+ if (!session->key.stek_initialized) {
+ return 0;
+ }
+ if (!session->internals.session_ticket_renew) {
+ return 0;
+ }
+
+ _gnutls_handshake_log
+ ("HSK[%p]: sending session ticket\n", session);
+
+ /* XXX: Temporarily set write algorithms to be used.
+ _gnutls_write_connection_state_init() does this job, but it also
+ triggers encryption, while NewSessionTicket should not be
+ encrypted in the record layer. */
+ ret =
+ _gnutls_epoch_set_keys(session,
+ session->security_parameters.
+ epoch_next, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* Under TLS1.2 with session tickets, the session ID is used for different
+ * purposes than the TLS1.0 session ID. Ensure that there is an internally
+ * set value which the server will see on the original and resumed sessions */
+ if (!session->internals.resumed) {
+ ret = _gnutls_generate_session_id(session->security_parameters.
+ session_id,
+ &session->security_parameters.
+ session_id_size);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ session->security_parameters.epoch_write =
+ session->security_parameters.epoch_next;
+
+ /* Pack security parameters. */
+ ret = _gnutls_session_pack(session, &state);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* Generate an encrypted ticket */
+ ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data);
+ session->security_parameters.epoch_write = epoch_saved;
+ _gnutls_free_datum(&state);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ bufel =
+ _gnutls_handshake_alloc(session,
+ 4 + 2 + ticket_data.size);
+ if (!bufel) {
+ gnutls_assert();
+ _gnutls_free_datum(&ticket_data);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ data = _mbuffer_get_udata_ptr(bufel);
+ p = data;
+
+ _gnutls_write_uint32(session->internals.expire_time, p);
+ p += 4;
+
+ _gnutls_write_uint16(ticket_data.size, p);
+ p += 2;
+
+ memcpy(p, ticket_data.data, ticket_data.size);
+ p += ticket_data.size;
+
+ _gnutls_free_datum(&ticket_data);
+
+ data_size = p - data;
+
+ session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
+ }
+ return _gnutls_send_handshake(session, data_size ? bufel : NULL,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
+}
+
+/*
+ * Return zero if session tickets haven't been enabled.
+ */
+int _gnutls_recv_new_session_ticket(gnutls_session_t session)
+{
+ uint8_t *p;
+ int data_size;
+ gnutls_buffer_st buf;
+ uint16_t ticket_len;
+ int ret;
+ session_ticket_ext_st *priv = NULL;
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->internals.flags & (GNUTLS_NO_TICKETS |
+ GNUTLS_NO_TICKETS_TLS12))
+ return 0;
+ if (!session->internals.session_ticket_renew)
+ return 0;
+
+ /* This is the last flight and peer cannot be sure
+ * we have received it unless we notify him. So we
+ * wait for a message and retransmit if needed. */
+ if (IS_DTLS(session) && !_dtls_is_async(session)) {
+ unsigned have;
+ mbuffer_st *bufel = NULL;
+
+ have = gnutls_record_check_pending(session) +
+ record_check_unprocessed(session);
+
+ if (have != 0) {
+ bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL);
+ }
+
+ if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
+ ret = _dtls_wait_and_retransmit(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ }
+
+ ret = _gnutls_recv_handshake(session,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
+ 0, &buf);
+ if (ret < 0)
+ return gnutls_assert_val_fatal(ret);
+
+ p = buf.data;
+ data_size = buf.length;
+
+ DECR_LENGTH_COM(data_size, 4, ret =
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ goto error);
+ /* skip over lifetime hint */
+ p += 4;
+
+ DECR_LENGTH_COM(data_size, 2, ret =
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ goto error);
+ ticket_len = _gnutls_read_uint16(p);
+ p += 2;
+
+ DECR_LENGTH_COM(data_size, ticket_len, ret =
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ goto error);
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (!priv) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+ if (ticket_len > 0) {
+ priv->session_ticket =
+ gnutls_realloc_fast(priv->session_ticket, ticket_len);
+ if (!priv->session_ticket) {
+ gnutls_free(priv);
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+ memcpy(priv->session_ticket, p, ticket_len);
+ }
+ priv->session_ticket_len = ticket_len;
+ epriv = priv;
+
+ /* Discard the current session ID. (RFC5077 3.4) */
+ ret =
+ _gnutls_generate_session_id(session->security_parameters.
+ session_id,
+ &session->security_parameters.
+ session_id_size);
+ if (ret < 0) {
+ gnutls_assert();
+ session_ticket_deinit_data(epriv);
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto error;
+ }
+ ret = 0;
+
+ _gnutls_handshake_log
+ ("HSK[%p]: received session ticket\n", session);
+ session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SESSION_TICKET,
+ epriv);
+
+ error:
+ _gnutls_buffer_clear(&buf);
+
+ return ret;
+}
diff --git a/lib/ext/session_ticket.h b/lib/ext/session_ticket.h
new file mode 100644
index 0000000..da804ec
--- /dev/null
+++ b/lib/ext/session_ticket.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SESSION_TICKET_H
+#define GNUTLS_LIB_EXT_SESSION_TICKET_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_session_ticket;
+
+int _gnutls_send_new_session_ticket(gnutls_session_t session, int again);
+int _gnutls_recv_new_session_ticket(gnutls_session_t session);
+
+int _gnutls_encrypt_session_ticket(gnutls_session_t session,
+ const gnutls_datum_t *state,
+ gnutls_datum_t *ticket_data);
+int _gnutls_decrypt_session_ticket(gnutls_session_t session,
+ const gnutls_datum_t *ticket_data,
+ gnutls_datum_t *state);
+
+#endif /* GNUTLS_LIB_EXT_SESSION_TICKET_H */
diff --git a/lib/ext/signature.c b/lib/ext/signature.c
new file mode 100644
index 0000000..bb350f5
--- /dev/null
+++ b/lib/ext/signature.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Signature Algorithms TLS extension.
+ * This extension is currently gnutls specific.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <gnutls/gnutls.h>
+#include <ext/signature.h>
+#include <state.h>
+#include <num.h>
+#include <algorithms.h>
+#include <abstract_int.h>
+
+/*
+ * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness.
+ * Patch the extension for them.
+ */
+#ifdef ENABLE_GOST
+#define GOST_SIG_FIXUP_SCHANNEL
+#endif
+
+static int _gnutls_signature_algorithm_recv_params(gnutls_session_t
+ session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_signature_algorithm_send_params(gnutls_session_t
+ session,
+ gnutls_buffer_st * extdata);
+static void signature_algorithms_deinit_data(gnutls_ext_priv_data_t priv);
+static int signature_algorithms_pack(gnutls_ext_priv_data_t epriv,
+ gnutls_buffer_st * ps);
+static int signature_algorithms_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv);
+
+const hello_ext_entry_st ext_mod_sig = {
+ .name = "Signature Algorithms",
+ .tls_id = 13,
+ .gid = GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .recv_func = _gnutls_signature_algorithm_recv_params,
+ .send_func = _gnutls_signature_algorithm_send_params,
+ .pack_func = signature_algorithms_pack,
+ .unpack_func = signature_algorithms_unpack,
+ .deinit_func = signature_algorithms_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+typedef struct {
+ /* TLS 1.2 signature algorithms */
+ gnutls_sign_algorithm_t sign_algorithms[MAX_ALGOS];
+ uint16_t sign_algorithms_size;
+} sig_ext_st;
+
+/* generates a SignatureAndHashAlgorithm structure with length as prefix
+ * by using the setup priorities.
+ */
+int
+_gnutls_sign_algorithm_write_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ uint8_t *p;
+ unsigned int len, i;
+ const sign_algorithm_st *aid, *prev = NULL;
+ uint8_t buffer[MAX_ALGOS*2];
+
+ p = buffer;
+ len = 0;
+
+ /* This generates a list of TLS signature algorithms. It has
+ * limited duplicate detection, and does not add twice the same
+ * AID */
+
+ for (i=0;i<session->internals.priorities->sigalg.size;i++) {
+ aid = &session->internals.priorities->sigalg.entry[i]->aid;
+
+ if (HAVE_UNKNOWN_SIGAID(aid))
+ continue;
+
+ if (prev && prev->id[0] == aid->id[0] && prev->id[1] == aid->id[1])
+ continue;
+
+ /* Ignore non-GOST sign types for CertReq */
+ if (session->security_parameters.cs &&
+ _gnutls_kx_is_vko_gost(session->security_parameters.cs->kx_algorithm) &&
+ !_sign_is_gost(session->internals.priorities->sigalg.entry[i]))
+ continue;
+
+ _gnutls_handshake_log
+ ("EXT[%p]: sent signature algo (%d.%d) %s\n", session,
+ (int)aid->id[0], (int)aid->id[1],
+ session->internals.priorities->sigalg.entry[i]->name);
+
+ len += 2;
+ if (unlikely(len >= sizeof(buffer))) {
+ len -= 2;
+ break;
+ }
+
+ *p = aid->id[0];
+ p++;
+ *p = aid->id[1];
+ p++;
+ prev = aid;
+ }
+
+ return _gnutls_buffer_append_data_prefix(extdata, 16, buffer, len);
+}
+
+
+/* Parses the Signature Algorithm structure and stores data into
+ * session->security_parameters.extensions.
+ */
+int
+_gnutls_sign_algorithm_parse_data(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ unsigned int sig, i;
+ sig_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ const version_entry_st *ver = get_version(session);
+
+ if (data_size == 0 || data_size % 2 != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (ver == NULL) { /* assume TLS 1.2 semantics */
+ ver = version_to_entry(GNUTLS_TLS1_2);
+ if (unlikely(ver == NULL)) {
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
+ }
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ for (i = 0; i < data_size; i += 2) {
+ uint8_t id[2];
+
+ id[0] = data[i];
+ id[1] = data[i + 1];
+
+ sig = _gnutls_tls_aid_to_sign(id[0], id[1], ver);
+
+ _gnutls_handshake_log
+ ("EXT[%p]: rcvd signature algo (%d.%d) %s\n", session,
+ (int)id[0], (int)id[1],
+ gnutls_sign_get_name(sig));
+
+ if (sig != GNUTLS_SIGN_UNKNOWN) {
+ if (priv->sign_algorithms_size == MAX_ALGOS)
+ break;
+ priv->sign_algorithms[priv->
+ sign_algorithms_size++] = sig;
+ }
+ }
+
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
+ epriv);
+
+ return 0;
+}
+
+/*
+ * In case of a server: if a SIGNATURE_ALGORITHMS extension type is
+ * received then it stores into the session security parameters the
+ * new value.
+ *
+ * In case of a client: If a signature_algorithms have been specified
+ * then it is an error;
+ */
+
+static int
+_gnutls_signature_algorithm_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size)
+{
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ /* nothing for now */
+ gnutls_assert();
+ /* Although TLS 1.2 mandates that we must not accept reply
+ * to this message, there are good reasons to just ignore it. Check
+ * https://www.ietf.org/mail-archive/web/tls/current/msg03880.html
+ */
+ /* return GNUTLS_E_UNEXPECTED_PACKET; */
+ } else {
+ /* SERVER SIDE
+ */
+ if (data_size >= 2) {
+ uint16_t len;
+
+ DECR_LEN(data_size, 2);
+ len = _gnutls_read_uint16(data);
+ DECR_LEN(data_size, len);
+
+ if (data_size > 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ ret =
+ _gnutls_sign_algorithm_parse_data(session,
+ data + 2,
+ len);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ } else {
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_signature_algorithm_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ int ret;
+ size_t init_length = extdata->length;
+ const version_entry_st *ver = get_version(session);
+
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ /* this function sends the client extension data */
+ if (session->security_parameters.entity == GNUTLS_CLIENT
+ && _gnutls_version_has_selectable_sighash(ver)) {
+ if (session->internals.priorities->sigalg.size > 0) {
+ ret =
+ _gnutls_sign_algorithm_write_params(session, extdata);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return extdata->length - init_length;
+ }
+ }
+
+ /* if we are here it means we don't send the extension */
+ return 0;
+}
+
+#ifdef GOST_SIG_FIXUP_SCHANNEL
+static bool
+is_gost_sig_present(sig_ext_st *priv)
+{
+ unsigned i;
+ const gnutls_sign_entry_st *se;
+
+ for (i = 0; i < priv->sign_algorithms_size; i++) {
+ se = _gnutls_sign_to_entry(priv->sign_algorithms[i]);
+ if (se != NULL && _sign_is_gost(se))
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+/* Returns a requested by the peer signature algorithm that
+ * matches the given certificate's public key algorithm.
+ *
+ * When the @client_cert flag is not set, then this function will
+ * also check whether the signature algorithm is allowed to be
+ * used in that session. Otherwise GNUTLS_SIGN_UNKNOWN is
+ * returned.
+ */
+gnutls_sign_algorithm_t
+_gnutls_session_get_sign_algo(gnutls_session_t session,
+ gnutls_pcert_st * cert,
+ gnutls_privkey_t privkey,
+ unsigned client_cert,
+ gnutls_kx_algorithm_t kx_algorithm)
+{
+ unsigned i;
+ int ret;
+ const version_entry_st *ver = get_version(session);
+ sig_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ unsigned int cert_algo;
+ const gnutls_sign_entry_st *se;
+
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_SIGN_UNKNOWN);
+
+ cert_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL);
+
+ ret =
+ _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
+ &epriv);
+ if (ret < 0)
+ priv = NULL;
+ else
+ priv = epriv;
+
+#ifdef GOST_SIG_FIXUP_SCHANNEL
+ /*
+ * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness.
+ * If we are negotiating GOST KX (because we have received GOST
+ * ciphersuites) and if we have received no GOST SignatureAlgorithms,
+ * assume that the client could not send them and continue negotiation
+ * as if correct algorithm was sent.
+ */
+ if (_gnutls_kx_is_vko_gost(kx_algorithm) &&
+ (!priv ||
+ !is_gost_sig_present(priv) ||
+ !_gnutls_version_has_selectable_sighash(ver))) {
+ gnutls_digest_algorithm_t dig;
+
+ _gnutls_handshake_log("EXT[%p]: GOST KX, but no GOST SigAlgs received, patching up.", session);
+
+ if (cert_algo == GNUTLS_PK_GOST_01)
+ dig = GNUTLS_DIG_GOSTR_94;
+ else if (cert_algo == GNUTLS_PK_GOST_12_256)
+ dig = GNUTLS_DIG_STREEBOG_256;
+ else if (cert_algo == GNUTLS_PK_GOST_12_512)
+ dig = GNUTLS_DIG_STREEBOG_512;
+ else
+ dig = GNUTLS_DIG_SHA1;
+
+ ret = gnutls_pk_to_sign(cert_algo, dig);
+
+ if (!client_cert && _gnutls_session_sign_algo_enabled(session, ret) < 0)
+ goto fail;
+ return ret;
+ }
+#endif
+
+ if (!priv || !_gnutls_version_has_selectable_sighash(ver)) {
+ /* none set, allow SHA-1 only */
+ ret = gnutls_pk_to_sign(cert_algo, GNUTLS_DIG_SHA1);
+
+ if (!client_cert && _gnutls_session_sign_algo_enabled(session, ret) < 0)
+ goto fail;
+ return ret;
+ }
+
+
+
+ for (i = 0; i < priv->sign_algorithms_size; i++) {
+ se = _gnutls_sign_to_entry(priv->sign_algorithms[i]);
+ if (se == NULL)
+ continue;
+
+ _gnutls_handshake_log("checking cert compat with %s\n", se->name);
+
+ if (_gnutls_privkey_compatible_with_sig(privkey, priv->sign_algorithms[i]) == 0)
+ continue;
+
+ if (sign_supports_cert_pk_algorithm(se, cert_algo) != 0) {
+ if (_gnutls_pubkey_compatible_with_sig
+ (session, cert->pubkey, ver, se->id) < 0)
+ continue;
+
+ if (_gnutls_session_sign_algo_enabled
+ (session, se->id) < 0)
+ continue;
+
+ return se->id;
+ }
+ }
+
+ /* When having a legacy client certificate which can only be signed
+ * using algorithms we don't always enable by default (e.g., DSA-SHA1),
+ * continue and sign with it. */
+ if (client_cert) {
+ _gnutls_audit_log(session, "No shared signature schemes with peer for client certificate (%s). Is the certificate a legacy one?\n",
+ gnutls_pk_get_name(cert_algo));
+ }
+
+ fail:
+ return GNUTLS_SIGN_UNKNOWN;
+}
+
+/* Check if the given signature algorithm is supported.
+ * This means that it is enabled by the priority functions,
+ * and in case of a server a matching certificate exists.
+ */
+int
+_gnutls_session_sign_algo_enabled(gnutls_session_t session,
+ gnutls_sign_algorithm_t sig)
+{
+ unsigned i;
+ const version_entry_st *ver = get_version(session);
+
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ if (!_gnutls_version_has_selectable_sighash(ver)) {
+ return 0;
+ }
+
+ if (ver->tls13_sem) {
+ /* disallow RSA, DSA, and SHA1 */
+ const gnutls_sign_entry_st *se;
+
+ se = _gnutls_sign_to_entry(sig);
+ if (se == NULL || (se->flags & GNUTLS_SIGN_FLAG_TLS13_OK) == 0) {
+ gnutls_assert();
+ goto disallowed;
+ }
+ }
+
+ for (i = 0; i < session->internals.priorities->sigalg.size; i++) {
+ if (session->internals.priorities->sigalg.entry[i]->id == sig) {
+ return 0; /* ok */
+ }
+ }
+
+ disallowed:
+ _gnutls_handshake_log("Signature algorithm %s is not enabled\n", gnutls_sign_algorithm_get_name(sig));
+ return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
+}
+
+static void signature_algorithms_deinit_data(gnutls_ext_priv_data_t priv)
+{
+ gnutls_free(priv);
+}
+
+static int
+signature_algorithms_pack(gnutls_ext_priv_data_t epriv,
+ gnutls_buffer_st * ps)
+{
+ sig_ext_st *priv = epriv;
+ int ret, i;
+
+ BUFFER_APPEND_NUM(ps, priv->sign_algorithms_size);
+ for (i = 0; i < priv->sign_algorithms_size; i++) {
+ BUFFER_APPEND_NUM(ps, priv->sign_algorithms[i]);
+ }
+ return 0;
+}
+
+static int
+signature_algorithms_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv)
+{
+ sig_ext_st *priv;
+ int i, ret;
+ gnutls_ext_priv_data_t epriv;
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ BUFFER_POP_NUM(ps, priv->sign_algorithms_size);
+ for (i = 0; i < priv->sign_algorithms_size; i++) {
+ BUFFER_POP_NUM(ps, priv->sign_algorithms[i]);
+ }
+
+ epriv = priv;
+ *_priv = epriv;
+
+ return 0;
+
+ error:
+ gnutls_free(priv);
+ return ret;
+}
+
+
+
+/**
+ * gnutls_sign_algorithm_get_requested:
+ * @session: is a #gnutls_session_t type.
+ * @indx: is an index of the signature algorithm to return
+ * @algo: the returned certificate type will be stored there
+ *
+ * Returns the signature algorithm specified by index that was
+ * requested by the peer. If the specified index has no data available
+ * this function returns %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE. If
+ * the negotiated TLS version does not support signature algorithms
+ * then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned even
+ * for the first index. The first index is 0.
+ *
+ * This function is useful in the certificate callback functions
+ * to assist in selecting the correct certificate.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ * an error code is returned.
+ *
+ * Since: 2.10.0
+ **/
+int
+gnutls_sign_algorithm_get_requested(gnutls_session_t session,
+ size_t indx,
+ gnutls_sign_algorithm_t * algo)
+{
+ const version_entry_st *ver = get_version(session);
+ sig_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ int ret;
+
+ if (unlikely(ver == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ ret =
+ _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
+ &epriv);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ priv = epriv;
+
+ if (!_gnutls_version_has_selectable_sighash(ver)
+ || priv->sign_algorithms_size == 0) {
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (indx < priv->sign_algorithms_size) {
+ *algo = priv->sign_algorithms[indx];
+ return 0;
+ } else
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+}
+
+/**
+ * gnutls_sign_algorithm_get:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Returns the signature algorithm that is (or will be) used in this
+ * session by the server to sign data. This function should be
+ * used only with TLS 1.2 or later.
+ *
+ * Returns: The sign algorithm or %GNUTLS_SIGN_UNKNOWN.
+ *
+ * Since: 3.1.1
+ **/
+int gnutls_sign_algorithm_get(gnutls_session_t session)
+{
+ return session->security_parameters.server_sign_algo;
+}
+
+/**
+ * gnutls_sign_algorithm_get_client:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Returns the signature algorithm that is (or will be) used in this
+ * session by the client to sign data. This function should be
+ * used only with TLS 1.2 or later.
+ *
+ * Returns: The sign algorithm or %GNUTLS_SIGN_UNKNOWN.
+ *
+ * Since: 3.1.11
+ **/
+int gnutls_sign_algorithm_get_client(gnutls_session_t session)
+{
+ return session->security_parameters.client_sign_algo;
+}
diff --git a/lib/ext/signature.h b/lib/ext/signature.h
new file mode 100644
index 0000000..ef42763
--- /dev/null
+++ b/lib/ext/signature.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2002-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SIGNATURE_H
+#define GNUTLS_LIB_EXT_SIGNATURE_H
+
+/* signature algorithms extension
+ */
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_sig;
+
+gnutls_sign_algorithm_t
+_gnutls_session_get_sign_algo(gnutls_session_t session,
+ gnutls_pcert_st * cert,
+ gnutls_privkey_t privkey,
+ unsigned client_cert,
+ gnutls_kx_algorithm_t kx_algorithm);
+int _gnutls_sign_algorithm_parse_data(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+int _gnutls_sign_algorithm_write_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+int _gnutls_session_sign_algo_enabled(gnutls_session_t session,
+ gnutls_sign_algorithm_t sig);
+
+static inline void
+gnutls_sign_algorithm_set_server(gnutls_session_t session,
+ gnutls_sign_algorithm_t sign)
+{
+ session->security_parameters.server_sign_algo = sign;
+}
+
+static inline void
+gnutls_sign_algorithm_set_client(gnutls_session_t session,
+ gnutls_sign_algorithm_t sign)
+{
+ session->security_parameters.client_sign_algo = sign;
+}
+
+#endif /* GNUTLS_LIB_EXT_SIGNATURE_H */
diff --git a/lib/ext/srp.c b/lib/ext/srp.c
new file mode 100644
index 0000000..f236c64
--- /dev/null
+++ b/lib/ext/srp.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include <ext/srp.h>
+
+#ifdef ENABLE_SRP
+
+#include "auth.h"
+#include <auth/srp_kx.h>
+#include "errors.h"
+#include "algorithms.h"
+#include <num.h>
+#include <hello_ext.h>
+
+static int _gnutls_srp_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv);
+static int _gnutls_srp_pack(gnutls_ext_priv_data_t epriv,
+ gnutls_buffer_st * ps);
+static void _gnutls_srp_deinit_data(gnutls_ext_priv_data_t epriv);
+static int _gnutls_srp_recv_params(gnutls_session_t state,
+ const uint8_t * data, size_t data_size);
+static int _gnutls_srp_send_params(gnutls_session_t state,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_srp = {
+ .name = "SRP",
+ .tls_id = 12,
+ .gid = GNUTLS_EXTENSION_SRP,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ .recv_func = _gnutls_srp_recv_params,
+ .send_func = _gnutls_srp_send_params,
+ .pack_func = _gnutls_srp_pack,
+ .unpack_func = _gnutls_srp_unpack,
+ .deinit_func = _gnutls_srp_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+
+static int
+_gnutls_srp_recv_params(gnutls_session_t session, const uint8_t * data,
+ size_t data_size)
+{
+ uint8_t len;
+ gnutls_ext_priv_data_t epriv;
+ srp_ext_st *priv;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (data_size > 0) {
+ DECR_LEN(data_size, 1);
+
+ len = data[0];
+ DECR_LEN(data_size, len);
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ priv->username = gnutls_malloc(len + 1);
+ if (priv->username) {
+ memcpy(priv->username, &data[1], len);
+ /* null terminated */
+ priv->username[len] = 0;
+ }
+
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRP,
+ epriv);
+ }
+ }
+ return 0;
+}
+
+static unsigned have_srp_ciphersuites(gnutls_session_t session)
+{
+ unsigned j;
+ unsigned kx;
+
+ for (j = 0; j < session->internals.priorities->cs.size; j++) {
+ kx = session->internals.priorities->cs.entry[j]->kx_algorithm;
+ if (kx == GNUTLS_KX_SRP || kx == GNUTLS_KX_SRP_RSA || kx == GNUTLS_KX_SRP_DSS)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ * data is allocated locally
+ */
+static int
+_gnutls_srp_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ unsigned len;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+ srp_ext_st *priv = NULL;
+ char *username = NULL, *password = NULL;
+ gnutls_srp_client_credentials_t cred =
+ (gnutls_srp_client_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_SRP);
+
+ if (session->security_parameters.entity != GNUTLS_CLIENT)
+ return 0;
+
+ if (cred == NULL)
+ return 0;
+
+ if (!have_srp_ciphersuites(session)) {
+ return 0;
+ }
+
+ /* this function sends the client extension data (username) */
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ if (cred->username != NULL) { /* send username */
+ len = MIN(strlen(cred->username), 255);
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 8,
+ cred->
+ username,
+ len);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ priv->username = gnutls_strdup(cred->username);
+ if (priv->username == NULL) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ priv->password = gnutls_strdup(cred->password);
+ if (priv->password == NULL) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRP,
+ epriv);
+
+ return len + 1;
+ } else if (cred->get_function != NULL) {
+ /* Try the callback
+ */
+
+ if (cred->
+ get_function(session, &username, &password) < 0
+ || username == NULL || password == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_ILLEGAL_SRP_USERNAME;
+ }
+
+ len = MIN(strlen(username), 255);
+
+ priv->username = username;
+ priv->password = password;
+
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 8,
+ username,
+ len);
+ if (ret < 0) {
+ ret = gnutls_assert_val(ret);
+ goto cleanup;
+ }
+
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRP,
+ epriv);
+
+ return len + 1;
+ }
+ return 0;
+
+ cleanup:
+ gnutls_free(username);
+ gnutls_free(password);
+ gnutls_free(priv);
+
+ return ret;
+}
+
+static void _gnutls_srp_deinit_data(gnutls_ext_priv_data_t epriv)
+{
+ srp_ext_st *priv = epriv;
+
+ gnutls_free(priv->username);
+ gnutls_free(priv->password);
+ gnutls_free(priv);
+}
+
+static int
+_gnutls_srp_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
+{
+ srp_ext_st *priv = epriv;
+ int ret;
+ int password_len = 0, username_len = 0;
+
+ if (priv->username)
+ username_len = strlen(priv->username);
+
+ if (priv->password)
+ password_len = strlen(priv->password);
+
+ BUFFER_APPEND_PFX4(ps, priv->username, username_len);
+ BUFFER_APPEND_PFX4(ps, priv->password, password_len);
+
+ return 0;
+}
+
+static int
+_gnutls_srp_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
+{
+ srp_ext_st *priv;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+ gnutls_datum_t username = { NULL, 0 };
+ gnutls_datum_t password = { NULL, 0 };
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ BUFFER_POP_DATUM(ps, &username);
+ BUFFER_POP_DATUM(ps, &password);
+
+ priv->username = (char *) username.data;
+ priv->password = (char *) password.data;
+
+ epriv = priv;
+ *_priv = epriv;
+
+ return 0;
+
+ error:
+ _gnutls_free_datum(&username);
+ _gnutls_free_datum(&password);
+ return ret;
+}
+
+
+#endif /* ENABLE_SRP */
diff --git a/lib/ext/srp.h b/lib/ext/srp.h
new file mode 100644
index 0000000..fd7576f
--- /dev/null
+++ b/lib/ext/srp.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SRP_H
+#define GNUTLS_LIB_EXT_SRP_H
+
+#include <hello_ext.h>
+
+#define IS_SRP_KX(kx) ((kx == GNUTLS_KX_SRP || (kx == GNUTLS_KX_SRP_RSA) || \
+ kx == GNUTLS_KX_SRP_DSS)?1:0)
+
+#ifdef ENABLE_SRP
+
+extern const hello_ext_entry_st ext_mod_srp;
+
+typedef struct {
+ char *username;
+ char *password;
+} srp_ext_st;
+
+#endif
+
+#endif /* GNUTLS_LIB_EXT_SRP_H */
diff --git a/lib/ext/srtp.c b/lib/ext/srtp.c
new file mode 100644
index 0000000..b2e36b3
--- /dev/null
+++ b/lib/ext/srtp.c
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2012 Free Software Foundation
+ *
+ * Author: Martin Storsjo
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "auth.h"
+#include "errors.h"
+#include "num.h"
+#include <ext/srtp.h>
+
+static int _gnutls_srtp_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_srtp_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+static int _gnutls_srtp_unpack(gnutls_buffer_st * ps,
+ gnutls_ext_priv_data_t * _priv);
+static int _gnutls_srtp_pack(gnutls_ext_priv_data_t _priv,
+ gnutls_buffer_st * ps);
+static void _gnutls_srtp_deinit_data(gnutls_ext_priv_data_t priv);
+
+
+const hello_ext_entry_st ext_mod_srtp = {
+ .name = "SRTP",
+ .tls_id = 14,
+ .gid = GNUTLS_EXTENSION_SRTP,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .client_parse_point = GNUTLS_EXT_APPLICATION,
+ .server_parse_point = GNUTLS_EXT_APPLICATION,
+ .recv_func = _gnutls_srtp_recv_params,
+ .send_func = _gnutls_srtp_send_params,
+ .pack_func = _gnutls_srtp_pack,
+ .unpack_func = _gnutls_srtp_unpack,
+ .deinit_func = _gnutls_srtp_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+typedef struct {
+ const char *name;
+ gnutls_srtp_profile_t id;
+ unsigned int key_length;
+ unsigned int salt_length;
+} srtp_profile_st;
+
+static const srtp_profile_st profile_names[] = {
+ {
+ "SRTP_AES128_CM_HMAC_SHA1_80",
+ GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80,
+ 16, 14},
+ {
+ "SRTP_AES128_CM_HMAC_SHA1_32",
+ GNUTLS_SRTP_AES128_CM_HMAC_SHA1_32,
+ 16, 14},
+ {
+ "SRTP_NULL_HMAC_SHA1_80",
+ GNUTLS_SRTP_NULL_HMAC_SHA1_80,
+ 16, 14},
+ {
+ "SRTP_NULL_SHA1_32",
+ GNUTLS_SRTP_NULL_HMAC_SHA1_32,
+ 16, 14},
+ {
+ NULL,
+ 0, 0, 0}
+};
+
+static const srtp_profile_st *get_profile(gnutls_srtp_profile_t profile)
+{
+ const srtp_profile_st *p = profile_names;
+ while (p->name != NULL) {
+ if (p->id == profile)
+ return p;
+ p++;
+ }
+ return NULL;
+}
+
+static gnutls_srtp_profile_t find_profile(const char *str, const char *end)
+{
+ const srtp_profile_st *prof = profile_names;
+ unsigned int len;
+ if (end != NULL) {
+ len = end - str;
+ } else {
+ len = strlen(str);
+ }
+
+ while (prof->name != NULL) {
+ if (strlen(prof->name) == len
+ && !strncmp(str, prof->name, len)) {
+ return prof->id;
+ }
+ prof++;
+ }
+ return 0;
+}
+
+/**
+ * gnutls_srtp_get_profile_id
+ * @name: The name of the profile to look up
+ * @profile: Will hold the profile id
+ *
+ * This function allows you to look up a profile based on a string.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.1.4
+ **/
+int gnutls_srtp_get_profile_id(const char *name,
+ gnutls_srtp_profile_t * profile)
+{
+ *profile = find_profile(name, NULL);
+ if (*profile == 0) {
+ return GNUTLS_E_ILLEGAL_PARAMETER;
+ }
+ return 0;
+}
+
+#define MAX_PROFILES_IN_SRTP_EXTENSION 256
+
+/**
+ * gnutls_srtp_get_profile_name
+ * @profile: The profile to look up a string for
+ *
+ * This function allows you to get the corresponding name for a
+ * SRTP protection profile.
+ *
+ * Returns: On success, the name of a SRTP profile as a string,
+ * otherwise NULL.
+ *
+ * Since 3.1.4
+ **/
+const char *gnutls_srtp_get_profile_name(gnutls_srtp_profile_t profile)
+{
+ const srtp_profile_st *p = get_profile(profile);
+
+ if (p != NULL)
+ return p->name;
+
+ return NULL;
+}
+
+static int
+_gnutls_srtp_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ unsigned int i;
+ int ret;
+ const uint8_t *p = data;
+ size_t len;
+ srtp_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ uint16_t profile;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ DECR_LENGTH_RET(data_size, 2, 0);
+ len = _gnutls_read_uint16(p);
+ p += 2;
+
+ if (len + 1 > data_size)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (len > MAX_PROFILES_IN_SRTP_EXTENSION * 2)
+ return 0;
+ } else {
+ if (len != 2)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ }
+
+ priv->selected_profile = 0;
+
+ while (len > 0) {
+ DECR_LEN(data_size, 2);
+ profile = _gnutls_read_uint16(p);
+
+ for (i = 0;
+ i < priv->profiles_size
+ && priv->selected_profile == 0; i++) {
+ if (priv->profiles[i] == profile) {
+ priv->selected_profile = profile;
+ break;
+ }
+ }
+ p += 2;
+ len -= 2;
+ }
+
+ DECR_LEN(data_size, 1);
+ priv->mki_size = *p;
+ p++;
+
+ if (priv->mki_size > 0) {
+ DECR_LEN(data_size, priv->mki_size);
+ memcpy(priv->mki, p, priv->mki_size);
+ priv->mki_received = 1;
+ }
+
+ return 0;
+}
+
+static int
+_gnutls_srtp_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ unsigned i;
+ int total_size = 0, ret;
+ srtp_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ if (priv->profiles_size == 0)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ /* Don't send anything if no matching profile was found */
+ if (priv->selected_profile == 0)
+ return 0;
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, 2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ priv->selected_profile);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ total_size = 4;
+ } else {
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ 2 * priv->profiles_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ for (i = 0; i < priv->profiles_size; i++) {
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ priv->
+ profiles[i]);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ total_size = 2 + 2 * priv->profiles_size;
+ }
+
+ /* use_mki */
+ ret =
+ _gnutls_buffer_append_data_prefix(extdata, 8, priv->mki,
+ priv->mki_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ total_size += 1 + priv->mki_size;
+
+ return total_size;
+}
+
+/**
+ * gnutls_srtp_get_selected_profile:
+ * @session: is a #gnutls_session_t type.
+ * @profile: will hold the profile
+ *
+ * This function allows you to get the negotiated SRTP profile.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.1.4
+ **/
+int
+gnutls_srtp_get_selected_profile(gnutls_session_t session,
+ gnutls_srtp_profile_t * profile)
+{
+ srtp_ext_st *priv;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ priv = epriv;
+
+ if (priv->selected_profile == 0) {
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ *profile = priv->selected_profile;
+
+ return 0;
+}
+
+/**
+ * gnutls_srtp_get_mki:
+ * @session: is a #gnutls_session_t type.
+ * @mki: will hold the MKI
+ *
+ * This function exports the negotiated Master Key Identifier,
+ * received by the peer if any. The returned value in @mki should be
+ * treated as constant and valid only during the session's lifetime.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.1.4
+ **/
+int gnutls_srtp_get_mki(gnutls_session_t session, gnutls_datum_t * mki)
+{
+ srtp_ext_st *priv;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ priv = epriv;
+
+ if (priv->mki_received == 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ mki->data = priv->mki;
+ mki->size = priv->mki_size;
+
+ return 0;
+}
+
+/**
+ * gnutls_srtp_set_mki:
+ * @session: is a #gnutls_session_t type.
+ * @mki: holds the MKI
+ *
+ * This function sets the Master Key Identifier, to be
+ * used by this session (if any).
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.1.4
+ **/
+int
+gnutls_srtp_set_mki(gnutls_session_t session, const gnutls_datum_t * mki)
+{
+ int ret;
+ srtp_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRTP, epriv);
+ } else
+ priv = epriv;
+
+ if (mki->size > 0 && mki->size <= sizeof(priv->mki)) {
+ priv->mki_size = mki->size;
+ memcpy(priv->mki, mki->data, mki->size);
+ } else
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ return 0;
+}
+
+/**
+ * gnutls_srtp_set_profile:
+ * @session: is a #gnutls_session_t type.
+ * @profile: is the profile id to add.
+ *
+ * This function is to be used by both clients and servers, to declare
+ * what SRTP profiles they support, to negotiate with the peer.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since 3.1.4
+ **/
+int
+gnutls_srtp_set_profile(gnutls_session_t session,
+ gnutls_srtp_profile_t profile)
+{
+ int ret;
+ srtp_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0) {
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRTP, epriv);
+ } else
+ priv = epriv;
+
+ if (priv->profiles_size < MAX_SRTP_PROFILES)
+ priv->profiles_size++;
+ priv->profiles[priv->profiles_size - 1] = profile;
+
+ return 0;
+}
+
+/**
+ * gnutls_srtp_set_profile_direct:
+ * @session: is a #gnutls_session_t type.
+ * @profiles: is a string that contains the supported SRTP profiles,
+ * separated by colons.
+ * @err_pos: In case of an error this will have the position in the string the error occurred, may be NULL.
+ *
+ * This function is to be used by both clients and servers, to declare
+ * what SRTP profiles they support, to negotiate with the peer.
+ *
+ * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
+ * %GNUTLS_E_SUCCESS on success, or an error code.
+ *
+ * Since 3.1.4
+ **/
+int
+gnutls_srtp_set_profile_direct(gnutls_session_t session,
+ const char *profiles, const char **err_pos)
+{
+ int ret;
+ srtp_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+ int set = 0;
+ const char *col;
+ gnutls_srtp_profile_t id;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP,
+ &epriv);
+ if (ret < 0) {
+ set = 1;
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ if (err_pos != NULL)
+ *err_pos = profiles;
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv = priv;
+ } else
+ priv = epriv;
+
+ do {
+ col = strchr(profiles, ':');
+ id = find_profile(profiles, col);
+ if (id == 0) {
+ if (set != 0)
+ gnutls_free(priv);
+ if (err_pos != NULL)
+ *err_pos = profiles;
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (priv->profiles_size < MAX_SRTP_PROFILES) {
+ priv->profiles_size++;
+ }
+ priv->profiles[priv->profiles_size - 1] = id;
+ profiles = col + 1;
+ } while (col != NULL);
+
+ if (set != 0)
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_SRTP, epriv);
+
+ return 0;
+}
+
+/**
+ * gnutls_srtp_get_keys:
+ * @session: is a #gnutls_session_t type.
+ * @key_material: Space to hold the generated key material
+ * @key_material_size: The maximum size of the key material
+ * @client_key: The master client write key, pointing inside the key material
+ * @server_key: The master server write key, pointing inside the key material
+ * @client_salt: The master client write salt, pointing inside the key material
+ * @server_salt: The master server write salt, pointing inside the key material
+ *
+ * This is a helper function to generate the keying material for SRTP.
+ * It requires the space of the key material to be pre-allocated (should be at least
+ * 2x the maximum key size and salt size). The @client_key, @client_salt, @server_key
+ * and @server_salt are convenience datums that point inside the key material. They may
+ * be %NULL.
+ *
+ * Returns: On success the size of the key material is returned,
+ * otherwise, %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
+ * sufficient, or a negative error code.
+ *
+ * Since 3.1.4
+ **/
+int
+gnutls_srtp_get_keys(gnutls_session_t session,
+ void *key_material,
+ unsigned int key_material_size,
+ gnutls_datum_t * client_key,
+ gnutls_datum_t * client_salt,
+ gnutls_datum_t * server_key,
+ gnutls_datum_t * server_salt)
+{
+ int ret;
+ const srtp_profile_st *p;
+ gnutls_srtp_profile_t profile;
+ unsigned int msize;
+ uint8_t *km = key_material;
+
+ ret = gnutls_srtp_get_selected_profile(session, &profile);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ p = get_profile(profile);
+ if (p == NULL)
+ return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
+
+ msize = 2 * (p->key_length + p->salt_length);
+ if (msize > key_material_size)
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+ if (msize == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret =
+ gnutls_prf(session, sizeof("EXTRACTOR-dtls_srtp") - 1,
+ "EXTRACTOR-dtls_srtp", 0, 0, NULL, msize,
+ key_material);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (client_key) {
+ client_key->data = km;
+ client_key->size = p->key_length;
+ }
+
+ if (server_key) {
+ server_key->data = km + p->key_length;
+ server_key->size = p->key_length;
+ }
+
+ if (client_salt) {
+ client_salt->data = km + 2 * p->key_length;
+ client_salt->size = p->salt_length;
+ }
+
+ if (server_salt) {
+ server_salt->data =
+ km + 2 * p->key_length + p->salt_length;
+ server_salt->size = p->salt_length;
+ }
+
+ return msize;
+}
+
+static void _gnutls_srtp_deinit_data(gnutls_ext_priv_data_t priv)
+{
+ gnutls_free(priv);
+}
+
+static int
+_gnutls_srtp_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
+{
+ srtp_ext_st *priv = epriv;
+ unsigned int i;
+ int ret;
+
+ BUFFER_APPEND_NUM(ps, priv->profiles_size);
+ for (i = 0; i < priv->profiles_size; i++) {
+ BUFFER_APPEND_NUM(ps, priv->profiles[i]);
+ }
+
+ BUFFER_APPEND_NUM(ps, priv->mki_received);
+ if (priv->mki_received) {
+ BUFFER_APPEND_NUM(ps, priv->selected_profile);
+ BUFFER_APPEND_PFX4(ps, priv->mki, priv->mki_size);
+ }
+ return 0;
+}
+
+static int
+_gnutls_srtp_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
+{
+ srtp_ext_st *priv;
+ unsigned int i;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+
+ priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ BUFFER_POP_NUM(ps, priv->profiles_size);
+ for (i = 0; i < priv->profiles_size; i++) {
+ BUFFER_POP_NUM(ps, priv->profiles[i]);
+ }
+ BUFFER_POP_NUM(ps, priv->selected_profile);
+
+ BUFFER_POP_NUM(ps, priv->mki_received);
+ if (priv->mki_received) {
+ BUFFER_POP_NUM(ps, priv->mki_size);
+ BUFFER_POP(ps, priv->mki, priv->mki_size);
+ }
+
+ epriv = priv;
+ *_priv = epriv;
+
+ return 0;
+
+ error:
+ gnutls_free(priv);
+ return ret;
+}
diff --git a/lib/ext/srtp.h b/lib/ext/srtp.h
new file mode 100644
index 0000000..d05454a
--- /dev/null
+++ b/lib/ext/srtp.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Free Software Foundation
+ *
+ * Author: Martin Storsjo
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SRTP_H
+#define GNUTLS_LIB_EXT_SRTP_H
+#ifndef EXT_SRTP_H
+#define EXT_SRTP_H
+
+#include <hello_ext.h>
+
+#define MAX_SRTP_PROFILES 4
+
+typedef struct {
+ gnutls_srtp_profile_t profiles[MAX_SRTP_PROFILES];
+ unsigned profiles_size;
+ gnutls_srtp_profile_t selected_profile;
+ uint8_t mki[256];
+ unsigned mki_size;
+ unsigned int mki_received;
+} srtp_ext_st;
+
+extern const hello_ext_entry_st ext_mod_srtp;
+
+#endif
+
+#endif /* GNUTLS_LIB_EXT_SRTP_H */
diff --git a/lib/ext/status_request.c b/lib/ext/status_request.c
new file mode 100644
index 0000000..1e89286
--- /dev/null
+++ b/lib/ext/status_request.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Simon Josefsson, Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/*
+ Status Request (OCSP) TLS extension. See RFC 6066 section 8:
+ https://tools.ietf.org/html/rfc6066#section-8
+*/
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include <hello_ext.h>
+#include <ext/status_request.h>
+#include <mbuffers.h>
+#include <auth.h>
+#include <auth/cert.h>
+#include <handshake.h>
+
+#ifdef ENABLE_OCSP
+
+typedef struct {
+ /* server response */
+ gnutls_datum_t sresp;
+
+ unsigned int expect_cstatus;
+} status_request_ext_st;
+
+/*
+ From RFC 6066. Client sends:
+
+ struct {
+ CertificateStatusType status_type;
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ } request;
+ } CertificateStatusRequest;
+
+ enum { ocsp(1), (255) } CertificateStatusType;
+
+ struct {
+ ResponderID responder_id_list<0..2^16-1>;
+ Extensions request_extensions;
+ } OCSPStatusRequest;
+
+ opaque ResponderID<1..2^16-1>;
+ opaque Extensions<0..2^16-1>;
+*/
+
+
+static int
+client_send(gnutls_session_t session,
+ gnutls_buffer_st * extdata, status_request_ext_st * priv)
+{
+ const uint8_t data[5] = "\x01\x00\x00\x00\x00";
+ const int len = 5;
+ int ret;
+
+ /* We do not support setting either ResponderID or Extensions */
+
+ ret = _gnutls_buffer_append_data(extdata, data, len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
+
+ return len;
+}
+
+static int
+server_recv(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ unsigned rid_bytes = 0;
+
+ /* minimum message is type (1) + responder_id_list (2) +
+ request_extension (2) = 5 */
+ if (data_size < 5)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ /* We ignore non-ocsp CertificateStatusType. The spec is unclear
+ what should be done. */
+ if (data[0] != 0x01) {
+ gnutls_assert();
+ _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
+ session, data[0]);
+ return 0;
+ }
+ DECR_LEN(data_size, 1);
+ data++;
+
+ rid_bytes = _gnutls_read_uint16(data);
+
+ DECR_LEN(data_size, 2);
+ /*data += 2;*/
+
+ /* sanity check only, we don't use any of the data below */
+
+ if (data_size < rid_bytes)
+ return
+ gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ _gnutls_handshake_log("EXT[%p]: OCSP status was requested\n", session);
+ session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
+
+ return 0;
+}
+
+
+static int
+client_recv(gnutls_session_t session,
+ status_request_ext_st * priv,
+ const uint8_t * data, size_t size)
+{
+ if (size != 0)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ else {
+ priv->expect_cstatus = 1;
+ return 0;
+ }
+}
+
+
+/*
+ * Servers return a certificate response along with their certificate
+ * by sending a "CertificateStatus" message immediately after the
+ * "Certificate" message (and before any "ServerKeyExchange" or
+ * "CertificateRequest" messages). If a server returns a
+ * "CertificateStatus" message, then the server MUST have included an
+ * extension of type "status_request" with empty "extension_data" in
+ * the extended server hello.
+ *
+ * According to the description above, as a server we could simply
+ * return GNUTLS_E_INT_RET_0 on this function. In that case we would
+ * only need to use the callbacks at the time we need to send the data,
+ * and skip the status response packet if no such data are there.
+ * However, that behavior would break gnutls 3.3.x which expects the status
+ * response to be always send if the extension is present.
+ *
+ * Instead we ensure that this extension is parsed after the CS/certificate
+ * are selected (with the _GNUTLS_EXT_TLS_POST_CS type), and we discover
+ * (or not) the response to send early.
+ */
+static int
+server_send(gnutls_session_t session,
+ gnutls_buffer_st * extdata, status_request_ext_st * priv)
+{
+ int ret;
+ gnutls_certificate_credentials_t cred;
+ gnutls_status_request_ocsp_func func;
+ void *func_ptr;
+ const version_entry_st *ver = get_version(session);
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) /* no certificate authentication */
+ return 0;
+
+ /* no need to set sresp; responses are send during certificate sending and
+ * no response is required from server side. */
+ if (ver && ver->multi_ocsp)
+ return 0;
+
+ /* Under TLS1.2 we obtain the response at this point in order to respond
+ * appropriately (empty extension vs no response) */
+ if (session->internals.selected_ocsp_length > 0) {
+ if (session->internals.selected_ocsp[0].response.data) {
+ if (session->internals.selected_ocsp[0].exptime != 0 &&
+ (gnutls_time(0) >= session->internals.selected_ocsp[0].exptime)) {
+ gnutls_assert();
+ return 0;
+ }
+
+ ret = _gnutls_set_datum(&priv->sresp,
+ session->internals.selected_ocsp[0].response.data,
+ session->internals.selected_ocsp[0].response.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ return GNUTLS_E_INT_RET_0;
+ } else {
+ return 0;
+ }
+ } else if (session->internals.selected_ocsp_func) {
+ func = session->internals.selected_ocsp_func;
+ func_ptr = session->internals.selected_ocsp_func_ptr;
+
+ if (func == NULL)
+ return 0;
+
+ ret = func(session, func_ptr, &priv->sresp);
+ if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
+ return 0;
+ else if (ret < 0)
+ return gnutls_assert_val(ret);
+ } else {
+ return 0;
+ }
+
+ return GNUTLS_E_INT_RET_0;
+}
+
+static int
+_gnutls_status_request_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ gnutls_ext_priv_data_t epriv;
+ status_request_ext_st *priv;
+ int ret;
+
+ /* Do not bother sending the OCSP status request extension
+ * if we are not using certificate authentication */
+ if (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ &epriv);
+ if (ret < 0 || epriv == NULL) /* it is ok not to have it */
+ return 0;
+ priv = epriv;
+
+ return client_send(session, extdata, priv);
+ } else {
+ epriv = priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ epriv);
+
+ return server_send(session, extdata, priv);
+ }
+}
+
+static int
+_gnutls_status_request_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t size)
+{
+ gnutls_ext_priv_data_t epriv;
+ status_request_ext_st *priv;
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ ret = _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ &epriv);
+ if (ret < 0 || epriv == NULL) /* it is ok not to have it */
+ return 0;
+ priv = epriv;
+
+ return client_recv(session, priv, data, size);
+ } else {
+ return server_recv(session, data, size);
+ }
+}
+
+/**
+ * gnutls_ocsp_status_request_enable_client:
+ * @session: is a #gnutls_session_t type.
+ * @responder_id: ignored, must be %NULL
+ * @responder_id_size: ignored, must be zero
+ * @extensions: ignored, must be %NULL
+ *
+ * This function is to be used by clients to request OCSP response
+ * from the server, using the "status_request" TLS extension. Only
+ * OCSP status type is supported.
+ *
+ * Previous versions of GnuTLS supported setting @responder_id and
+ * @extensions fields, but due to the difficult semantics of the
+ * parameter usage, and other issues, this support was removed
+ * since 3.6.0 and these parameters must be set to %NULL.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
+ * otherwise a negative error code is returned.
+ *
+ * Since: 3.1.3
+ **/
+int
+gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
+ gnutls_datum_t * responder_id,
+ size_t responder_id_size,
+ gnutls_datum_t * extensions)
+{
+ status_request_ext_st *priv;
+ gnutls_ext_priv_data_t epriv;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ epriv = priv = gnutls_calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _gnutls_hello_ext_set_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ epriv);
+
+ return 0;
+}
+
+
+static void _gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv)
+{
+ status_request_ext_st *priv = epriv;
+
+ if (priv == NULL)
+ return;
+
+ gnutls_free(priv->sresp.data);
+ gnutls_free(priv);
+}
+
+const hello_ext_entry_st ext_mod_status_request = {
+ .name = "OCSP Status Request",
+ .tls_id = STATUS_REQUEST_TLS_ID,
+ .gid = GNUTLS_EXTENSION_STATUS_REQUEST,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
+ .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
+ .recv_func = _gnutls_status_request_recv_params,
+ .send_func = _gnutls_status_request_send_params,
+ .deinit_func = _gnutls_status_request_deinit_data,
+ .cannot_be_overriden = 1
+};
+
+/* Functions to be called from handshake */
+
+int
+_gnutls_send_server_certificate_status(gnutls_session_t session, int again)
+{
+ mbuffer_st *bufel = NULL;
+ uint8_t *data;
+ int data_size = 0;
+ int ret;
+ gnutls_ext_priv_data_t epriv;
+ status_request_ext_st *priv;
+
+ if (!(session->internals.hsk_flags & HSK_OCSP_REQUESTED))
+ return 0;
+
+ if (again == 0) {
+ ret =
+ _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ if (!priv->sresp.size)
+ return 0;
+
+ data_size = priv->sresp.size + 4;
+ bufel =
+ _gnutls_handshake_alloc(session, data_size);
+ if (!bufel) {
+ _gnutls_free_datum(&priv->sresp);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+
+ data = _mbuffer_get_udata_ptr(bufel);
+
+ data[0] = 0x01;
+ _gnutls_write_uint24(priv->sresp.size, &data[1]);
+ memcpy(&data[4], priv->sresp.data, priv->sresp.size);
+
+ _gnutls_free_datum(&priv->sresp);
+ }
+ return _gnutls_send_handshake(session, data_size ? bufel : NULL,
+ GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
+}
+
+int _gnutls_parse_ocsp_response(gnutls_session_t session, const uint8_t *data, ssize_t data_size, gnutls_datum_t *resp)
+{
+ int ret;
+ ssize_t r_size;
+
+ resp->data = 0;
+ resp->size = 0;
+
+ /* minimum message is type (1) + response (3) + data */
+ if (data_size < 4)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (data[0] != 0x01) {
+ gnutls_assert();
+ _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
+ session, data[0]);
+ return 0;
+ }
+
+ DECR_LENGTH_RET(data_size, 1,
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ data++;
+
+ DECR_LENGTH_RET(data_size, 3,
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ r_size = _gnutls_read_uint24(data);
+ data += 3;
+
+ DECR_LENGTH_RET(data_size, r_size,
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (r_size < 1)
+ return
+ gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ ret = _gnutls_set_datum(resp, data, r_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+int _gnutls_recv_server_certificate_status(gnutls_session_t session)
+{
+ uint8_t *data;
+ ssize_t data_size;
+ gnutls_buffer_st buf;
+ int ret;
+ gnutls_datum_t resp;
+ status_request_ext_st *priv = NULL;
+ gnutls_ext_priv_data_t epriv;
+ cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
+
+ if (info == NULL)
+ return 0;
+
+ ret =
+ _gnutls_hello_ext_get_priv(session,
+ GNUTLS_EXTENSION_STATUS_REQUEST,
+ &epriv);
+ if (ret < 0)
+ return 0;
+
+ priv = epriv;
+
+ if (!priv->expect_cstatus)
+ return 0;
+
+ ret = _gnutls_recv_handshake(session,
+ GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
+ 1, &buf);
+ if (ret < 0)
+ return gnutls_assert_val_fatal(ret);
+
+ priv->expect_cstatus = 0;
+
+ data = buf.data;
+ data_size = buf.length;
+
+ if (data_size == 0) {
+ ret = 0;
+ goto error;
+ }
+
+ ret = _gnutls_parse_ocsp_response(session, data, data_size, &resp);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ if (resp.data && resp.size > 0) {
+ for (unsigned int i = 0; i < info->nocsp; i++)
+ gnutls_free(info->raw_ocsp_list[i].data);
+ gnutls_free(info->raw_ocsp_list);
+
+ info->raw_ocsp_list = gnutls_malloc(sizeof(gnutls_datum_t));
+ if (info->raw_ocsp_list == NULL) {
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+ info->raw_ocsp_list[0].data = resp.data;
+ info->raw_ocsp_list[0].size = resp.size;
+ info->nocsp = 1;
+ }
+
+ ret = 0;
+
+ error:
+ _gnutls_buffer_clear(&buf);
+
+ return ret;
+}
+
+#endif
diff --git a/lib/ext/status_request.h b/lib/ext/status_request.h
new file mode 100644
index 0000000..dc1d233
--- /dev/null
+++ b/lib/ext/status_request.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ * Author: Simon Josefsson
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_STATUS_REQUEST_H
+#define GNUTLS_LIB_EXT_STATUS_REQUEST_H
+
+#include <hello_ext.h>
+
+#define STATUS_REQUEST_TLS_ID 5
+
+extern const hello_ext_entry_st ext_mod_status_request;
+
+int
+_gnutls_send_server_certificate_status(gnutls_session_t session,
+ int again);
+int _gnutls_recv_server_certificate_status(gnutls_session_t session);
+
+int _gnutls_parse_ocsp_response(gnutls_session_t session, const uint8_t *data,
+ ssize_t data_size,
+ gnutls_datum_t *resp);
+
+#endif /* GNUTLS_LIB_EXT_STATUS_REQUEST_H */
diff --git a/lib/ext/supported_groups.c b/lib/ext/supported_groups.c
new file mode 100644
index 0000000..56e514a
--- /dev/null
+++ b/lib/ext/supported_groups.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Supported Groups extension (rfc7919).
+ * This extension was previously named Supported Elliptic Curves under TLS 1.2.
+ */
+
+#include "ext/supported_groups.h"
+#include "str.h"
+#include "num.h"
+#include "auth/psk.h"
+#include "auth/cert.h"
+#include "auth/anon.h"
+#include "algorithms.h"
+#include <gnutls/gnutls.h>
+
+
+static int _gnutls_supported_groups_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int _gnutls_supported_groups_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+
+const hello_ext_entry_st ext_mod_supported_groups = {
+ .name = "Supported Groups",
+ .tls_id = 10,
+ .gid = GNUTLS_EXTENSION_SUPPORTED_GROUPS,
+ .client_parse_point = GNUTLS_EXT_TLS,
+ .server_parse_point = GNUTLS_EXT_TLS,
+ .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ .recv_func = _gnutls_supported_groups_recv_params,
+ .send_func = _gnutls_supported_groups_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+
+static unsigned get_min_dh(gnutls_session_t session)
+{
+ gnutls_certificate_credentials_t cert_cred;
+ gnutls_psk_server_credentials_t psk_cred;
+ gnutls_anon_server_credentials_t anon_cred;
+ unsigned level = 0;
+
+ cert_cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ psk_cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ anon_cred = (gnutls_anon_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_ANON);
+
+ if (cert_cred) {
+ level = cert_cred->dh_sec_param;
+ } else if (psk_cred) {
+ level = psk_cred->dh_sec_param;
+ } else if (anon_cred) {
+ level = anon_cred->dh_sec_param;
+ }
+
+ if (level)
+ return gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, level);
+
+ return 0;
+}
+
+/*
+ * In case of a server: if a SUPPORTED_GROUPS extension type is received then it stores
+ * into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(),
+ * to access it.
+ *
+ * In case of a client: If supported_eccs have been specified then we send the extension.
+ *
+ */
+static int
+_gnutls_supported_groups_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ int i;
+ uint16_t len;
+ const uint8_t *p = data;
+ const gnutls_group_entry_st *group = NULL;
+ unsigned have_ffdhe = 0;
+ unsigned tls_id;
+ unsigned min_dh;
+ unsigned j;
+ int serv_ec_idx, serv_dh_idx; /* index in server's priority listing */
+ int cli_ec_pos, cli_dh_pos; /* position in listing sent by client */
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ /* A client shouldn't receive this extension in TLS1.2. It is
+ * possible to read that message under TLS1.3 as an encrypted
+ * extension. */
+ return 0;
+ } else { /* SERVER SIDE - we must check if the sent supported ecc type is the right one
+ */
+ if (data_size < 2)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+
+ DECR_LEN(data_size, 2);
+ len = _gnutls_read_uint16(p);
+ p += 2;
+
+ if (len % 2 != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ DECR_LEN(data_size, len);
+
+ /* we figure what is the minimum DH allowed for this session, if any */
+ min_dh = get_min_dh(session);
+
+ serv_ec_idx = serv_dh_idx = -1;
+ cli_ec_pos = cli_dh_pos = -1;
+
+ /* This extension is being processed prior to a ciphersuite being selected,
+ * so we cannot rely on ciphersuite information. */
+ for (i = 0; i < len; i += 2) {
+ if (have_ffdhe == 0 && p[i] == 0x01)
+ have_ffdhe = 1;
+
+ tls_id = _gnutls_read_uint16(&p[i]);
+ group = _gnutls_tls_id_to_group(tls_id);
+
+ _gnutls_handshake_log("EXT[%p]: Received group %s (0x%x)\n", session, group?group->name:"unknown", tls_id);
+ if (group == NULL)
+ continue;
+
+ if (min_dh > 0 && group->prime && group->prime->size*8 < min_dh)
+ continue;
+
+ /* we simulate _gnutls_session_supports_group, but we prioritize if
+ * %SERVER_PRECEDENCE is given */
+ for (j = 0; j < session->internals.priorities->groups.size; j++) {
+ if (session->internals.priorities->groups.entry[j]->id == group->id) {
+ if (session->internals.priorities->server_precedence) {
+ if (group->pk == GNUTLS_PK_DH) {
+ if (serv_dh_idx != -1 && (int)j > serv_dh_idx)
+ break;
+ serv_dh_idx = j;
+ cli_dh_pos = i;
+ } else if (IS_EC(group->pk)) {
+ if (serv_ec_idx != -1 && (int)j > serv_ec_idx)
+ break;
+ serv_ec_idx = j;
+ cli_ec_pos = i;
+ }
+ } else {
+ if (group->pk == GNUTLS_PK_DH) {
+ if (cli_dh_pos != -1)
+ break;
+ cli_dh_pos = i;
+ serv_dh_idx = j;
+ } else if (IS_EC(group->pk)) {
+ if (cli_ec_pos != -1)
+ break;
+ cli_ec_pos = i;
+ serv_ec_idx = j;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /* serv_dh/ec_pos contain the index of the groups we want to use.
+ */
+ if (serv_dh_idx != -1) {
+ session->internals.cand_dh_group = session->internals.priorities->groups.entry[serv_dh_idx];
+ session->internals.cand_group = session->internals.cand_dh_group;
+ }
+
+ if (serv_ec_idx != -1) {
+ session->internals.cand_ec_group = session->internals.priorities->groups.entry[serv_ec_idx];
+ if (session->internals.cand_group == NULL ||
+ (session->internals.priorities->server_precedence && serv_ec_idx < serv_dh_idx) ||
+ (!session->internals.priorities->server_precedence && cli_ec_pos < cli_dh_pos)) {
+ session->internals.cand_group = session->internals.cand_ec_group;
+ }
+ }
+
+ if (session->internals.cand_group)
+ _gnutls_handshake_log("EXT[%p]: Selected group %s\n", session, session->internals.cand_group->name);
+
+ if (have_ffdhe)
+ session->internals.hsk_flags |= HSK_HAVE_FFDHE;
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_supported_groups_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ unsigned len, i;
+ int ret;
+ uint16_t p;
+
+ /* this extension is only being sent on client side */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+
+ len = session->internals.priorities->groups.size;
+ if (len > 0) {
+ ret =
+ _gnutls_buffer_append_prefix(extdata, 16,
+ len * 2);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ for (i = 0; i < len; i++) {
+ p = session->internals.priorities->groups.entry[i]->tls_id;
+
+ _gnutls_handshake_log("EXT[%p]: Sent group %s (0x%x)\n", session,
+ session->internals.priorities->groups.entry[i]->name, (unsigned)p);
+
+ ret =
+ _gnutls_buffer_append_prefix(extdata,
+ 16, p);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ return (len + 1) * 2;
+ }
+
+ }
+
+ return 0;
+}
+
+/* Returns 0 if the given ECC curve is allowed in the current
+ * session. A negative error value is returned otherwise.
+ */
+int
+_gnutls_session_supports_group(gnutls_session_t session,
+ unsigned int group)
+{
+ unsigned i;
+
+ for (i = 0; i < session->internals.priorities->groups.size; i++) {
+ if (session->internals.priorities->groups.entry[i]->id == group)
+ return 0;
+ }
+
+ return GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+}
diff --git a/lib/ext/supported_groups.h b/lib/ext/supported_groups.h
new file mode 100644
index 0000000..769b3be
--- /dev/null
+++ b/lib/ext/supported_groups.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SUPPORTED_GROUPS_H
+#define GNUTLS_LIB_EXT_SUPPORTED_GROUPS_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_supported_groups;
+
+int
+_gnutls_session_supports_group(gnutls_session_t session,
+ unsigned int group);
+
+#endif /* GNUTLS_LIB_EXT_SUPPORTED_GROUPS_H */
diff --git a/lib/ext/supported_versions.c b/lib/ext/supported_versions.c
new file mode 100644
index 0000000..157a0a7
--- /dev/null
+++ b/lib/ext/supported_versions.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains the code for the Max Record Size TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "num.h"
+#include <hello_ext.h>
+#include <ext/supported_versions.h>
+#include "handshake.h"
+
+static int supported_versions_recv_params(gnutls_session_t session,
+ const uint8_t * data,
+ size_t data_size);
+static int supported_versions_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata);
+
+const hello_ext_entry_st ext_mod_supported_versions = {
+ .name = "Supported Versions",
+ .tls_id = 43,
+ .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS,
+ .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
+ GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_HRR|GNUTLS_EXT_FLAG_TLS,
+ .client_parse_point = GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */
+ .server_parse_point = GNUTLS_EXT_VERSION_NEG,
+ .recv_func = supported_versions_recv_params,
+ .send_func = supported_versions_send_params,
+ .pack_func = NULL,
+ .unpack_func = NULL,
+ .deinit_func = NULL,
+ .cannot_be_overriden = 1
+};
+
+static int
+supported_versions_recv_params(gnutls_session_t session,
+ const uint8_t * data, size_t data_size)
+{
+ const version_entry_st *vers;
+ uint8_t major, minor;
+ size_t bytes;
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ const version_entry_st *old_vers;
+ const version_entry_st *cli_vers = NULL;
+
+ vers = _gnutls_version_max(session);
+ old_vers = get_version(session);
+
+ /* do not parse this extension when we haven't TLS1.3
+ * enabled. That is because we cannot handle earlier protocol
+ * negotiation (such as SSL3.0) with this */
+ if (vers && !vers->tls13_sem)
+ return 0;
+
+ DECR_LEN(data_size, 1);
+ bytes = data[0];
+ data++;
+
+ if (bytes % 2 == 1)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ DECR_LEN(data_size, bytes);
+
+ if (data_size != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ while (bytes > 0) {
+ major = data[0];
+ minor = data[1];
+ data += 2;
+ bytes -= 2;
+
+ _gnutls_handshake_log("EXT[%p]: Found version: %d.%d\n",
+ session, (int)major, (int)minor);
+
+ if (!_gnutls_nversion_is_supported(session, major, minor))
+ continue;
+
+ /* Prefer the latest possible version
+ * regardless of the client's precedence. See
+ * https://gitlab.com/gnutls/gnutls/issues/837
+ * for the rationale.
+ */
+ if (!cli_vers ||
+ major > cli_vers->major ||
+ (major == cli_vers->major &&
+ minor > cli_vers->minor))
+ cli_vers = nversion_to_entry(major, minor);
+ }
+
+ if (!cli_vers)
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
+
+ session->security_parameters.pversion = cli_vers;
+
+ _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
+ session,
+ (int)cli_vers->major,
+ (int)cli_vers->minor);
+
+ if (old_vers != cli_vers) {
+ /* regenerate the random value to set
+ * downgrade sentinel if necessary
+ */
+ ret = _gnutls_gen_server_random(session, cli_vers->id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ return 0;
+ } else { /* client */
+
+ if (!have_creds_for_tls13(session)) {
+ /* if we don't have certificate or PSK (which work under TLS1.3)
+ * don't try to negotiate version using the extension. We fallback
+ * instead to the normal TLS negotiation which has a cap on TLS1.2.
+ */
+ return 0;
+ }
+
+ DECR_LEN(data_size, 2);
+
+ if (data_size != 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ major = data[0];
+ minor = data[1];
+
+ vers = nversion_to_entry(major, minor);
+ if (!vers)
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
+
+ set_adv_version(session, major, minor);
+
+ _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
+ session, (int)major, (int)minor);
+
+ if (!vers->tls13_sem)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ ret = _gnutls_negotiate_version(session, major, minor, 1);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+supported_versions_send_params(gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ uint8_t versions[32];
+ size_t versions_size;
+ const version_entry_st *vers;
+ int ret;
+
+ /* this function sends the client extension data (dnsname) */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ vers = _gnutls_version_max(session);
+
+ /* Do not advertise this extension if we are not doing certificate
+ * or PSK authentication; i.e., do not try to do TLS1.3 if we have
+ * credentials which do not fit it. */
+ if (!have_creds_for_tls13(session)) {
+ /* if we don't have certificate or PSK (which work under TLS1.3)
+ * don't try to negotiate version using the extension. We fallback
+ * instead to the normal TLS negotiation which has a cap on TLS1.2.
+ */
+ return 0;
+ }
+
+ /* do not advertise this extension when we haven't TLS1.3
+ * enabled. */
+ if (vers && !vers->tls13_sem)
+ return 0;
+
+ ret = _gnutls_write_supported_versions(session, versions, sizeof(versions));
+ if (ret <= 0) /* if this function doesn't succeed do not send anything */
+ return 0;
+
+ versions_size = ret;
+
+ ret = _gnutls_buffer_append_data_prefix(extdata, 8, versions, versions_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return versions_size+2;
+ } else {
+ vers = get_version(session);
+ if (unlikely(vers == NULL))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ /* don't use this extension to negotiate versions <= 1.2,
+ * pretend we don't support it, so that we use a single
+ * code path to negotiate these protocols. */
+ if (!vers->tls13_sem)
+ return 0;
+
+ ret = _gnutls_buffer_append_data(extdata, &vers->major, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/lib/ext/supported_versions.h b/lib/ext/supported_versions.h
new file mode 100644
index 0000000..f7dfb9e
--- /dev/null
+++ b/lib/ext/supported_versions.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_EXT_SUPPORTED_VERSIONS_H
+#define GNUTLS_LIB_EXT_SUPPORTED_VERSIONS_H
+
+#include <hello_ext.h>
+
+extern const hello_ext_entry_st ext_mod_supported_versions;
+
+#endif /* GNUTLS_LIB_EXT_SUPPORTED_VERSIONS_H */