summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Josefsson <simon@josefsson.org>2005-12-15 10:52:19 +0000
committerSimon Josefsson <simon@josefsson.org>2005-12-15 10:52:19 +0000
commit3860714e697158a17086fff6a87fa9d22877895a (patch)
treedb6ae00dc003790ce52fc23fb7c100db8498ffeb
parent1b6f0a191d7dd2ab25da837494a53992e01b9229 (diff)
downloadgnutls-3860714e697158a17086fff6a87fa9d22877895a.tar.gz
Add TLS/IA support.
-rw-r--r--NEWS57
-rw-r--r--doc/Makefile.am21
-rw-r--r--doc/examples/ex-client-tlsia.c161
-rw-r--r--doc/gnutls.texi64
-rw-r--r--doc/manpages/Makefile.am2
-rw-r--r--includes/gnutls/extra.h81
-rw-r--r--includes/gnutls/gnutls.h.in24
-rw-r--r--lib/Makefile.am8
-rw-r--r--lib/debug.c2
-rw-r--r--lib/defines.h1
-rw-r--r--lib/ext_inner_application.c121
-rw-r--r--lib/ext_inner_application.h29
-rw-r--r--lib/gnutls_alert.c4
-rw-r--r--lib/gnutls_buffers.c64
-rw-r--r--lib/gnutls_constate.c3
-rw-r--r--lib/gnutls_errors.c8
-rw-r--r--lib/gnutls_extensions.c22
-rw-r--r--lib/gnutls_int.h16
-rw-r--r--lib/gnutls_kx.c4
-rw-r--r--lib/gnutls_record.c26
-rw-r--r--lib/gnutls_state.c2
-rw-r--r--libextra/Makefile.am31
-rw-r--r--libextra/gnutls_ia.c916
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/tlsia.c575
25 files changed, 2181 insertions, 67 deletions
diff --git a/NEWS b/NEWS
index ef470be4e1..161cfda7b8 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,11 @@ See the end for copying conditions.
* Version 1.3.2 (unreleased)
+** GnuTLS now support TLS Inner application (TLS/IA).
+This is per draft-funk-tls-inner-application-extension-01. This
+functionality is added to libgnutls-extra, so it is licensed under the
+GPL.
+
** Internal type cleanups.
The uint8, uint16, uint32 types have been replaced by uint8_t,
uint16_t, uint32_t. Gnulib is used to guarantee the presence of
@@ -12,7 +17,57 @@ correct types on platforms that lack them. The uint type have been
replaced by unsigned.
** API and ABI modifications:
-None
+New function, to perform TLS/IA handshake:
+ gnutls_ia_handshake
+
+New function to decide whether to do a TLS/IA handshake:
+ gnutls_ia_handshake_p
+
+New functions to allocate a TLS/IA credential:
+ gnutls_ia_allocate_client_credentials
+ gnutls_ia_free_client_credentials
+ gnutls_ia_allocate_server_credentials
+ gnutls_ia_free_server_credentials
+
+New functions to handle the AVP callback:
+ gnutls_ia_set_client_avp_function
+ gnutls_ia_set_client_avp_ptr
+ gnutls_ia_get_client_avp_ptr
+ gnutls_ia_set_server_avp_function
+ gnutls_ia_set_server_avp_ptr
+ gnutls_ia_get_server_avp_ptr
+
+New functions, to toggle TLS/IA application phases:
+ gnutls_ia_require_inner_phase
+
+New function to mix session keys with inner secret:
+ gnutls_ia_permute_inner_secret
+
+Low-level API:
+ gnutls_ia_endphase_send
+ gnutls_ia_send
+ gnutls_ia_recv
+
+New functions that can be used after successful TLS/IA negotiation:
+ gnutls_ia_generate_challenge
+ gnutls_ia_extract_inner_secret
+
+Enum type with TLS/IA modes:
+ gnutls_ia_mode_t
+
+Enum type with TLS/IA packet types:
+ gnutls_ia_apptype_t
+
+Enum values for TLS/IA alerts:
+ GNUTLS_A_INNER_APPLICATION_FAILURE
+ GNUTLS_A_INNER_APPLICATION_VERIFICATION
+
+New error codes, to signal when an application phase has finished:
+ GNUTLS_E_WARNING_IA_IPHF_RECEIVED
+ GNUTLS_E_WARNING_IA_FPHF_RECEIVED
+
+New error code to signal TLS/IA verify failure:
+ GNUTLS_E_IA_VERIFY_FAILED
* Version 1.3.1 (released 2005-12-08)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 1056f2124b..81e433ada3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -27,13 +27,14 @@ SUBDIRS += reference
endif
info_TEXINFOS = gnutls.texi
-gnutls_TEXINFOS = gnutls.texi signatures.texi fdl.texi error_codes.texi bibliography.texi \
- gnutls-api.texi gnutls-extra-api.texi x509-api.texi \
- my-bib-macros.texi internals.texi \
- pgp-api.texi examples/ex-client1.c examples/ex-client2.c \
- examples/ex-session-info.c examples/ex-verify.c \
- examples/ex-cert-select.c examples/ex-client-resume.c \
- examples/ex-client-srp.c examples/ex-rfc2818.c \
+gnutls_TEXINFOS = gnutls.texi signatures.texi fdl.texi \
+ error_codes.texi bibliography.texi gnutls-api.texi \
+ gnutls-extra-api.texi ia-api.texi x509-api.texi pgp-api.texi \
+ my-bib-macros.texi internals.texi examples/ex-client1.c \
+ examples/ex-client2.c examples/ex-session-info.c \
+ examples/ex-verify.c examples/ex-cert-select.c \
+ examples/ex-client-resume.c examples/ex-client-srp.c \
+ examples/ex-client-tlsia.c examples/ex-rfc2818.c \
examples/ex-serv1.c examples/ex-serv-export.c \
examples/ex-serv-anon.c examples/ex-serv-pgp.c \
examples/ex-serv-srp.c examples/ex-alert.c \
@@ -55,6 +56,9 @@ AM_MAKEINFOHTMLFLAGS = --no-split
../libextra/openpgp/pgp-api.texi:
cd ../libextra/openpgp && make pgp-api.texi
+../libextra/ia-api.texi:
+ cd ../libextra && make ia-api.texi
+
gnutls-api.texi: ../lib/gnutls-api.texi
-scripts/sort2.pl < ../lib/gnutls-api.texi > gnutls-api.texi
@@ -67,5 +71,8 @@ x509-api.texi: ../lib/x509/x509-api.texi
pgp-api.texi: ../libextra/openpgp/pgp-api.texi
-scripts/sort2.pl < ../libextra/openpgp/pgp-api.texi > pgp-api.texi
+ia-api.texi: ../libextra/ia-api.texi
+ -scripts/sort2.pl < ../libextra/ia-api.texi > ia-api.texi
+
error_codes.texi: ../lib/gnutls_errors.c ../src/errcodes.c
-../src/errcodes > error_codes.texi
diff --git a/doc/examples/ex-client-tlsia.c b/doc/examples/ex-client-tlsia.c
new file mode 100644
index 0000000000..d63e7fb4bd
--- /dev/null
+++ b/doc/examples/ex-client-tlsia.c
@@ -0,0 +1,161 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+
+/* A basic TLS client, with anonymous authentication and TLS/IA handshake.
+ */
+
+#define MAX_BUF 1024
+#define SA struct sockaddr
+#define MSG "GET / HTTP/1.0\r\n\r\n"
+
+extern int tcp_connect (void);
+extern void tcp_close (int sd);
+
+int
+client_avp (gnutls_session_t session, void *ptr,
+ const char *last, size_t lastlen,
+ char **new, size_t *newlen)
+{
+
+ if (last)
+ printf ("- received %d bytes AVP: `%.*s'\n",
+ lastlen, lastlen, last);
+ else
+ printf ("- new application phase\n");
+
+ *new = gnutls_strdup ("client avp");
+ if (!*new)
+ return -1;
+ *newlen = strlen (*new);
+
+ printf ("- sending %d bytes AVP: `%s'\n", *newlen, *new);
+
+ gnutls_ia_permute_inner_secret (session, 3, "foo");
+
+ return 0;
+
+}
+
+int
+main (void)
+{
+ int ret, sd, ii;
+ gnutls_session_t session;
+ char buffer[MAX_BUF + 1];
+ gnutls_anon_client_credentials_t anoncred;
+ gnutls_ia_client_credentials_t iacred;
+ /* Need to enable anonymous KX specifically. */
+ const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
+
+ gnutls_global_init ();
+
+ gnutls_anon_allocate_client_credentials (&anoncred);
+ gnutls_ia_allocate_client_credentials (&iacred);
+
+ /* Set TLS/IA stuff
+ */
+ gnutls_ia_set_client_avp_function (iacred, client_avp);
+
+ /* Initialize TLS session
+ */
+ gnutls_init (&session, GNUTLS_CLIENT);
+
+ /* Use default priorities */
+ gnutls_set_default_priority (session);
+ gnutls_kx_set_priority (session, kx_prio);
+
+ /* put the anonymous and TLS/IA credentials to the current session
+ */
+ gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+ gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
+
+ /* connect to the peer
+ */
+ sd = tcp_connect ();
+
+ gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
+
+ /* Perform the TLS handshake
+ */
+ ret = gnutls_handshake (session);
+
+ if (ret < 0)
+ {
+ fprintf (stderr, "*** Handshake failed\n");
+ gnutls_perror (ret);
+ goto end;
+ }
+ else
+ {
+ printf ("- Handshake was completed\n");
+ }
+
+ if (!gnutls_ia_handshake_p (session))
+ {
+ fprintf (stderr, "*** TLS/IA not negotiated...\n");
+ goto end;
+ }
+ else
+ {
+ printf ("- Starting TLS/IA handshake...\n");
+
+ ret = gnutls_ia_handshake (session);
+
+ if (ret < 0)
+ {
+ fprintf (stderr, "*** TLS/IA handshake failed\n");
+ gnutls_perror (ret);
+ goto end;
+ }
+ else
+ {
+ printf ("- TLS/IA Handshake was completed\n");
+ }
+ }
+
+
+ gnutls_record_send (session, MSG, strlen (MSG));
+
+ ret = gnutls_record_recv (session, buffer, MAX_BUF);
+ if (ret == 0)
+ {
+ printf ("- Peer has closed the TLS connection\n");
+ goto end;
+ }
+ else if (ret < 0)
+ {
+ fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
+ goto end;
+ }
+
+ printf ("- Received %d bytes: ", ret);
+ for (ii = 0; ii < ret; ii++)
+ {
+ fputc (buffer[ii], stdout);
+ }
+ fputs ("\n", stdout);
+
+ gnutls_bye (session, GNUTLS_SHUT_RDWR);
+
+end:
+
+ tcp_close (sd);
+
+ gnutls_deinit (session);
+
+ gnutls_ia_free_client_credentials (iacred);
+ gnutls_anon_free_client_credentials (anoncred);
+
+ gnutls_global_deinit ();
+
+ return 0;
+}
diff --git a/doc/gnutls.texi b/doc/gnutls.texi
index 2a7927ab90..8daa898c17 100644
--- a/doc/gnutls.texi
+++ b/doc/gnutls.texi
@@ -2510,6 +2510,7 @@ signing_key
* X.509 certificate functions::
* GnuTLS-extra functions::
* OpenPGP functions::
+* TLS Inner Application (TLS/IA) functions::
* Error codes and descriptions::
@end menu
@@ -2546,11 +2547,70 @@ called @code{gnutls-extra}. The prototypes for this library lie in
@cindex @acronym{OpenPGP} functions
@anchor{sec:openpgpapi}
-The following functions are to be used for @acronym{OpenPGP} certificate
-handling. Their prototypes lie in @file{gnutls/openpgp.h}.
+The following functions are to be used for @acronym{OpenPGP}
+certificate handling. Their prototypes lie in
+@file{gnutls/openpgp.h}. You need to link with @file{libgnutls-extra}
+to be able to use these functions (@pxref{GnuTLS-extra functions}).
@include pgp-api.texi
+@node TLS Inner Application (TLS/IA) functions
+@section @acronym{TLS} Inner Application (@acronym{TLS/IA}) functions
+@cindex @acronym{TLS} Inner Application (@acronym{TLS/IA}) functions
+@cindex Inner Application (@acronym{TLS/IA}) functions
+
+The following functions are used for @acronym{TLS} Inner Application
+(@acronym{TLS/IA}). Their prototypes lie in @file{gnutls/extra.h}.
+You need to link with @file{libgnutls-extra} to be able to use these
+functions (@pxref{GnuTLS-extra functions}).
+
+The typical control flow in an TLS/IA client (that would not require
+an Application Phase for resumed sessions) would be similar to the
+following:
+
+@example
+int client_avp (gnuls_session_t *session, void *ptr,
+ const char *last, size_t lastlen,
+ char **new, size_t *newlen)
+@{
+...
+@}
+...
+int main ()
+@{
+ gnutls_ia_client_credentials_t iacred;
+...
+ gnutls_init (&session, GNUTLS_CLIENT);
+...
+ /* Enable TLS/IA. */
+ gnutls_ia_allocate_client_credentials(&iacred);
+ gnutls_ia_set_client_avp_function(iacred, client_avp);
+ gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
+...
+ ret = gnutls_handshake (session);
+ // Error handling...
+...
+ if (gnutls_ia_handshake_p (session))
+ @{
+ ret = gnutls_ia_handshake (session);
+ // Error handling...
+...
+@end example
+
+See below for detailed descriptions of all the functions used above.
+
+The function @code{client_avp} would have to be implemented by your
+application. The function is responsible for handling the AVP data.
+See @code{gnutls_ia_set_client_avp_function} below for more
+information on how that function should be implemented.
+
+The control flow in a typical server is similar to the above, use
+@code{gnutls_ia_server_credentials_t} instead of
+@code{gnutls_ia_client_credentials_t}, and replace the call to the
+client functions with the corresponding server functions.
+
+@include ia-api.texi
+
@node Error codes and descriptions
@section Error codes and descriptions
@anchor{Error Codes}
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index c34244ed36..1e0fc195fa 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -26,7 +26,7 @@ if ENABLE_SRP
dist_man_MANS += srptool.1
endif
-APIMANS = gnutls_server_name_get.3 gnutls_server_name_set.3 gnutls_alert_get_name.3 gnutls_alert_send.3 gnutls_error_to_alert.3 gnutls_alert_send_appropriate.3 gnutls_alert_get.3 gnutls_mac_get_name.3 gnutls_compression_get_name.3 gnutls_cipher_get_key_size.3 gnutls_cipher_get_name.3 gnutls_kx_get_name.3 gnutls_protocol_get_name.3 gnutls_cipher_suite_get_name.3 gnutls_certificate_type_get_name.3 gnutls_sign_algorithm_get_name.3 gnutls_pk_algorithm_get_name.3 gnutls_anon_free_server_credentials.3 gnutls_anon_allocate_server_credentials.3 gnutls_anon_free_client_credentials.3 gnutls_anon_allocate_client_credentials.3 gnutls_anon_set_server_dh_params.3 gnutls_anon_set_server_params_function.3 gnutls_credentials_clear.3 gnutls_credentials_set.3 gnutls_auth_get_type.3 gnutls_auth_server_get_type.3 gnutls_auth_client_get_type.3 gnutls_record_check_pending.3 gnutls_certificate_free_keys.3 gnutls_certificate_free_cas.3 gnutls_certificate_free_ca_names.3 gnutls_certificate_free_credentials.3 gnutls_certificate_allocate_credentials.3 gnutls_certificate_server_set_request.3 gnutls_certificate_client_set_retrieve_function.3 gnutls_certificate_server_set_retrieve_function.3 gnutls_certificate_verify_peers2.3 gnutls_certificate_verify_peers.3 gnutls_certificate_expiration_time_peers.3 gnutls_certificate_activation_time_peers.3 gnutls_db_set_retrieve_function.3 gnutls_db_set_remove_function.3 gnutls_db_set_store_function.3 gnutls_db_set_ptr.3 gnutls_db_get_ptr.3 gnutls_db_set_cache_expiration.3 gnutls_db_check_entry.3 gnutls_db_remove_session.3 gnutls_dh_params_import_raw.3 gnutls_dh_params_init.3 gnutls_dh_params_deinit.3 gnutls_dh_params_cpy.3 gnutls_dh_params_generate2.3 gnutls_dh_params_import_pkcs3.3 gnutls_dh_params_export_pkcs3.3 gnutls_dh_params_export_raw.3 gnutls_error_is_fatal.3 gnutls_perror.3 gnutls_strerror.3 gnutls_global_set_log_function.3 gnutls_global_set_log_level.3 gnutls_global_set_mem_functions.3 gnutls_global_init.3 gnutls_global_deinit.3 gnutls_transport_set_pull_function.3 gnutls_transport_set_push_function.3 gnutls_check_version.3 gnutls_rehandshake.3 gnutls_handshake.3 gnutls_handshake_set_max_packet_length.3 gnutls_handshake_get_last_in.3 gnutls_handshake_get_last_out.3 gnutls_malloc.3 gnutls_free.3 gnutls_cipher_set_priority.3 gnutls_kx_set_priority.3 gnutls_mac_set_priority.3 gnutls_compression_set_priority.3 gnutls_protocol_set_priority.3 gnutls_certificate_type_set_priority.3 gnutls_set_default_priority.3 gnutls_set_default_export_priority.3 gnutls_psk_free_client_credentials.3 gnutls_psk_allocate_client_credentials.3 gnutls_psk_set_client_credentials.3 gnutls_psk_free_server_credentials.3 gnutls_psk_allocate_server_credentials.3 gnutls_psk_set_server_credentials_file.3 gnutls_psk_set_server_credentials_function.3 gnutls_psk_set_client_credentials_function.3 gnutls_psk_server_get_username.3 gnutls_hex_decode.3 gnutls_hex_encode.3 gnutls_psk_set_server_dh_params.3 gnutls_psk_set_server_params_function.3 gnutls_protocol_get_version.3 gnutls_transport_set_lowat.3 gnutls_transport_set_ptr.3 gnutls_transport_set_ptr2.3 gnutls_transport_get_ptr.3 gnutls_transport_get_ptr2.3 gnutls_bye.3 gnutls_record_send.3 gnutls_record_recv.3 gnutls_record_get_max_size.3 gnutls_record_set_max_size.3 gnutls_rsa_params_import_raw.3 gnutls_rsa_params_init.3 gnutls_rsa_params_deinit.3 gnutls_rsa_params_cpy.3 gnutls_rsa_params_generate2.3 gnutls_rsa_params_import_pkcs1.3 gnutls_rsa_params_export_pkcs1.3 gnutls_rsa_params_export_raw.3 gnutls_session_get_data.3 gnutls_session_get_data2.3 gnutls_session_get_id.3 gnutls_session_set_data.3 gnutls_cipher_get.3 gnutls_certificate_type_get.3 gnutls_kx_get.3 gnutls_mac_get.3 gnutls_compression_get.3 gnutls_init.3 gnutls_deinit.3 gnutls_openpgp_send_key.3 gnutls_certificate_send_x509_rdn_sequence.3 gnutls_handshake_set_private_extensions.3 gnutls_session_is_resumed.3 gnutls_session_get_ptr.3 gnutls_session_set_ptr.3 gnutls_record_get_direction.3 gnutls_dh_set_prime_bits.3 gnutls_dh_get_group.3 gnutls_dh_get_pubkey.3 gnutls_rsa_export_get_pubkey.3 gnutls_dh_get_secret_bits.3 gnutls_dh_get_prime_bits.3 gnutls_rsa_export_get_modulus_bits.3 gnutls_dh_get_peers_public_bits.3 gnutls_certificate_get_ours.3 gnutls_certificate_get_peers.3 gnutls_certificate_client_get_request_status.3 gnutls_fingerprint.3 gnutls_certificate_set_dh_params.3 gnutls_certificate_set_params_function.3 gnutls_certificate_set_verify_flags.3 gnutls_certificate_set_verify_limits.3 gnutls_certificate_set_rsa_export_params.3 gnutls_certificate_set_x509_key_mem.3 gnutls_certificate_set_x509_key.3 gnutls_certificate_set_x509_key_file.3 gnutls_certificate_set_x509_trust_mem.3 gnutls_certificate_set_x509_trust.3 gnutls_certificate_set_x509_trust_file.3 gnutls_certificate_set_x509_crl_mem.3 gnutls_certificate_set_x509_crl.3 gnutls_certificate_set_x509_crl_file.3 gnutls_certificate_set_x509_simple_pkcs12_file.3 gnutls_certificate_free_crls.3 gnutls_pem_base64_encode.3 gnutls_pem_base64_encode_alloc.3 gnutls_pem_base64_decode.3 gnutls_pem_base64_decode_alloc.3 gnutls_global_init_extra.3 gnutls_extra_check_version.3 gnutls_certificate_set_openpgp_key_mem.3 gnutls_certificate_set_openpgp_key_file.3 gnutls_certificate_set_openpgp_keyring_file.3 gnutls_certificate_set_openpgp_keyring_mem.3 gnutls_certificate_set_openpgp_keyserver.3 gnutls_certificate_set_openpgp_trustdb.3 gnutls_openpgp_set_recv_key_function.3 gnutls_certificate_set_openpgp_key.3 gnutls_x509_dn_oid_known.3 gnutls_x509_crl_init.3 gnutls_x509_crl_deinit.3 gnutls_x509_crl_import.3 gnutls_x509_crl_get_issuer_dn.3 gnutls_x509_crl_get_issuer_dn_by_oid.3 gnutls_x509_crl_get_dn_oid.3 gnutls_x509_crl_get_signature_algorithm.3 gnutls_x509_crl_get_version.3 gnutls_x509_crl_get_this_update.3 gnutls_x509_crl_get_next_update.3 gnutls_x509_crl_get_crt_count.3 gnutls_x509_crl_get_crt_serial.3 gnutls_x509_crl_export.3 gnutls_x509_crl_set_version.3 gnutls_x509_crl_sign2.3 gnutls_x509_crl_sign.3 gnutls_x509_crl_set_this_update.3 gnutls_x509_crl_set_next_update.3 gnutls_x509_crl_set_crt_serial.3 gnutls_x509_crl_set_crt.3 gnutls_x509_crq_init.3 gnutls_x509_crq_deinit.3 gnutls_x509_crq_import.3 gnutls_x509_crq_get_dn.3 gnutls_x509_crq_get_dn_by_oid.3 gnutls_x509_crq_get_dn_oid.3 gnutls_x509_crq_get_challenge_password.3 gnutls_x509_crq_set_attribute_by_oid.3 gnutls_x509_crq_get_attribute_by_oid.3 gnutls_x509_crq_set_dn_by_oid.3 gnutls_x509_crq_set_version.3 gnutls_x509_crq_get_version.3 gnutls_x509_crq_set_key.3 gnutls_x509_crq_set_challenge_password.3 gnutls_x509_crq_sign2.3 gnutls_x509_crq_sign.3 gnutls_x509_crq_export.3 gnutls_x509_crq_get_pk_algorithm.3 gnutls_x509_rdn_get.3 gnutls_x509_rdn_get_by_oid.3 gnutls_x509_rdn_get_oid.3 gnutls_pkcs12_bag_init.3 gnutls_pkcs12_bag_deinit.3 gnutls_pkcs12_bag_get_type.3 gnutls_pkcs12_bag_get_count.3 gnutls_pkcs12_bag_get_data.3 gnutls_pkcs12_bag_set_data.3 gnutls_pkcs12_bag_set_crt.3 gnutls_pkcs12_bag_set_crl.3 gnutls_pkcs12_bag_set_key_id.3 gnutls_pkcs12_bag_get_key_id.3 gnutls_pkcs12_bag_get_friendly_name.3 gnutls_pkcs12_bag_set_friendly_name.3 gnutls_pkcs12_bag_decrypt.3 gnutls_pkcs12_bag_encrypt.3 gnutls_pkcs12_init.3 gnutls_pkcs12_deinit.3 gnutls_pkcs12_import.3 gnutls_pkcs12_export.3 gnutls_pkcs12_get_bag.3 gnutls_pkcs12_set_bag.3 gnutls_pkcs12_generate_mac.3 gnutls_pkcs12_verify_mac.3 gnutls_pkcs7_init.3 gnutls_pkcs7_deinit.3 gnutls_pkcs7_import.3 gnutls_pkcs7_get_crt_raw.3 gnutls_pkcs7_get_crt_count.3 gnutls_pkcs7_export.3 gnutls_pkcs7_set_crt_raw.3 gnutls_pkcs7_set_crt.3 gnutls_pkcs7_delete_crt.3 gnutls_pkcs7_get_crl_raw.3 gnutls_pkcs7_get_crl_count.3 gnutls_pkcs7_set_crl_raw.3 gnutls_pkcs7_set_crl.3 gnutls_pkcs7_delete_crl.3 gnutls_x509_privkey_init.3 gnutls_x509_privkey_deinit.3 gnutls_x509_privkey_cpy.3 gnutls_x509_privkey_import.3 gnutls_x509_privkey_import_rsa_raw.3 gnutls_x509_privkey_import_dsa_raw.3 gnutls_x509_privkey_get_pk_algorithm.3 gnutls_x509_privkey_export.3 gnutls_x509_privkey_export_rsa_raw.3 gnutls_x509_privkey_export_dsa_raw.3 gnutls_x509_privkey_generate.3 gnutls_x509_privkey_get_key_id.3 gnutls_x509_privkey_sign_data.3 gnutls_x509_privkey_verify_data.3 gnutls_x509_privkey_fix.3 gnutls_x509_privkey_export_pkcs8.3 gnutls_x509_privkey_import_pkcs8.3 gnutls_x509_crt_check_hostname.3 gnutls_x509_crt_check_issuer.3 gnutls_x509_crt_list_verify.3 gnutls_x509_crt_verify.3 gnutls_x509_crl_check_issuer.3 gnutls_x509_crl_verify.3 gnutls_x509_crt_init.3 gnutls_x509_crt_deinit.3 gnutls_x509_crt_import.3 gnutls_x509_crt_get_issuer_dn.3 gnutls_x509_crt_get_issuer_dn_by_oid.3 gnutls_x509_crt_get_issuer_dn_oid.3 gnutls_x509_crt_get_dn.3 gnutls_x509_crt_get_dn_by_oid.3 gnutls_x509_crt_get_dn_oid.3 gnutls_x509_crt_get_signature_algorithm.3 gnutls_x509_crt_get_version.3 gnutls_x509_crt_get_activation_time.3 gnutls_x509_crt_get_expiration_time.3 gnutls_x509_crt_get_serial.3 gnutls_x509_crt_get_subject_key_id.3 gnutls_x509_crt_get_authority_key_id.3 gnutls_x509_crt_get_pk_algorithm.3 gnutls_x509_crt_get_subject_alt_name.3 gnutls_x509_crt_get_ca_status.3 gnutls_x509_crt_get_key_usage.3 gnutls_x509_crt_get_extension_by_oid.3 gnutls_x509_crt_get_extension_oid.3 gnutls_x509_crt_get_fingerprint.3 gnutls_x509_crt_export.3 gnutls_x509_crt_get_key_id.3 gnutls_x509_crt_check_revocation.3 gnutls_x509_crt_verify_data.3 gnutls_x509_crt_get_crl_dist_points.3 gnutls_x509_crt_get_key_purpose_oid.3 gnutls_x509_crt_get_pk_rsa_raw.3 gnutls_x509_crt_get_pk_dsa_raw.3 gnutls_x509_crt_list_import.3 gnutls_x509_crt_set_dn_by_oid.3 gnutls_x509_crt_set_issuer_dn_by_oid.3 gnutls_x509_crt_set_version.3 gnutls_x509_crt_set_key.3 gnutls_x509_crt_set_crq.3 gnutls_x509_crt_set_extension_by_oid.3 gnutls_x509_crt_set_ca_status.3 gnutls_x509_crt_set_key_usage.3 gnutls_x509_crt_set_subject_alternative_name.3 gnutls_x509_crt_sign2.3 gnutls_x509_crt_sign.3 gnutls_x509_crt_set_activation_time.3 gnutls_x509_crt_set_expiration_time.3 gnutls_x509_crt_set_serial.3 gnutls_x509_crt_set_crl_dist_points.3 gnutls_x509_crt_cpy_crl_dist_points.3 gnutls_x509_crt_set_subject_key_id.3 gnutls_x509_crt_set_authority_key_id.3 gnutls_x509_crt_set_key_purpose_oid.3 gnutls_x509_crt_to_xml.3 gnutls_openpgp_keyring_init.3 gnutls_openpgp_keyring_deinit.3 gnutls_openpgp_keyring_check_id.3 gnutls_openpgp_keyring_import.3 gnutls_openpgp_trustdb_init.3 gnutls_openpgp_trustdb_deinit.3 gnutls_openpgp_trustdb_import_file.3 gnutls_openpgp_key_init.3 gnutls_openpgp_key_deinit.3 gnutls_openpgp_key_import.3 gnutls_openpgp_key_export.3 gnutls_openpgp_key_get_fingerprint.3 gnutls_openpgp_key_get_name.3 gnutls_openpgp_key_get_pk_algorithm.3 gnutls_openpgp_key_get_version.3 gnutls_openpgp_key_get_creation_time.3 gnutls_openpgp_key_get_expiration_time.3 gnutls_openpgp_key_get_id.3 gnutls_openpgp_key_check_hostname.3 gnutls_openpgp_key_get_key_usage.3 gnutls_openpgp_key_verify_ring.3 gnutls_openpgp_key_verify_self.3 gnutls_openpgp_key_verify_trustdb.3 gnutls_openpgp_privkey_init.3 gnutls_openpgp_privkey_deinit.3 gnutls_openpgp_privkey_import.3 gnutls_openpgp_privkey_get_pk_algorithm.3 gnutls_openpgp_key_to_xml.3
+APIMANS = gnutls_server_name_get.3 gnutls_server_name_set.3 gnutls_alert_get_name.3 gnutls_alert_send.3 gnutls_error_to_alert.3 gnutls_alert_send_appropriate.3 gnutls_alert_get.3 gnutls_mac_get_name.3 gnutls_compression_get_name.3 gnutls_cipher_get_key_size.3 gnutls_cipher_get_name.3 gnutls_kx_get_name.3 gnutls_protocol_get_name.3 gnutls_cipher_suite_get_name.3 gnutls_certificate_type_get_name.3 gnutls_sign_algorithm_get_name.3 gnutls_pk_algorithm_get_name.3 gnutls_anon_free_server_credentials.3 gnutls_anon_allocate_server_credentials.3 gnutls_anon_free_client_credentials.3 gnutls_anon_allocate_client_credentials.3 gnutls_anon_set_server_dh_params.3 gnutls_anon_set_server_params_function.3 gnutls_credentials_clear.3 gnutls_credentials_set.3 gnutls_auth_get_type.3 gnutls_auth_server_get_type.3 gnutls_auth_client_get_type.3 gnutls_record_check_pending.3 gnutls_certificate_free_keys.3 gnutls_certificate_free_cas.3 gnutls_certificate_free_ca_names.3 gnutls_certificate_free_credentials.3 gnutls_certificate_allocate_credentials.3 gnutls_certificate_server_set_request.3 gnutls_certificate_client_set_retrieve_function.3 gnutls_certificate_server_set_retrieve_function.3 gnutls_certificate_verify_peers2.3 gnutls_certificate_verify_peers.3 gnutls_certificate_expiration_time_peers.3 gnutls_certificate_activation_time_peers.3 gnutls_db_set_retrieve_function.3 gnutls_db_set_remove_function.3 gnutls_db_set_store_function.3 gnutls_db_set_ptr.3 gnutls_db_get_ptr.3 gnutls_db_set_cache_expiration.3 gnutls_db_check_entry.3 gnutls_db_remove_session.3 gnutls_dh_params_import_raw.3 gnutls_dh_params_init.3 gnutls_dh_params_deinit.3 gnutls_dh_params_cpy.3 gnutls_dh_params_generate2.3 gnutls_dh_params_import_pkcs3.3 gnutls_dh_params_export_pkcs3.3 gnutls_dh_params_export_raw.3 gnutls_error_is_fatal.3 gnutls_perror.3 gnutls_strerror.3 gnutls_global_set_log_function.3 gnutls_global_set_log_level.3 gnutls_global_set_mem_functions.3 gnutls_global_init.3 gnutls_global_deinit.3 gnutls_transport_set_pull_function.3 gnutls_transport_set_push_function.3 gnutls_check_version.3 gnutls_rehandshake.3 gnutls_handshake.3 gnutls_handshake_set_max_packet_length.3 gnutls_handshake_get_last_in.3 gnutls_handshake_get_last_out.3 gnutls_malloc.3 gnutls_free.3 gnutls_cipher_set_priority.3 gnutls_kx_set_priority.3 gnutls_mac_set_priority.3 gnutls_compression_set_priority.3 gnutls_protocol_set_priority.3 gnutls_certificate_type_set_priority.3 gnutls_set_default_priority.3 gnutls_set_default_export_priority.3 gnutls_psk_free_client_credentials.3 gnutls_psk_allocate_client_credentials.3 gnutls_psk_set_client_credentials.3 gnutls_psk_free_server_credentials.3 gnutls_psk_allocate_server_credentials.3 gnutls_psk_set_server_credentials_file.3 gnutls_psk_set_server_credentials_function.3 gnutls_psk_set_client_credentials_function.3 gnutls_psk_server_get_username.3 gnutls_hex_decode.3 gnutls_hex_encode.3 gnutls_psk_set_server_dh_params.3 gnutls_psk_set_server_params_function.3 gnutls_protocol_get_version.3 gnutls_transport_set_lowat.3 gnutls_transport_set_ptr.3 gnutls_transport_set_ptr2.3 gnutls_transport_get_ptr.3 gnutls_transport_get_ptr2.3 gnutls_bye.3 gnutls_record_send.3 gnutls_record_recv.3 gnutls_record_get_max_size.3 gnutls_record_set_max_size.3 gnutls_rsa_params_import_raw.3 gnutls_rsa_params_init.3 gnutls_rsa_params_deinit.3 gnutls_rsa_params_cpy.3 gnutls_rsa_params_generate2.3 gnutls_rsa_params_import_pkcs1.3 gnutls_rsa_params_export_pkcs1.3 gnutls_rsa_params_export_raw.3 gnutls_session_get_data.3 gnutls_session_get_data2.3 gnutls_session_get_id.3 gnutls_session_set_data.3 gnutls_cipher_get.3 gnutls_certificate_type_get.3 gnutls_kx_get.3 gnutls_mac_get.3 gnutls_compression_get.3 gnutls_init.3 gnutls_deinit.3 gnutls_openpgp_send_key.3 gnutls_certificate_send_x509_rdn_sequence.3 gnutls_handshake_set_private_extensions.3 gnutls_session_is_resumed.3 gnutls_session_get_ptr.3 gnutls_session_set_ptr.3 gnutls_record_get_direction.3 gnutls_dh_set_prime_bits.3 gnutls_dh_get_group.3 gnutls_dh_get_pubkey.3 gnutls_rsa_export_get_pubkey.3 gnutls_dh_get_secret_bits.3 gnutls_dh_get_prime_bits.3 gnutls_rsa_export_get_modulus_bits.3 gnutls_dh_get_peers_public_bits.3 gnutls_certificate_get_ours.3 gnutls_certificate_get_peers.3 gnutls_certificate_client_get_request_status.3 gnutls_fingerprint.3 gnutls_certificate_set_dh_params.3 gnutls_certificate_set_params_function.3 gnutls_certificate_set_verify_flags.3 gnutls_certificate_set_verify_limits.3 gnutls_certificate_set_rsa_export_params.3 gnutls_psk_set_params_function.3 gnutls_anon_set_params_function.3 gnutls_certificate_set_x509_key_mem.3 gnutls_certificate_set_x509_key.3 gnutls_certificate_set_x509_key_file.3 gnutls_certificate_set_x509_trust_mem.3 gnutls_certificate_set_x509_trust.3 gnutls_certificate_set_x509_trust_file.3 gnutls_certificate_set_x509_crl_mem.3 gnutls_certificate_set_x509_crl.3 gnutls_certificate_set_x509_crl_file.3 gnutls_certificate_set_x509_simple_pkcs12_file.3 gnutls_certificate_free_crls.3 gnutls_pem_base64_encode.3 gnutls_pem_base64_encode_alloc.3 gnutls_pem_base64_decode.3 gnutls_pem_base64_decode_alloc.3 gnutls_global_init_extra.3 gnutls_extra_check_version.3 gnutls_ia_permute_inner_secret.3 gnutls_ia_generate_challenge.3 gnutls_ia_extract_inner_secret.3 gnutls_ia_endphase_send.3 gnutls_ia_verify_endphase.3 gnutls_ia_send.3 gnutls_ia_recv.3 gnutls_ia_handshake_p.3 gnutls_ia_handshake.3 gnutls_ia_allocate_client_credentials.3 gnutls_ia_free_client_credentials.3 gnutls_ia_set_client_avp_function.3 gnutls_ia_set_client_avp_ptr.3 gnutls_ia_get_client_avp_ptr.3 gnutls_ia_allocate_server_credentials.3 gnutls_ia_free_server_credentials.3 gnutls_ia_set_server_avp_function.3 gnutls_ia_set_server_avp_ptr.3 gnutls_ia_get_server_avp_ptr.3 gnutls_ia_require_inner_phase.3 gnutls_certificate_set_openpgp_key_mem.3 gnutls_certificate_set_openpgp_key_file.3 gnutls_certificate_set_openpgp_keyring_file.3 gnutls_certificate_set_openpgp_keyring_mem.3 gnutls_certificate_set_openpgp_keyserver.3 gnutls_certificate_set_openpgp_trustdb.3 gnutls_openpgp_set_recv_key_function.3 gnutls_certificate_set_openpgp_key.3 gnutls_x509_dn_oid_known.3 gnutls_x509_crl_init.3 gnutls_x509_crl_deinit.3 gnutls_x509_crl_import.3 gnutls_x509_crl_get_issuer_dn.3 gnutls_x509_crl_get_issuer_dn_by_oid.3 gnutls_x509_crl_get_dn_oid.3 gnutls_x509_crl_get_signature_algorithm.3 gnutls_x509_crl_get_version.3 gnutls_x509_crl_get_this_update.3 gnutls_x509_crl_get_next_update.3 gnutls_x509_crl_get_crt_count.3 gnutls_x509_crl_get_crt_serial.3 gnutls_x509_crl_export.3 gnutls_x509_crl_set_version.3 gnutls_x509_crl_sign2.3 gnutls_x509_crl_sign.3 gnutls_x509_crl_set_this_update.3 gnutls_x509_crl_set_next_update.3 gnutls_x509_crl_set_crt_serial.3 gnutls_x509_crl_set_crt.3 gnutls_x509_crq_init.3 gnutls_x509_crq_deinit.3 gnutls_x509_crq_import.3 gnutls_x509_crq_get_dn.3 gnutls_x509_crq_get_dn_by_oid.3 gnutls_x509_crq_get_dn_oid.3 gnutls_x509_crq_get_challenge_password.3 gnutls_x509_crq_set_attribute_by_oid.3 gnutls_x509_crq_get_attribute_by_oid.3 gnutls_x509_crq_set_dn_by_oid.3 gnutls_x509_crq_set_version.3 gnutls_x509_crq_get_version.3 gnutls_x509_crq_set_key.3 gnutls_x509_crq_set_challenge_password.3 gnutls_x509_crq_sign2.3 gnutls_x509_crq_sign.3 gnutls_x509_crq_export.3 gnutls_x509_crq_get_pk_algorithm.3 gnutls_x509_rdn_get.3 gnutls_x509_rdn_get_by_oid.3 gnutls_x509_rdn_get_oid.3 gnutls_pkcs12_bag_init.3 gnutls_pkcs12_bag_deinit.3 gnutls_pkcs12_bag_get_type.3 gnutls_pkcs12_bag_get_count.3 gnutls_pkcs12_bag_get_data.3 gnutls_pkcs12_bag_set_data.3 gnutls_pkcs12_bag_set_crt.3 gnutls_pkcs12_bag_set_crl.3 gnutls_pkcs12_bag_set_key_id.3 gnutls_pkcs12_bag_get_key_id.3 gnutls_pkcs12_bag_get_friendly_name.3 gnutls_pkcs12_bag_set_friendly_name.3 gnutls_pkcs12_bag_decrypt.3 gnutls_pkcs12_bag_encrypt.3 gnutls_pkcs12_init.3 gnutls_pkcs12_deinit.3 gnutls_pkcs12_import.3 gnutls_pkcs12_export.3 gnutls_pkcs12_get_bag.3 gnutls_pkcs12_set_bag.3 gnutls_pkcs12_generate_mac.3 gnutls_pkcs12_verify_mac.3 gnutls_pkcs7_init.3 gnutls_pkcs7_deinit.3 gnutls_pkcs7_import.3 gnutls_pkcs7_get_crt_raw.3 gnutls_pkcs7_get_crt_count.3 gnutls_pkcs7_export.3 gnutls_pkcs7_set_crt_raw.3 gnutls_pkcs7_set_crt.3 gnutls_pkcs7_delete_crt.3 gnutls_pkcs7_get_crl_raw.3 gnutls_pkcs7_get_crl_count.3 gnutls_pkcs7_set_crl_raw.3 gnutls_pkcs7_set_crl.3 gnutls_pkcs7_delete_crl.3 gnutls_x509_privkey_init.3 gnutls_x509_privkey_deinit.3 gnutls_x509_privkey_cpy.3 gnutls_x509_privkey_import.3 gnutls_x509_privkey_import_rsa_raw.3 gnutls_x509_privkey_import_dsa_raw.3 gnutls_x509_privkey_get_pk_algorithm.3 gnutls_x509_privkey_export.3 gnutls_x509_privkey_export_rsa_raw.3 gnutls_x509_privkey_export_dsa_raw.3 gnutls_x509_privkey_generate.3 gnutls_x509_privkey_get_key_id.3 gnutls_x509_privkey_sign_data.3 gnutls_x509_privkey_verify_data.3 gnutls_x509_privkey_fix.3 gnutls_x509_privkey_export_pkcs8.3 gnutls_x509_privkey_import_pkcs8.3 gnutls_x509_crt_check_hostname.3 gnutls_x509_crt_check_issuer.3 gnutls_x509_crt_list_verify.3 gnutls_x509_crt_verify.3 gnutls_x509_crl_check_issuer.3 gnutls_x509_crl_verify.3 gnutls_x509_crt_init.3 gnutls_x509_crt_deinit.3 gnutls_x509_crt_import.3 gnutls_x509_crt_get_issuer_dn.3 gnutls_x509_crt_get_issuer_dn_by_oid.3 gnutls_x509_crt_get_issuer_dn_oid.3 gnutls_x509_crt_get_dn.3 gnutls_x509_crt_get_dn_by_oid.3 gnutls_x509_crt_get_dn_oid.3 gnutls_x509_crt_get_signature_algorithm.3 gnutls_x509_crt_get_version.3 gnutls_x509_crt_get_activation_time.3 gnutls_x509_crt_get_expiration_time.3 gnutls_x509_crt_get_serial.3 gnutls_x509_crt_get_subject_key_id.3 gnutls_x509_crt_get_authority_key_id.3 gnutls_x509_crt_get_pk_algorithm.3 gnutls_x509_crt_get_subject_alt_name.3 gnutls_x509_crt_get_ca_status.3 gnutls_x509_crt_get_key_usage.3 gnutls_x509_crt_get_extension_by_oid.3 gnutls_x509_crt_get_extension_oid.3 gnutls_x509_crt_get_fingerprint.3 gnutls_x509_crt_export.3 gnutls_x509_crt_get_key_id.3 gnutls_x509_crt_check_revocation.3 gnutls_x509_crt_verify_data.3 gnutls_x509_crt_get_crl_dist_points.3 gnutls_x509_crt_get_key_purpose_oid.3 gnutls_x509_crt_get_pk_rsa_raw.3 gnutls_x509_crt_get_pk_dsa_raw.3 gnutls_x509_crt_list_import.3 gnutls_x509_crt_set_dn_by_oid.3 gnutls_x509_crt_set_issuer_dn_by_oid.3 gnutls_x509_crt_set_version.3 gnutls_x509_crt_set_key.3 gnutls_x509_crt_set_crq.3 gnutls_x509_crt_set_extension_by_oid.3 gnutls_x509_crt_set_ca_status.3 gnutls_x509_crt_set_key_usage.3 gnutls_x509_crt_set_subject_alternative_name.3 gnutls_x509_crt_sign2.3 gnutls_x509_crt_sign.3 gnutls_x509_crt_set_activation_time.3 gnutls_x509_crt_set_expiration_time.3 gnutls_x509_crt_set_serial.3 gnutls_x509_crt_set_crl_dist_points.3 gnutls_x509_crt_cpy_crl_dist_points.3 gnutls_x509_crt_set_subject_key_id.3 gnutls_x509_crt_set_authority_key_id.3 gnutls_x509_crt_set_key_purpose_oid.3 gnutls_x509_crt_to_xml.3 gnutls_openpgp_keyring_init.3 gnutls_openpgp_keyring_deinit.3 gnutls_openpgp_keyring_check_id.3 gnutls_openpgp_keyring_import.3 gnutls_openpgp_trustdb_init.3 gnutls_openpgp_trustdb_deinit.3 gnutls_openpgp_trustdb_import_file.3 gnutls_openpgp_key_init.3 gnutls_openpgp_key_deinit.3 gnutls_openpgp_key_import.3 gnutls_openpgp_key_export.3 gnutls_openpgp_key_get_fingerprint.3 gnutls_openpgp_key_get_name.3 gnutls_openpgp_key_get_pk_algorithm.3 gnutls_openpgp_key_get_version.3 gnutls_openpgp_key_get_creation_time.3 gnutls_openpgp_key_get_expiration_time.3 gnutls_openpgp_key_get_id.3 gnutls_openpgp_key_check_hostname.3 gnutls_openpgp_key_get_key_usage.3 gnutls_openpgp_key_verify_ring.3 gnutls_openpgp_key_verify_self.3 gnutls_openpgp_key_verify_trustdb.3 gnutls_openpgp_privkey_init.3 gnutls_openpgp_privkey_deinit.3 gnutls_openpgp_privkey_import.3 gnutls_openpgp_privkey_get_pk_algorithm.3 gnutls_openpgp_key_to_xml.3
SRPMANS = gnutls_srp_base64_encode.3 gnutls_srp_base64_encode_alloc.3 gnutls_srp_base64_decode.3 gnutls_srp_base64_decode_alloc.3 gnutls_srp_free_client_credentials.3 gnutls_srp_allocate_client_credentials.3 gnutls_srp_set_client_credentials.3 gnutls_srp_free_server_credentials.3 gnutls_srp_allocate_server_credentials.3 gnutls_srp_set_server_credentials_file.3 gnutls_srp_set_server_credentials_function.3 gnutls_srp_set_client_credentials_function.3 gnutls_srp_server_get_username.3 gnutls_srp_verifier.3
diff --git a/includes/gnutls/extra.h b/includes/gnutls/extra.h
index 7769878713..a3f166f72f 100644
--- a/includes/gnutls/extra.h
+++ b/includes/gnutls/extra.h
@@ -79,6 +79,87 @@ int gnutls_certificate_set_openpgp_keyring_mem(
int gnutls_certificate_set_openpgp_keyring_file( gnutls_certificate_credentials_t c,
const char *file);
+ /* TLS/IA stuff
+ */
+
+ typedef enum {
+ GNUTLS_IA_APPLICATION_PAYLOAD = 0,
+ GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED = 1,
+ GNUTLS_IA_FINAL_PHASE_FINISHED = 2
+ } gnutls_ia_apptype_t;
+
+ /* TLS/IA credential
+ */
+
+ typedef int (*gnutls_ia_avp_func) (gnutls_session_t session, void *ptr,
+ const char *last, size_t lastlen,
+ char **new, size_t *newlen);
+
+ typedef struct gnutls_ia_server_credentials_st* gnutls_ia_server_credentials_t;
+ typedef struct gnutls_ia_client_credentials_st* gnutls_ia_client_credentials_t;
+
+ /* Allocate and free TLS/IA credentials. */
+ extern void
+ gnutls_ia_free_client_credentials(gnutls_ia_client_credentials_t sc);
+ extern int
+ gnutls_ia_allocate_client_credentials(gnutls_ia_client_credentials_t * sc);
+
+ extern void
+ gnutls_ia_free_server_credentials(gnutls_ia_server_credentials_t sc);
+ extern int
+ gnutls_ia_allocate_server_credentials(gnutls_ia_server_credentials_t * sc);
+
+ /* Client TLS/IA credential functions. */
+ extern void
+ gnutls_ia_set_client_avp_function(gnutls_ia_client_credentials_t cred,
+ gnutls_ia_avp_func avp_func);
+ extern void
+ gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred,
+ void *ptr);
+ extern void *
+ gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred);
+
+ /* Server TLS/IA credential functions. */
+ extern void
+ gnutls_ia_set_server_avp_function(gnutls_ia_server_credentials_t cred,
+ gnutls_ia_avp_func avp_func);
+ extern void
+ gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred,
+ void *ptr);
+ extern void *
+ gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred);
+
+ /* TLS/IA handshake. */
+ extern int gnutls_ia_handshake_p (gnutls_session_t session);
+
+ extern int gnutls_ia_handshake (gnutls_session_t session);
+
+ /* TLS/IA low level interface. */
+ extern int
+ gnutls_ia_permute_inner_secret (gnutls_session_t session,
+ size_t session_keys_size,
+ const char *session_keys);
+ extern int
+ gnutls_ia_endphase_send(gnutls_session_t session, int final_p);
+
+ extern ssize_t
+ gnutls_ia_send(gnutls_session_t session, char *data, size_t datal);
+ extern ssize_t
+ gnutls_ia_recv(gnutls_session_t session, char *data, size_t datal);
+
+ /* Utility stuff. */
+ extern int
+ gnutls_ia_generate_challenge (gnutls_session_t session,
+ size_t buffer_size,
+ char *buffer);
+ extern void
+ gnutls_ia_extract_inner_secret (gnutls_session_t session,
+ char *buffer);
+
+ /* Toggle whether inner phases are required. */
+ extern void
+ gnutls_ia_require_inner_phase (gnutls_session_t session, int require);
+
int gnutls_global_init_extra(void);
/* returns libgnutls-extra version (call it with a NULL argument)
diff --git a/includes/gnutls/gnutls.h.in b/includes/gnutls/gnutls.h.in
index e1d33b9fdd..714d13c50b 100644
--- a/includes/gnutls/gnutls.h.in
+++ b/includes/gnutls/gnutls.h.in
@@ -86,8 +86,13 @@ typedef enum { GNUTLS_PARAMS_RSA_EXPORT=1,
GNUTLS_PARAMS_DH
} gnutls_params_type_t;
-typedef enum { GNUTLS_CRD_CERTIFICATE=1, GNUTLS_CRD_ANON, GNUTLS_CRD_SRP,
- GNUTLS_CRD_PSK } gnutls_credentials_type_t;
+typedef enum {
+ GNUTLS_CRD_CERTIFICATE=1,
+ GNUTLS_CRD_ANON,
+ GNUTLS_CRD_SRP,
+ GNUTLS_CRD_PSK,
+ GNUTLS_CRD_IA
+} gnutls_credentials_type_t;
#define GNUTLS_MAC_SHA GNUTLS_MAC_SHA1
#define GNUTLS_DIG_SHA GNUTLS_DIG_SHA1
@@ -137,7 +142,9 @@ typedef enum { GNUTLS_A_CLOSE_NOTIFY,
GNUTLS_A_INSUFFICIENT_SECURITY, GNUTLS_A_INTERNAL_ERROR=80, GNUTLS_A_USER_CANCELED=90,
GNUTLS_A_NO_RENEGOTIATION=100, GNUTLS_A_UNSUPPORTED_EXTENSION=110,
GNUTLS_A_CERTIFICATE_UNOBTAINABLE=111, GNUTLS_A_UNRECOGNIZED_NAME=112,
- GNUTLS_A_UNKNOWN_SRP_USERNAME=120, GNUTLS_A_MISSING_SRP_USERNAME=121
+ GNUTLS_A_UNKNOWN_SRP_USERNAME=120, GNUTLS_A_MISSING_SRP_USERNAME=121,
+ GNUTLS_A_INNER_APPLICATION_FAILURE=208,
+ GNUTLS_A_INNER_APPLICATION_VERIFICATION=209
} gnutls_alert_description_t;
typedef enum { GNUTLS_HANDSHAKE_HELLO_REQUEST,
@@ -297,6 +304,12 @@ int gnutls_server_name_get(gnutls_session_t session,
void *data, size_t *data_length,
unsigned int * type, unsigned int indx);
+typedef enum {
+ GNUTLS_IA_DISABLED = 0,
+ GNUTLS_IA_APP_PHASE_ON_RESUMPTION_NO = 1,
+ GNUTLS_IA_APP_PHASE_ON_RESUMPTION_YES = 2
+} gnutls_ia_mode_t;
+
/* functions to set priority of cipher suites
*/
int gnutls_cipher_set_priority( gnutls_session_t session, const int *list);
@@ -919,6 +932,11 @@ void gnutls_psk_set_params_function(gnutls_psk_server_credentials_t res,
#define GNUTLS_E_MAC_VERIFY_FAILED -100 /* for PKCS #12 MAC */
#define GNUTLS_E_CONSTRAINT_ERROR -101
+#define GNUTLS_E_WARNING_IA_IPHF_RECEIVED -102
+#define GNUTLS_E_WARNING_IA_FPHF_RECEIVED -103
+
+#define GNUTLS_E_IA_VERIFY_FAILED -104
+
#define GNUTLS_E_BASE64_ENCODING_ERROR -201
#define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202 /* obsolete */
#define GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY -202
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1af672e3b6..6be50fc8a2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -69,7 +69,8 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \
gnutls_ui.c gnutls_sig.c auth_dhe.c gnutls_dh_primes.c \
ext_max_record.c gnutls_alert.c gnutls_str.c gnutls_state.c \
gnutls_x509.c ext_cert_type.c gnutls_rsa_export.c \
- auth_rsa_export.c ext_server_name.c auth_dh_common.c gnutls_helper.c
+ auth_rsa_export.c ext_server_name.c auth_dh_common.c \
+ gnutls_helper.c ext_inner_application.c
HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h \
gnutls_buffers.h gnutls_errors.h gnutls_int.h \
@@ -84,8 +85,9 @@ HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h \
gnutls_mem.h io_debug.h ext_max_record.h gnutls_session_pack.h \
gnutls_str.h gnutls_state.h gnutls_x509.h ext_cert_type.h \
gnutls_rsa_export.h ext_server_name.h auth_dh_common.h \
- ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h \
- gnutls_helper.h auth_psk.h auth_psk_passwd.h
+ ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h \
+ gnutls_helper.h auth_psk.h auth_psk_passwd.h \
+ ext_inner_application.h
# Separate so we can create the documentation
diff --git a/lib/debug.c b/lib/debug.c
index ee2e220f86..88003dde97 100644
--- a/lib/debug.c
+++ b/lib/debug.c
@@ -63,6 +63,8 @@ _gnutls_packet2str (content_type_t packet)
return "Handshake";
case GNUTLS_APPLICATION_DATA:
return "Application Data";
+ case GNUTLS_INNER_APPLICATION:
+ return "Inner Application";
default:
return "Unknown Packet";
diff --git a/lib/defines.h b/lib/defines.h
index 925d10c982..0126e81c8a 100644
--- a/lib/defines.h
+++ b/lib/defines.h
@@ -35,6 +35,7 @@
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
+#include <stdint.h>
#ifdef NO_SSIZE_T
# define HAVE_SSIZE_T
diff --git a/lib/ext_inner_application.c b/lib/ext_inner_application.c
new file mode 100644
index 0000000000..a05f906e30
--- /dev/null
+++ b/lib/ext_inner_application.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2005 Free Software Foundation
+ *
+ * Author: Simon Josefsson
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "gnutls_int.h"
+#include "gnutls_auth_int.h"
+#include "gnutls_errors.h"
+#include "gnutls_num.h"
+#include "ext_inner_application.h"
+
+#define NO 0
+#define YES 1
+
+int
+_gnutls_inner_application_recv_params (gnutls_session_t session,
+ const opaque * data, size_t data_size)
+{
+ tls_ext_st *ext = &session->security_parameters.extensions;
+ gnutls_ia_mode_t state;
+
+ if (data_size != 1)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ switch ((unsigned char)*data)
+ {
+ case NO:
+ state = GNUTLS_IA_APP_PHASE_ON_RESUMPTION_NO;
+ break;
+
+ case YES:
+ state = GNUTLS_IA_APP_PHASE_ON_RESUMPTION_YES;
+ break;
+
+ default:
+ gnutls_assert ();
+ return 0;
+ }
+
+ ext->peer_mode = state;
+
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+int
+_gnutls_inner_application_send_params (gnutls_session_t session,
+ opaque * data, size_t data_size)
+{
+ tls_ext_st *ext = &session->security_parameters.extensions;
+
+ if (data_size < 1)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ {
+ gnutls_ia_client_credentials_t cred = (gnutls_ia_client_credentials_t)
+ _gnutls_get_cred(session->key, GNUTLS_CRD_IA, NULL);
+
+ if (cred == NULL)
+ return 0;
+
+ /* Simple case, just send what the application requested. */
+
+ if (ext->inner_phase_optional)
+ *data = NO;
+ else
+ *data = YES;
+ }
+ else
+ {
+ gnutls_ia_server_credentials_t cred = (gnutls_ia_server_credentials_t)
+ _gnutls_get_cred(session->key, GNUTLS_CRD_IA, NULL);
+
+ if (cred == NULL)
+ return 0;
+
+ /* The server MUST set app_phase_on_resumption to "yes" if the
+ client set app_phase_on_resumption to "yes" or if the server
+ does not resume the session. */
+ if ((ext->peer_mode == GNUTLS_IA_APP_PHASE_ON_RESUMPTION_YES) ||
+ !gnutls_session_is_resumed(session))
+ *data = YES;
+ /* The server MAY set app_phase_on_resumption to "yes" for a
+ resumed session even if the client set
+ app_phase_on_resumption to "no", as the server may have
+ reason to proceed with one or more application phases. */
+ else if (!ext->inner_phase_optional)
+ *data = YES;
+ else
+ *data = NO;
+ }
+
+ return 1;
+}
diff --git a/lib/ext_inner_application.h b/lib/ext_inner_application.h
new file mode 100644
index 0000000000..86e0a1e12c
--- /dev/null
+++ b/lib/ext_inner_application.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2005 Free Software Foundation
+ *
+ * Author: Simon Josefsson
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+int _gnutls_inner_application_recv_params(gnutls_session_t session,
+ const opaque * data,
+ size_t data_size);
+int _gnutls_inner_application_send_params(gnutls_session_t session,
+ opaque * data, size_t);
diff --git a/lib/gnutls_alert.c b/lib/gnutls_alert.c
index 566fe49bf5..92431bc799 100644
--- a/lib/gnutls_alert.c
+++ b/lib/gnutls_alert.c
@@ -64,6 +64,10 @@ static const gnutls_alert_entry sup_alerts[] = {
"The server name sent was not recognized"},
{GNUTLS_A_UNKNOWN_SRP_USERNAME, "The SRP username is not known"},
{GNUTLS_A_MISSING_SRP_USERNAME, "The SRP username was not sent"},
+ {GNUTLS_A_INNER_APPLICATION_FAILURE,
+ "Inner application negotiation failed"},
+ {GNUTLS_A_INNER_APPLICATION_VERIFICATION,
+ "Inner application verification failed"},
{0, NULL}
};
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 2923232cac..7034e5e868 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -85,42 +85,43 @@ _gnutls_record_buffer_put (content_type_t type,
gnutls_session_t session, opaque * data,
size_t length)
{
+ gnutls_buffer *buf;
+
if (length == 0)
return 0;
+
switch (type)
{
case GNUTLS_APPLICATION_DATA:
-
- if (_gnutls_buffer_append
- (&session->internals.application_data_buffer, data, length) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
- _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
- length, type);
-
+ buf = &session->internals.application_data_buffer;
+ _gnutls_buffers_log("BUF[REC]: Inserted %d bytes of Data(%d)\n",
+ length, type);
break;
- case GNUTLS_HANDSHAKE:
- if (_gnutls_buffer_append
- (&session->internals.handshake_data_buffer, data, length) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
- _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
- length, type);
+ case GNUTLS_HANDSHAKE:
+ buf = &session->internals.handshake_data_buffer;
+ _gnutls_buffers_log("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
+ length, type);
+ break;
+ case GNUTLS_INNER_APPLICATION:
+ buf = &session->internals.ia_data_buffer;
+ _gnutls_buffers_log("BUF[IA]: Inserted %d bytes of Data(%d)\n",
+ length, type);
break;
default:
- gnutls_assert ();
+ gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- return 0;
+ if (_gnutls_buffer_append (buf, data, length) < 0)
+ {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ return 0;
}
int
@@ -134,6 +135,9 @@ _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session)
case GNUTLS_HANDSHAKE:
return session->internals.handshake_data_buffer.length;
+ case GNUTLS_INNER_APPLICATION:
+ return session->internals.ia_data_buffer.length;
+
default:
return GNUTLS_E_INVALID_REQUEST;
}
@@ -211,6 +215,24 @@ _gnutls_record_buffer_get (content_type_t type,
session->internals.handshake_data_buffer.length);
break;
+
+ case GNUTLS_INNER_APPLICATION:
+ if (length > session->internals.ia_data_buffer.length)
+ length = session->internals.ia_data_buffer.length;
+
+ _gnutls_buffers_log("BUF[REC][IA]: Read %d bytes of Data(%d)\n",
+ length, type);
+
+ session->internals.ia_data_buffer.length -= length;
+ memcpy(data, session->internals.ia_data_buffer.data, length);
+
+ /* overwrite buffer */
+ memmove(session->internals.ia_data_buffer.data,
+ &session->internals.ia_data_buffer.data[length],
+ session->internals.ia_data_buffer.length);
+
+ break;
+
default:
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index 3ac7b3ef2e..55ac8aa49e 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -442,7 +442,8 @@ _gnutls_set_write_keys (gnutls_session_t session)
dst->max_record_recv_size = src->max_record_recv_size; \
dst->max_record_send_size = src->max_record_send_size; \
dst->version = src->version; \
- memcpy( &dst->extensions, &src->extensions, sizeof(tls_ext_st));
+ memcpy( &dst->extensions, &src->extensions, sizeof(tls_ext_st)); \
+ memcpy( &dst->inner_secret, &src->inner_secret, sizeof(tls_ext_st));
static void
_gnutls_cpy_read_security_parameters (security_parameters_st *
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 5409e44752..4307318425 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -233,6 +233,14 @@ static gnutls_error_entry error_algorithms[] = {
GNUTLS_E_CONSTRAINT_ERROR, 1),
ERROR_ENTRY ("Failed to acquire random data.", GNUTLS_E_RANDOM_FAILED,
1),
+
+ ERROR_ENTRY("Received a TLS/IA Intermediate Phase Finished message",
+ GNUTLS_E_WARNING_IA_IPHF_RECEIVED, 0),
+ ERROR_ENTRY("Received a TLS/IA Final Phase Finished message",
+ GNUTLS_E_WARNING_IA_FPHF_RECEIVED, 0),
+ ERROR_ENTRY("Verifying TLS/IA phase checksum failed",
+ GNUTLS_E_IA_VERIFY_FAILED, 1),
+
{NULL, NULL, 0, 0}
};
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index 11c35286dd..def360b895 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -34,6 +34,7 @@
#include <ext_cert_type.h>
#include <ext_server_name.h>
#include <ext_srp.h>
+#include <ext_inner_application.h>
#include <gnutls_num.h>
/* Key Exchange Section */
@@ -59,6 +60,9 @@ gnutls_extension_entry _gnutls_extensions[MAX_EXT_SIZE] = {
_gnutls_srp_recv_params,
_gnutls_srp_send_params),
#endif
+ GNUTLS_EXTENSION_ENTRY(GNUTLS_EXTENSION_INNER_APPLICATION,
+ _gnutls_inner_application_recv_params,
+ _gnutls_inner_application_send_params),
{0, 0, 0, 0}
};
@@ -218,12 +222,12 @@ int
_gnutls_gen_extensions (gnutls_session_t session, opaque * data,
size_t data_size)
{
- int next, size;
+ int size;
uint16_t pos = 0;
opaque *sdata;
int sdata_size;
ext_send_func ext_send;
-
+ gnutls_extension_entry *p;
if (data_size < 2)
{
@@ -242,11 +246,9 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
}
pos += 2;
- next = MAX_EXT_TYPES; /* maximum supported extensions */
- do
+ for(p = _gnutls_extensions; p->name != NULL; p++)
{
- next--;
- ext_send = _gnutls_ext_func_send (next);
+ ext_send = _gnutls_ext_func_send(p->type);
if (ext_send == NULL)
continue;
size = ext_send (session, sdata, sdata_size);
@@ -260,7 +262,7 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
}
/* write extension type */
- _gnutls_write_uint16 (next, &data[pos]);
+ _gnutls_write_uint16(p->type, &data[pos]);
pos += 2;
/* write size */
@@ -272,10 +274,10 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
/* add this extension to the extension list
*/
- _gnutls_extension_list_add (session, next);
+ _gnutls_extension_list_add(session, p->type);
_gnutls_debug_log ("EXT[%x]: Sending extension %s\n", session,
- _gnutls_extension_get_name (next));
+ _gnutls_extension_get_name (p->type));
}
else if (size < 0)
{
@@ -283,9 +285,7 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
gnutls_free (sdata);
return size;
}
-
}
- while (next >= 0);
size = pos;
pos -= 2; /* remove the size of the size header! */
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 6d560bcc60..914c2d1d55 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -31,6 +31,10 @@
#include <gnutls/gnutls.h>
#include <gnutls/extra.h>
+struct bar {
+ uint8_t foo;
+};
+
/*
* They are not needed any more. You can simply enable
* the gnutls_log callback to get error descriptions.
@@ -137,7 +141,8 @@ typedef enum handshake_state_t
typedef enum extensions_t
{ GNUTLS_EXTENSION_SERVER_NAME = 0,
GNUTLS_EXTENSION_MAX_RECORD_SIZE = 1, GNUTLS_EXTENSION_SRP = 6,
- GNUTLS_EXTENSION_CERT_TYPE = 7
+ GNUTLS_EXTENSION_CERT_TYPE = 7,
+ GNUTLS_EXTENSION_INNER_APPLICATION = 37703
} extensions_t;
typedef enum
@@ -154,7 +159,8 @@ typedef enum resumable_session_t
typedef enum content_type_t
{
GNUTLS_CHANGE_CIPHER_SPEC = 20, GNUTLS_ALERT,
- GNUTLS_HANDSHAKE, GNUTLS_APPLICATION_DATA
+ GNUTLS_HANDSHAKE, GNUTLS_APPLICATION_DATA,
+ GNUTLS_INNER_APPLICATION = 24
} content_type_t;
#define GNUTLS_PK_ANY (gnutls_pk_algorithm_t)-1
@@ -258,6 +264,9 @@ typedef struct
/* limit server_name extensions */
unsigned server_names_size;
opaque srp_username[MAX_SRP_USERNAME + 1];
+ /* 0 = tls/ia not used, 1 = no, 2 = yes */
+ gnutls_ia_mode_t peer_mode;
+ int inner_phase_optional;
} tls_ext_st;
/* auth_info_t structures now MAY contain malloced
@@ -315,6 +324,8 @@ typedef struct
/* holds the negotiated certificate type */
gnutls_certificate_type_t cert_type;
gnutls_protocol_t version; /* moved here */
+ /* For TLS/IA. XXX: Move to IA credential? */
+ opaque inner_secret[TLS_MASTER_SIZE];
} security_parameters_st;
/* This structure holds the generated keys
@@ -391,6 +402,7 @@ typedef struct
mac_hd_t handshake_mac_handle_md5; /* hash of the handshake messages */
gnutls_buffer handshake_data_buffer; /* this is a buffer that holds the current handshake message */
+ gnutls_buffer ia_data_buffer; /* holds inner application data (TLS/IA) */
resumable_session_t resumable; /* TRUE or FALSE - if we can resume that session */
handshake_state_t handshake_state; /* holds
* a number which indicates where
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index e990d3ac22..f2d1d4b939 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -95,6 +95,10 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
session->security_parameters.master_secret);
}
+ /* TLS/IA inner secret is derived from the master secret. */
+ memcpy (session->security_parameters.inner_secret,
+ session->security_parameters.master_secret, TLS_MASTER_SIZE);
+
if (!keep_premaster)
_gnutls_free_datum (&PREMASTER);
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index 0f34fc629d..24930ad144 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -481,6 +481,7 @@ check_recv_type (content_type_t recv_type)
case GNUTLS_ALERT:
case GNUTLS_HANDSHAKE:
case GNUTLS_APPLICATION_DATA:
+ case GNUTLS_INNER_APPLICATION:
return 0;
default:
gnutls_assert ();
@@ -497,7 +498,9 @@ static int
check_buffers (gnutls_session_t session, content_type_t type,
opaque * data, int sizeofdata)
{
- if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE)
+ if ((type == GNUTLS_APPLICATION_DATA ||
+ type == GNUTLS_HANDSHAKE ||
+ type == GNUTLS_INNER_APPLICATION)
&& _gnutls_record_buffer_get_size (type, session) > 0)
{
int ret, ret2;
@@ -634,7 +637,9 @@ record_check_type (gnutls_session_t session,
int ret;
if ((recv_type == type)
- && (type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE))
+ && (type == GNUTLS_APPLICATION_DATA ||
+ type == GNUTLS_HANDSHAKE ||
+ type == GNUTLS_INNER_APPLICATION))
{
_gnutls_record_buffer_put (type, session, (void *) data, data_size);
}
@@ -731,6 +736,17 @@ record_check_type (gnutls_session_t session,
return _gnutls_recv_hello_request (session, data, data_size);
break;
+ case GNUTLS_INNER_APPLICATION:
+ /* even if data is unexpected put it into the buffer */
+ if ((ret = _gnutls_record_buffer_put(recv_type, session,
+ (void *) data,
+ data_size)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET;
+ break;
default:
_gnutls_record_log
@@ -1008,8 +1024,10 @@ begin:
/* Get Application data from buffer
*/
- if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE)
- && (recv_type == type))
+ if ((recv_type == type) &&
+ (type == GNUTLS_APPLICATION_DATA ||
+ type == GNUTLS_HANDSHAKE ||
+ type == GNUTLS_INNER_APPLICATION))
{
ret = _gnutls_record_buffer_get (type, session, data, sizeofdata);
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index 7e270132fb..d67077c191 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -262,6 +262,7 @@ gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end)
_gnutls_buffer_init (&(*session)->internals.application_data_buffer);
_gnutls_buffer_init (&(*session)->internals.handshake_data_buffer);
_gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer);
+ _gnutls_buffer_init(&(*session)->internals.ia_data_buffer);
_gnutls_buffer_init (&(*session)->internals.record_send_buffer);
_gnutls_buffer_init (&(*session)->internals.record_recv_buffer);
@@ -354,6 +355,7 @@ gnutls_deinit (gnutls_session_t session)
_gnutls_free_datum (&session->connection_state.read_mac_secret);
_gnutls_free_datum (&session->connection_state.write_mac_secret);
+ _gnutls_buffer_clear(&session->internals.ia_data_buffer);
_gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
_gnutls_buffer_clear (&session->internals.handshake_data_buffer);
_gnutls_buffer_clear (&session->internals.application_data_buffer);
diff --git a/libextra/Makefile.am b/libextra/Makefile.am
index ca8aa3f745..fc1fa833c0 100644
--- a/libextra/Makefile.am
+++ b/libextra/Makefile.am
@@ -53,14 +53,13 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = gnutls-extra.pc
DISTCLEANFILES = $(pkgconfig_DATA)
-EXTRA_DIST = gnutls-extra-api.texi
+EXTRA_DIST = gnutls-extra-api.texi ia-api.texi
lib_LTLIBRARIES = libgnutls-extra.la
-COBJECTS = gnutls_extra.c
+libgnutls_extra_la_SOURCES = gnutls_extra.c
libgnutls_openssl_la_LDFLAGS =
-libgnutls_extra_la_SOURCES =
# OpenSSL
@@ -95,11 +94,17 @@ libgnutls_extra_la_LDFLAGS += $(LIBOPENCDK_LIBS)
endif
endif
+# TLS/IA
+
+libgnutls_extra_la_SOURCES += gnutls_ia.c
+
+# Rest
+
libgnutls_extra_la_LDFLAGS += \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
$(LZO_LIBS)
-libgnutls_extra_la_SOURCES += $(COBJECTS) gnutls_extra.h libgnutls-extra.vers
+libgnutls_extra_la_SOURCES += gnutls_extra.h libgnutls-extra.vers
libgnutls_extra_la_LIBADD += ../lib/libgnutls.la ../gl/libgnu.la
@@ -115,12 +120,20 @@ SUBDIRS += minilzo
libgnutls_extra_la_LIBADD += minilzo/libminilzo.la
endif
-gnutls-extra-api.texi: $(COBJECTS)
- @echo "" > gnutls-extra-api.texi
- @for i in $(COBJECTS); do \
+gnutls-extra-api.texi: gnutls_extra.c
+ @echo "" > $@
+ @for i in $<; do \
+ echo -n "Creating documentation for file $$i... " && \
+ ../doc/scripts/gdoc -texinfo $$i >> $@ && \
+ echo "ok"; \
+ done
+
+ia-api.texi: gnutls_ia.c
+ @echo "" > $@
+ @for i in $<; do \
echo -n "Creating documentation for file $$i... " && \
- ../doc/scripts/gdoc -texinfo $$i >> gnutls-extra-api.texi && \
+ ../doc/scripts/gdoc -texinfo $$i >> $@ && \
echo "ok"; \
done
-dist-hook: gnutls-extra-api.texi
+dist-hook: gnutls-extra-api.texi ia-api.texi
diff --git a/libextra/gnutls_ia.c b/libextra/gnutls_ia.c
new file mode 100644
index 0000000000..56677ee772
--- /dev/null
+++ b/libextra/gnutls_ia.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2005 Free Software Foundation
+ *
+ * Author: Simon Josefsson
+ *
+ * This file is part of GNUTLS-EXTRA.
+ *
+ * GNUTLS-EXTRA is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GNUTLS-EXTRA 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUTLS-EXTRA; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "gnutls_int.h"
+#include "gnutls_record.h"
+#include "gnutls_errors.h"
+#include "gnutls_num.h"
+#include "gnutls_state.h"
+
+#define CHECKSUM_SIZE 12
+
+struct gnutls_ia_client_credentials_st
+{
+ gnutls_ia_avp_func avp_func;
+ void *avp_ptr;
+};
+
+struct gnutls_ia_server_credentials_st
+{
+ gnutls_ia_avp_func avp_func;
+ void *avp_ptr;
+};
+
+static const char server_finished_label[] = "server phase finished";
+static const char client_finished_label[] = "client phase finished";
+static const char inner_permutation_label[] = "inner secret permutation";
+static const char challenge_label[] = "inner application challenge";
+
+/*
+ * The TLS/IA packet is the InnerApplication token, described as
+ * follows in draft-funk-tls-inner-application-extension-01.txt:
+ *
+ * enum {
+ * application_payload(0), intermediate_phase_finished(1),
+ * final_phase_finished(2), (255)
+ * } InnerApplicationType;
+ *
+ * struct {
+ * InnerApplicationType msg_type;
+ * uint24 length;
+ * select (InnerApplicationType) {
+ * case application_payload: ApplicationPayload;
+ * case intermediate_phase_finished: IntermediatePhaseFinished;
+ * case final_phase_finished: FinalPhaseFinished;
+ * } body;
+ * } InnerApplication;
+ *
+ */
+
+/* Send TLS/IA data. If data==NULL && sizeofdata==NULL, then the last
+ send was interrupted for some reason, and then we try to send it
+ again. Returns the number of bytes sent, or an error code. If
+ this return E_AGAIN and E_INTERRUPTED, call this function again
+ with data==NULL&&sizeofdata=0NULL until it returns successfully. */
+static ssize_t
+_gnutls_send_inner_application (gnutls_session_t session,
+ gnutls_ia_apptype_t msg_type,
+ const char *data, size_t sizeofdata)
+{
+ opaque *p = NULL;
+ size_t plen = 0;
+ ssize_t len;
+
+ if (data != NULL)
+ {
+ plen = sizeofdata + 4;
+ p = gnutls_malloc (plen);
+ if (!p)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ *(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
+ _gnutls_write_uint24 (sizeofdata, p + 1);
+ memcpy (p + 4, data, sizeofdata);
+ }
+
+ len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
+
+ if (p)
+ gnutls_free (p);
+
+ return len;
+}
+
+/* Receive TLS/IA data. Store received TLS/IA message type in
+ *MSG_TYPE, and the data in DATA of max SIZEOFDATA size. Return the
+ number of bytes read, or an error code. */
+static ssize_t
+_gnutls_recv_inner_application (gnutls_session_t session,
+ gnutls_ia_apptype_t * msg_type,
+ opaque *data, size_t sizeofdata)
+{
+ ssize_t len;
+ opaque pkt[4];
+
+ len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
+ if (len != 4)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ *msg_type = pkt[0];
+ len = _gnutls_read_uint24 (&pkt[1]);
+
+ if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len != CHECKSUM_SIZE)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ if (sizeofdata < len)
+ {
+ /* XXX push back pkt to IA buffer? */
+ gnutls_assert ();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ if (len > 0)
+ {
+ int tmplen = len;
+
+ len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
+ data, tmplen);
+ if (len != tmplen)
+ {
+ gnutls_assert ();
+ /* XXX Correct? */
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+ }
+
+ return len;
+}
+
+/* Apply the TLS PRF using the TLS/IA inner secret as keying material,
+ where the seed is the client random concatenated with the server
+ random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
+ respectively). LABEL and LABEL_SIZE is used as the label. The
+ result is placed in pre-allocated OUT of OUTSIZE length. */
+static int
+_gnutls_ia_prf (gnutls_session_t session,
+ size_t label_size,
+ const char *label,
+ size_t extra_size,
+ const char *extra,
+ size_t outsize,
+ opaque *out)
+{
+ int ret;
+ opaque *seed;
+ size_t seedsize = 2 * TLS_RANDOM_SIZE + extra_size;
+
+ seed = gnutls_malloc (seedsize);
+ if (!seed)
+ {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ memcpy (seed, session->security_parameters.server_random, TLS_RANDOM_SIZE);
+ memcpy (seed + TLS_RANDOM_SIZE, session->security_parameters.client_random,
+ TLS_RANDOM_SIZE);
+ memcpy (seed + 2 * TLS_RANDOM_SIZE, extra, extra_size);
+
+ ret = _gnutls_PRF (session->security_parameters.inner_secret,
+ TLS_MASTER_SIZE,
+ label,
+ label_size,
+ seed,
+ seedsize,
+ outsize,
+ out);
+
+ gnutls_free (seed);
+
+ return ret;
+}
+
+/**
+ * gnutls_ia_permute_inner_secret:
+ * @session: is a #gnutls_session_t structure.
+ * @session_keys_size: Size of generated session keys (0 if none).
+ * @session_keys: Generated session keys, used to permute inner secret
+ * (NULL if none).
+ *
+ * Permute the inner secret using the generated session keys.
+ *
+ * This can be called in the TLS/IA AVP callback to mix any generated
+ * session keys with the TLS/IA inner secret.
+ *
+ * Return value: Return zero on success, or a negative error code.
+ **/
+int
+gnutls_ia_permute_inner_secret (gnutls_session_t session,
+ size_t session_keys_size,
+ const char *session_keys)
+{
+ return _gnutls_ia_prf (session,
+ sizeof (inner_permutation_label) - 1,
+ inner_permutation_label,
+ session_keys_size,
+ session_keys,
+ TLS_RANDOM_SIZE,
+ session->security_parameters.inner_secret);
+}
+
+/**
+ * gnutls_ia_generate_challenge:
+ * @session: is a #gnutls_session_t structure.
+ * @buffer_size: size of output buffer.
+ * @buffer: pre-allocated buffer to contain @buffer_size bytes of output.
+ *
+ * Generate an application challenge that the client cannot control or
+ * predict, based on the TLS/IA inner secret.
+ *
+ * Return value: Returns 0 on success, or an negative error code.
+ **/
+int
+gnutls_ia_generate_challenge (gnutls_session_t session,
+ size_t buffer_size,
+ char *buffer)
+{
+ return _gnutls_ia_prf (session,
+ sizeof (challenge_label) - 1,
+ challenge_label,
+ 0,
+ NULL,
+ buffer_size,
+ buffer);
+}
+
+/**
+ * gnutls_ia_extract_inner_secret:
+ * @session: is a #gnutls_session_t structure.
+ * @buffer: pre-allocated buffer to hold 48 bytes of inner secret.
+ *
+ * Copy the 48 bytes large inner secret into the specified buffer
+ *
+ * This function is typically used after the TLS/IA handshake has
+ * concluded. The TLS/IA inner secret can be used as input to a PRF
+ * to derive session keys. Do not use the inner secret directly as a
+ * session key, because for a resumed session that does not include an
+ * application phase, the inner secret will be identical to the inner
+ * secret in the original session. It is important to include, for
+ * example, the client and server randomness when deriving a sesssion
+ * key from the inner secret.
+ **/
+void
+gnutls_ia_extract_inner_secret (gnutls_session_t session,
+ char *buffer)
+{
+ memcpy (buffer, session->security_parameters.inner_secret, TLS_MASTER_SIZE);
+}
+
+/**
+ * gnutls_ia_endphase_send:
+ * @session: is a #gnutls_session_t structure.
+ * @final_p: Set iff this should signal the final phase.
+ *
+ * Send a TLS/IA end phase message.
+ *
+ * In the client, this should only be used to acknowledge an end phase
+ * message sent by the server.
+ *
+ * In the server, this can be called instead of gnutls_ia_send() if
+ * the server wishes to end an application phase.
+ *
+ * Return value: Return 0 on success, or an error code.
+ **/
+int
+gnutls_ia_endphase_send(gnutls_session_t session, int final_p)
+{
+ opaque local_checksum[CHECKSUM_SIZE];
+ int client = session->security_parameters.entity == GNUTLS_CLIENT;
+ const char *label = client ? client_finished_label : server_finished_label;
+ int size_of_label = client ? sizeof (client_finished_label) :
+ sizeof (server_finished_label);
+ ssize_t len;
+ int ret;
+
+ ret = _gnutls_PRF (session->security_parameters.inner_secret,
+ TLS_MASTER_SIZE,
+ label, size_of_label - 1,
+ /* XXX specification unclear on seed. */
+ "", 0, CHECKSUM_SIZE, local_checksum);
+ if (ret < 0)
+ return ret;
+
+ len = _gnutls_send_inner_application
+ (session,
+ final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
+ GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED,
+ local_checksum, CHECKSUM_SIZE);
+
+ /* XXX Instead of calling this function over and over...?
+ * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
+ * len = _gnutls_io_write_flush(session);
+ */
+
+ if (len < 0)
+ {
+ gnutls_assert();
+ return len;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_ia_verify_endphase:
+ * @session: is a #gnutls_session_t structure.
+ * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
+ *
+ * Verify TLS/IA end phase checksum data. If verification fails, the
+ * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
+ * sie.
+ *
+ * This function is called when gnutls_ia_recv() return
+ * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
+ * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
+ *
+ * Return value: Return 0 on successful verification, or an error
+ * code. If the checksum verification of the end phase message fails,
+ * %GNUTLS_E_IA_VERIFY_FAILED is returned.
+ **/
+int
+gnutls_ia_verify_endphase (gnutls_session_t session, char *checksum)
+{
+ char local_checksum[CHECKSUM_SIZE];
+ int client = session->security_parameters.entity == GNUTLS_CLIENT;
+ const char *label = client ? server_finished_label : client_finished_label;
+ int size_of_label = client ? sizeof (server_finished_label) :
+ sizeof (client_finished_label);
+ int ret;
+
+ ret = _gnutls_PRF (session->security_parameters.inner_secret,
+ TLS_MASTER_SIZE,
+ label, size_of_label - 1,
+ "", 0, CHECKSUM_SIZE, local_checksum);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
+ {
+ ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
+ GNUTLS_A_INNER_APPLICATION_VERIFICATION);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ return GNUTLS_E_IA_VERIFY_FAILED;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_ia_send: Send peer the specified TLS/IA data.
+ * @session: is a #gnutls_session_t structure.
+ * @data: contains the data to send
+ * @sizeofdata: is the length of the data
+ *
+ * Send TLS/IA application payload data. This function has the
+ * similar semantics with send(). The only difference is that is
+ * accepts a GNUTLS session, and uses different error codes.
+ *
+ * The TLS/IA protocol is synchronous, so you cannot send more than
+ * one packet at a time. The client always send the first packet.
+ *
+ * To finish an application phase in the server, use
+ * gnutls_ia_endphase_send(). The client cannot end an application
+ * phase.
+ *
+ * If the EINTR is returned by the internal push function (the default
+ * is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
+ * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
+ * this function again, with the same parameters; alternatively you
+ * could provide a %NULL pointer for data, and 0 for size.
+ *
+ * Returns the number of bytes sent, or a negative error code.
+ **/
+ssize_t
+gnutls_ia_send (gnutls_session_t session, char *data, size_t sizeofdata)
+{
+ ssize_t len;
+
+ len = _gnutls_send_inner_application (session,
+ GNUTLS_IA_APPLICATION_PAYLOAD,
+ data, sizeofdata);
+
+ return len;
+}
+
+/**
+ * gnutls_ia_recv - read data from the TLS/IA protocol
+ * @session: is a #gnutls_session_t structure.
+ * @data: the buffer that the data will be read into, must hold >= 12 bytes.
+ * @sizeofdata: the number of requested bytes, must be >= 12.
+ *
+ * Receive TLS/IA data. This function has the similar semantics with
+ * recv(). The only difference is that is accepts a GNUTLS session,
+ * and uses different error codes.
+ *
+ * If the server attempt to finish an application phase, this function
+ * will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
+ * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. The caller should then invoke
+ * gnutls_ia_verify_endphase().
+ *
+ * If EINTR is returned by the internal push function (the default is
+ * @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned. If
+ * GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
+ * this function again, with the same parameters; alternatively you
+ * could provide a NULL pointer for data, and 0 for size.
+ *
+ * Returns the number of bytes received. A negative error code is
+ * returned in case of an error. The
+ * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
+ * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
+ * application phase finished message has been sent by the server.
+ **/
+ssize_t
+gnutls_ia_recv (gnutls_session_t session, char *data, size_t sizeofdata)
+{
+ gnutls_ia_apptype_t msg_type;
+ ssize_t len;
+
+ len = _gnutls_recv_inner_application (session, &msg_type,
+ data, sizeofdata);
+
+ if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
+ return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
+ else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
+ return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
+
+ return len;
+}
+
+/* XXX rewrite the following two functions as state machines, to
+ handle EAGAIN/EINTERRUPTED? just add more problems to callers,
+ though. */
+
+int
+_gnutls_ia_client_handshake (gnutls_session_t session)
+{
+ char *buf = NULL;
+ size_t buflen = 0;
+ char tmp[1024]; /* XXX */
+ ssize_t len;
+ int ret;
+ const struct gnutls_ia_client_credentials_st * cred =
+ _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
+
+ if (cred == NULL)
+ return GNUTLS_E_INTERNAL_ERROR;
+
+ while (1)
+ {
+ char *avp;
+ size_t avplen;
+
+ ret = cred->avp_func (session, cred->avp_ptr,
+ buf, buflen, &avp, &avplen);
+ if (ret)
+ {
+ int tmpret;
+ tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
+ GNUTLS_A_INNER_APPLICATION_FAILURE);
+ if (tmpret < 0)
+ gnutls_assert ();
+ return ret;
+ }
+
+ len = gnutls_ia_send (session, avp, avplen);
+ gnutls_free (avp);
+ if (len < 0)
+ return len;
+
+ len = gnutls_ia_recv (session, tmp, sizeof (tmp));
+ if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
+ len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
+ {
+ ret = gnutls_ia_verify_endphase (session, tmp);
+ if (ret < 0)
+ return ret;
+
+ ret = gnutls_ia_endphase_send
+ (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
+ {
+ buf = NULL;
+ buflen = 0;
+ continue;
+ }
+ else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
+ break;
+
+ if (len < 0)
+ return len;
+
+ buflen = len;
+ buf = tmp;
+ }
+
+ return 0;
+}
+
+int
+_gnutls_ia_server_handshake (gnutls_session_t session)
+{
+ gnutls_ia_apptype_t msg_type;
+ ssize_t len;
+ char buf[1024];
+ int ret;
+ const struct gnutls_ia_server_credentials_st * cred =
+ _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
+
+ if (cred == NULL)
+ return GNUTLS_E_INTERNAL_ERROR;
+
+ do
+ {
+ char *avp;
+ size_t avplen;
+
+ len = gnutls_ia_recv (session, buf, sizeof (buf));
+ if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
+ len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
+ {
+ ret = gnutls_ia_verify_endphase (session, buf);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
+ continue;
+ else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
+ break;
+
+ if (len < 0)
+ return len;
+
+ avp = NULL;
+ avplen = 0;
+
+ ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
+ if (ret < 0)
+ {
+ int tmpret;
+ tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
+ GNUTLS_A_INNER_APPLICATION_FAILURE);
+ if (tmpret < 0)
+ gnutls_assert ();
+ return ret;
+ }
+
+ msg_type = ret;
+
+ if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
+ {
+ ret = gnutls_ia_endphase_send (session, msg_type ==
+ GNUTLS_IA_FINAL_PHASE_FINISHED);
+ if (ret < 0)
+ return ret;
+ }
+ else
+ {
+ len = gnutls_ia_send (session, avp, avplen);
+ gnutls_free (avp);
+ if (len < 0)
+ return len;
+ }
+ }
+ while (1);
+
+ return 0;
+}
+
+/**
+ * gnutls_ia_handshake_p:
+ * @session: is a #gnutls_session_t structure.
+ *
+ * Predicate to be used after gnutls_handshake() to decide whether to
+ * invoke gnutls_ia_handshake(). Usable by both clients and servers.
+ *
+ * Return value: non-zero if TLS/IA handshake is expected, zero
+ * otherwise.
+ **/
+int
+gnutls_ia_handshake_p (gnutls_session_t session)
+{
+ tls_ext_st *ext = &session->security_parameters.extensions;
+
+ /* The other side didn't advertise TLS/IA. */
+ if (ext->peer_mode == GNUTLS_IA_DISABLED)
+ return 0;
+
+ /* We don't consider the inner phase optional. */
+ if (!ext->inner_phase_optional)
+ return 1;
+
+ /* This is not a resumed session. always require an inner
+ application. */
+ if (!gnutls_session_is_resumed (session))
+ return 1;
+
+ /* Require an inner phase if the other end requested it. */
+ return ext->peer_mode == GNUTLS_IA_APP_PHASE_ON_RESUMPTION_YES;
+}
+
+/**
+ * gnutls_ia_handshake:
+ * @session: is a #gnutls_session_t structure.
+ *
+ * Perform a TLS/IA handshake. This should be called after
+ * gnutls_handshake() iff gnutls_ia_handshake_p().
+ *
+ * Return 0 on success, or an error code.
+ **/
+int
+gnutls_ia_handshake (gnutls_session_t session)
+{
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ ret = _gnutls_ia_client_handshake (session);
+ else
+ ret = _gnutls_ia_server_handshake (session);
+
+ return ret;
+}
+
+/**
+ * gnutls_ia_allocate_client_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
+ * @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus this
+ * helper function is provided in order to allocate it.
+ *
+ * Adding this credential to a session will enable TLS/IA, and will
+ * require an Application Phase after the TLS handshake (if the server
+ * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
+ * TLS/IA mode.
+ *
+ * Returns 0 on success.
+ **/
+int
+gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
+{
+ *sc = gnutls_calloc (1, sizeof (**sc));
+
+ if (*sc == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ return 0;
+}
+
+/**
+ * gnutls_ia_free_client_credentials - Used to free an allocated #gnutls_ia_client_credentials_t structure
+ * @sc: is an #gnutls_ia_client_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus this
+ * helper function is provided in order to free (deallocate) it.
+ *
+ **/
+void
+gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
+{
+ gnutls_free (sc);
+}
+
+/**
+ * gnutls_ia_set_client_avp_function - Used to set a AVP callback
+ * @cred: is a #gnutls_ia_client_credentials_t structure.
+ * @avp_func: is the callback function
+ *
+ * Set the TLS/IA AVP callback handler used for the session.
+ *
+ * The AVP callback is called to process AVPs received from the
+ * server, and to get a new AVP to send to the server.
+ *
+ * The callback's function form is:
+ * int (*avp_func) (gnutls_session_t session, void *ptr,
+ * const char *last, size_t lastlen,
+ * char **new, size_t *newlen);
+ *
+ * The @session parameter is the #gnutls_session_t structure
+ * corresponding to the current session. The @ptr parameter is the
+ * application hook pointer, set through
+ * gnutls_ia_set_client_avp_ptr(). The AVP received from the server
+ * is present in @last of @lastlen size, which will be %NULL on the
+ * first invocation. The newly allocated output AVP to send to the
+ * server should be placed in *@new of *@newlen size.
+ *
+ * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
+ * generated session keys with the TLS/IA inner secret.
+ *
+ * Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
+ * error code to abort the TLS/IA handshake.
+ *
+ * Note that the callback must use allocate the @new parameter using
+ * gnutls_malloc(), because it is released via gnutls_free() by the
+ * TLS/IA handshake function.
+ *
+ **/
+void
+gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
+ gnutls_ia_avp_func avp_func)
+{
+ cred->avp_func = avp_func;
+}
+
+/**
+ * gnutls_ia_set_client_avp_ptr - Sets a pointer to be sent to TLS/IA callback
+ * @cred: is a #gnutls_ia_client_credentials_t structure.
+ * @ptr: is the pointer
+ *
+ * Sets the pointer that will be provided to the TLS/IA callback
+ * function as the first argument.
+ *
+ **/
+void
+gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
+{
+ cred->avp_ptr = ptr;
+}
+
+/**
+ * gnutls_ia_get_client_avp_ptr - Returns the pointer which is sent to TLS/IA callback
+ * @cred: is a #gnutls_ia_client_credentials_t structure.
+ *
+ * Returns the pointer that will be provided to the TLS/IA callback
+ * function as the first argument.
+ *
+ **/
+void *
+gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
+{
+ return cred->avp_ptr;
+}
+
+/**
+ * gnutls_ia_allocate_server_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
+ * @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus this
+ * helper function is provided in order to allocate it.
+ *
+ * Adding this credential to a session will enable TLS/IA, and will
+ * require an Application Phase after the TLS handshake (if the client
+ * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
+ * TLS/IA mode.
+ *
+ * Returns 0 on success.
+ **/
+int
+gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
+{
+ *sc = gnutls_calloc (1, sizeof (**sc));
+
+ if (*sc == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ return 0;
+}
+
+/**
+ * gnutls_ia_free_server_credentials - Used to free an allocated #gnutls_ia_server_credentials_t structure
+ * @sc: is an #gnutls_ia_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus this
+ * helper function is provided in order to free (deallocate) it.
+ *
+ **/
+void
+gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
+{
+ gnutls_free (sc);
+}
+
+/**
+ * gnutls_ia_set_server_credentials_function - Used to set a AVP callback
+ * @cred: is a #gnutls_ia_server_credentials_t structure.
+ * @func: is the callback function
+ *
+ * Set the TLS/IA AVP callback handler used for the session.
+ *
+ * The callback's function form is:
+ * int (*avp_func) (gnutls_session_t session, void *ptr,
+ * const char *last, size_t lastlen,
+ * char **new, size_t *newlen);
+ *
+ * The @session parameter is the #gnutls_session_t structure
+ * corresponding to the current session. The @ptr parameter is the
+ * application hook pointer, set through
+ * gnutls_ia_set_server_avp_ptr(). The AVP received from the client
+ * is present in @last of @lastlen size. The newly allocated output
+ * AVP to send to the client should be placed in *@new of *@newlen
+ * size.
+ *
+ * The AVP callback is called to process incoming AVPs from the
+ * client, and to get a new AVP to send to the client. It can also be
+ * used to instruct the TLS/IA handshake to do go into the
+ * Intermediate or Final phases. It return a negative error code, or
+ * an #gnutls_ia_apptype_t message type.
+ *
+ * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
+ * generated session keys with the TLS/IA inner secret.
+ *
+ * Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
+ * another AVP to the client, return
+ * %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
+ * IntermediatePhaseFinished message should be sent, and return
+ * %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
+ * FinalPhaseFinished message should be sent. In the last two cases,
+ * the contents of the @new and @newlen parameter is not used.
+ *
+ * Note that the callback must use allocate the @new parameter using
+ * gnutls_malloc(), because it is released via gnutls_free() by the
+ * TLS/IA handshake function.
+ **/
+void
+gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
+ gnutls_ia_avp_func avp_func)
+{
+ cred->avp_func = avp_func;
+}
+
+/**
+ * gnutls_ia_set_server_avp_ptr - Sets a pointer to be sent to TLS/IA callback
+ * @cred: is a #gnutls_ia_client_credentials_t structure.
+ * @ptr: is the pointer
+ *
+ * Sets the pointer that will be provided to the TLS/IA callback
+ * function as the first argument.
+ *
+ **/
+void
+gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
+{
+ cred->avp_ptr = ptr;
+}
+
+/**
+ * gnutls_ia_get_server_avp_ptr - Returns the pointer which is sent to TLS/IA callback
+ * @cred: is a #gnutls_ia_client_credentials_t structure.
+ *
+ * Returns the pointer that will be provided to the TLS/IA callback
+ * function as the first argument.
+ *
+ **/
+void *
+gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
+{
+ return cred->avp_ptr;
+}
+
+/**
+ * gnutls_ia_require_inner_phase - Set if a TLS/IA inner phase is required
+ * @session: is a #gnutls_session_t structure.
+ * @require: non-zero if an inner application phase should be required.
+ *
+ * Specify whether a TLS/IA Inner Application Phase will be required
+ * or not. If the TLS session is resumed, it is possibly to optimize
+ * away the inner application phase by calling this function and
+ * specify a zero value for @require.
+ *
+ * For this function to have any effect, it must be called before
+ * gnutls_handshake().
+ *
+ * Whether to invoke the TLS/IA handshake will also depend on whether
+ * the client supports or requested TLS/IA. A server should thus use
+ * gnutls_ia_handshake_p() to decide whether to call
+ * gnutls_ia_handshake() or not.
+ **/
+void
+gnutls_ia_require_inner_phase (gnutls_session_t session, int require)
+{
+ /* XXX. This function should ideally take a TLS/IA credential, but
+ we can't do that, since we don't want the LGPL'd
+ lib/ext_inner_applicaiton.c to call/inspect GPL'd
+ functions/structures. */
+ session->security_parameters.extensions.inner_phase_optional = !require;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 04707e09c5..734f7c82bd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -19,7 +19,7 @@
# along with this file; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-AM_CPPFLAGS = -I../includes -I$(top_srcdir)/includes -I$(top_srcdir)/gl
+AM_CPPFLAGS = -I../gl -I$(top_srcdir)/gl -I../includes -I$(top_srcdir)/includes
AM_LDFLAGS = -no-install
LDADD = ../lib/libgnutls.la ../gl/libgnu.la libutils.la
@@ -33,8 +33,10 @@ EXTRA_DIST = client.p12 noclient.p12 unclient.p12
EXTRA_DIST += encpkcs8.pem unencpkcs8.pem enc2pkcs8.pem
openssl_LDADD = $(LDADD) ../libextra/libgnutls-openssl.la
+tlsia_LDADD = $(LDADD) ../libextra/libgnutls-extra.la \
+ ../gl/libgnu.la @LTLIBREADLINE@
-ctests = simple anonself pskself openssl gc dhepskself set_pkcs12_cred
+ctests = simple anonself pskself openssl gc dhepskself set_pkcs12_cred tlsia
TESTS = pkcs12_neon pkcs8 $(ctests)
check_PROGRAMS = $(ctests)
dist_check_SCRIPTS = pkcs12_neon pkcs8
diff --git a/tests/tlsia.c b/tests/tlsia.c
new file mode 100644
index 0000000000..be4fde9e76
--- /dev/null
+++ b/tests/tlsia.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2004, 2005 Free Software Foundation
+ *
+ * Author: Simon Josefsson
+ *
+ * This file is part of GNUTLS.
+ *
+ * GNUTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* Parts copied from GnuTLS example programs. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+
+#include "utils.h"
+
+#include <readline.h>
+
+/* A very basic TLS client, with anonymous authentication.
+ */
+
+#define MAX_BUF 1024
+#define MSG "Hello TLS"
+
+/* Connects to the peer and returns a socket
+ * descriptor.
+ */
+int
+tcp_connect (void)
+{
+ const char *PORT = "5556";
+ const char *SERVER = "127.0.0.1";
+ int err, sd;
+ struct sockaddr_in sa;
+
+ /* connects to server
+ */
+ sd = socket (AF_INET, SOCK_STREAM, 0);
+
+ memset (&sa, '\0', sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (atoi (PORT));
+ inet_pton (AF_INET, SERVER, &sa.sin_addr);
+
+ err = connect (sd, (struct sockaddr *) & sa, sizeof (sa));
+ if (err < 0)
+ {
+ fprintf (stderr, "Connect error\n");
+ exit (1);
+ }
+
+ return sd;
+}
+
+/* closes the given socket descriptor.
+ */
+void
+tcp_close (int sd)
+{
+ shutdown (sd, SHUT_RDWR); /* no more receptions */
+ close (sd);
+}
+
+int client_avp (gnutls_session_t session, void *ptr,
+ const char *last, size_t lastlen,
+ char **new, size_t *newlen)
+{
+ static int iter = 0;
+ char *p;
+
+ if (last)
+ printf ("client: received %d bytes AVP: `%.*s'\n",
+ lastlen, lastlen, last);
+ else
+ printf ("client: new application phase\n");
+
+ switch (iter)
+ {
+ case 0:
+ p = "client's first AVP, next will be empty";
+ break;
+
+ case 1:
+ p = "";
+ break;
+
+ case 2:
+ p = "client avp";
+ break;
+
+ default:
+ p = "final client AVP, we'll restart next";
+ iter = -1;
+ break;
+ }
+
+ iter++;
+
+ if (debug)
+ p = readline ("Client TLS/IA AVP: ");
+
+ *new = gnutls_strdup (p);
+ if (!*new)
+ return -1;
+ *newlen = strlen (*new);
+
+ printf ("client: sending %d bytes AVP: `%s'\n", *newlen, *new);
+
+ gnutls_ia_permute_inner_secret (session, 3, "foo");
+
+ return 0;
+}
+
+void
+client (void)
+{
+ int ret, sd, ii;
+ gnutls_session_t session;
+ char buffer[MAX_BUF + 1];
+ gnutls_anon_client_credentials_t anoncred;
+ gnutls_ia_client_credentials_t iacred;
+ /* Need to enable anonymous KX specifically. */
+ const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
+
+ gnutls_global_init ();
+ gnutls_global_init_extra();
+
+ gnutls_anon_allocate_client_credentials (&anoncred);
+ gnutls_ia_allocate_client_credentials(&iacred);
+
+ /* Initialize TLS session
+ */
+ gnutls_init (&session, GNUTLS_CLIENT);
+
+ /* Use default priorities */
+ gnutls_set_default_priority (session);
+ gnutls_kx_set_priority (session, kx_prio);
+
+ /* put the anonymous credentials to the current session
+ */
+ gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+ gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
+
+ /* connect to the peer
+ */
+ sd = tcp_connect ();
+
+ gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
+
+ /* Enable TLS/IA. */
+ gnutls_ia_set_client_avp_function (iacred, client_avp);
+
+ /* Perform the TLS handshake
+ */
+ ret = gnutls_handshake (session);
+
+ if (ret < 0)
+ {
+ fail ("client: Handshake failed\n");
+ gnutls_perror (ret);
+ goto end;
+ }
+ else
+ {
+ success ("client: Handshake was completed\n");
+ }
+
+ /*
+ To test TLS/IA alert's (the server will print that a fatal alert
+ was received):
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_INNER_APPLICATION_FAILURE);
+ */
+
+ if (!gnutls_ia_handshake_p (session))
+ fail ("client: No TLS/IA negotiation\n");
+ else
+ {
+ success ("client: TLS/IA handshake\n");
+
+ ret = gnutls_ia_handshake (session);
+
+ if (ret < 0)
+ {
+ fail ("client: TLS/IA handshake failed\n");
+ gnutls_perror (ret);
+ goto end;
+ }
+ else
+ {
+ success ("client: TLS/IA Handshake was completed\n");
+ }
+ }
+
+ gnutls_record_send (session, MSG, strlen (MSG));
+
+ ret = gnutls_record_recv (session, buffer, MAX_BUF);
+ if (ret == 0)
+ {
+ success ("client: Peer has closed the TLS connection\n");
+ goto end;
+ }
+ else if (ret < 0)
+ {
+ fail ("client: Error: %s\n", gnutls_strerror (ret));
+ goto end;
+ }
+
+ if (debug)
+ {
+ printf ("- Received %d bytes: ", ret);
+ for (ii = 0; ii < ret; ii++)
+ {
+ fputc (buffer[ii], stdout);
+ }
+ fputs ("\n", stdout);
+ }
+
+ gnutls_bye (session, GNUTLS_SHUT_RDWR);
+
+end:
+
+ tcp_close (sd);
+
+ gnutls_deinit (session);
+
+ gnutls_ia_free_client_credentials (iacred);
+
+ gnutls_anon_free_client_credentials (anoncred);
+
+ gnutls_global_deinit ();
+}
+
+/* This is a sample TLS 1.0 echo server, for anonymous authentication only.
+ */
+
+#define SA struct sockaddr
+#define MAX_BUF 1024
+#define PORT 5556 /* listen to 5556 port */
+#define DH_BITS 1024
+
+/* These are global */
+gnutls_anon_server_credentials_t anoncred;
+gnutls_ia_server_credentials_t iacred;
+
+gnutls_session_t
+initialize_tls_session (void)
+{
+ gnutls_session_t session;
+ const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
+
+ gnutls_init (&session, GNUTLS_SERVER);
+
+ /* avoid calling all the priority functions, since the defaults
+ * are adequate.
+ */
+ gnutls_set_default_priority (session);
+ gnutls_kx_set_priority (session, kx_prio);
+
+ gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+
+ gnutls_dh_set_prime_bits (session, DH_BITS);
+
+ return session;
+}
+
+static gnutls_dh_params_t dh_params;
+
+static int
+generate_dh_params (void)
+{
+
+ /* Generate Diffie Hellman parameters - for use with DHE
+ * kx algorithms. These should be discarded and regenerated
+ * once a day, once a week or once a month. Depending on the
+ * security requirements.
+ */
+ gnutls_dh_params_init (&dh_params);
+ gnutls_dh_params_generate2 (dh_params, DH_BITS);
+
+ return 0;
+}
+
+int err, listen_sd, i;
+int sd, ret;
+struct sockaddr_in sa_serv;
+struct sockaddr_in sa_cli;
+socklen_t client_len;
+char topbuf[512];
+gnutls_session_t session;
+char buffer[MAX_BUF + 1];
+int optval = 1;
+
+int server_avp (gnutls_session_t session, void *ptr,
+ const char *last, size_t lastlen,
+ char **new, size_t *newlen)
+{
+ static int iter = 0;
+ char *p;
+
+ if (last)
+ printf ("server: received %d bytes AVP: `%.*s'\n",
+ lastlen, lastlen, last);
+
+ gnutls_ia_permute_inner_secret (session, 3, "foo");
+
+ switch (iter)
+ {
+ case 0:
+ p = "first server AVP";
+ break;
+
+ case 1:
+ p = "second server AVP, next will be empty, then a intermediate finish";
+ break;
+
+ case 2:
+ p = "";
+ break;
+
+ case 3:
+ p = "1";
+ break;
+
+ case 4:
+ p = "server avp, after intermediate finish, next another intermediate";
+ break;
+
+ case 5:
+ p = "1";
+ break;
+
+ case 6:
+ p = "server avp, next will be the finish phase";
+ break;
+
+ default:
+ p = "2";
+ break;
+ }
+
+ iter++;
+
+ if (debug)
+ p = readline ("Server TLS/IA AVP (type '1' to sync, '2' to finish): ");
+
+ if (!p)
+ return -1;
+
+ if (strcmp (p, "1") == 0)
+ {
+ success ("server: Sending IntermediatePhaseFinished...\n");
+ return 1;
+ }
+
+ if (strcmp (p, "2") == 0)
+ {
+ success ("server: Sending FinalPhaseFinished...\n");
+ return 2;
+ }
+
+ *new = gnutls_strdup (p);
+ if (!*new)
+ return -1;
+ *newlen = strlen (*new);
+
+ printf ("server: sending %d bytes AVP: `%s'\n", *newlen, *new);
+
+ return 0;
+}
+
+void
+server_start (void)
+{
+ /* this must be called once in the program
+ */
+ gnutls_global_init ();
+
+ gnutls_anon_allocate_server_credentials (&anoncred);
+ gnutls_ia_allocate_server_credentials (&iacred);
+
+ success ("Launched, generating DH parameters...\n");
+
+ generate_dh_params ();
+
+ gnutls_anon_set_server_dh_params (anoncred, dh_params);
+
+ /* Socket operations
+ */
+ listen_sd = socket (AF_INET, SOCK_STREAM, 0);
+ if (err == -1)
+ {
+ perror ("socket");
+ fail ("server: socket failed\n");
+ return;
+ }
+
+ memset (&sa_serv, '\0', sizeof (sa_serv));
+ sa_serv.sin_family = AF_INET;
+ sa_serv.sin_addr.s_addr = INADDR_ANY;
+ sa_serv.sin_port = htons (PORT); /* Server Port number */
+
+ setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));
+
+ err = bind (listen_sd, (SA *) & sa_serv, sizeof (sa_serv));
+ if (err == -1)
+ {
+ perror ("bind");
+ fail ("server: bind failed\n");
+ return;
+ }
+
+ err = listen (listen_sd, 1024);
+ if (err == -1)
+ {
+ perror ("listen");
+ fail ("server: listen failed\n");
+ return;
+ }
+
+ success ("server: ready. Listening to port '%d'\n", PORT);
+}
+
+void
+server (void)
+{
+ client_len = sizeof (sa_cli);
+
+ session = initialize_tls_session ();
+
+ sd = accept (listen_sd, (SA *) & sa_cli, &client_len);
+
+ success ("server: connection from %s, port %d\n",
+ inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf,
+ sizeof (topbuf)), ntohs (sa_cli.sin_port));
+
+ gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
+
+ /* Enable TLS/IA. */
+ gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
+ gnutls_ia_set_server_avp_function (iacred, server_avp);
+
+ ret = gnutls_handshake (session);
+ if (ret < 0)
+ {
+ close (sd);
+ gnutls_deinit (session);
+ fail ("server: Handshake has failed (%s)\n\n", gnutls_strerror (ret));
+ return;
+ }
+ success ("server: Handshake was completed\n");
+
+ if (!gnutls_ia_handshake_p (session))
+ fail ("server: No TLS/IA negotiation\n");
+ else
+ {
+ success ("server: TLS/IA handshake\n");
+
+ ret = gnutls_ia_handshake (session);
+
+ if (ret < 0)
+ {
+ fail ("server: TLS/IA handshake failed\n");
+ gnutls_perror (ret);
+ return;
+ }
+ else
+ {
+ success ("server: TLS/IA Handshake was completed\n");
+ }
+ }
+
+ /* see the Getting peer's information example */
+ /* print_info(session); */
+
+ i = 0;
+ for (;;)
+ {
+ bzero (buffer, MAX_BUF + 1);
+ ret = gnutls_record_recv (session, buffer, MAX_BUF);
+
+ if (ret == 0)
+ {
+ success ("server: Peer has closed the GNUTLS connection\n");
+ break;
+ }
+ else if (ret < 0)
+ {
+ if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
+ {
+ gnutls_alert_description_t alert;
+ const char *err;
+ alert = gnutls_alert_get(session);
+ err = gnutls_alert_get_name(alert);
+ if (err)
+ printf ("Fatal alert: %s\n", err);
+ }
+
+ fail ("server: Received corrupted data(%d). Closing...\n", ret);
+ break;
+ }
+ else if (ret > 0)
+ {
+ /* echo data back to the client
+ */
+ gnutls_record_send (session, buffer, strlen (buffer));
+ }
+ }
+ /* do not wait for the peer to close the connection.
+ */
+ gnutls_bye (session, GNUTLS_SHUT_WR);
+
+ close (sd);
+ gnutls_deinit (session);
+
+ close (listen_sd);
+
+ gnutls_ia_free_server_credentials (iacred);
+
+ gnutls_anon_free_server_credentials (anoncred);
+
+ gnutls_global_deinit ();
+
+ success ("server: finished\n");
+}
+
+void
+doit (void)
+{
+ pid_t child;
+
+ server_start ();
+ if (error_count)
+ return;
+
+ child = fork ();
+ if (child < 0)
+ {
+ perror ("fork");
+ fail ("fork");
+ return;
+ }
+
+ if (child)
+ {
+ int status;
+ /* parent */
+ server ();
+ wait (&status);
+ }
+ else
+ client ();
+}