gnutls_cipher_get_tag_size: Added
gnutls_record_overhead_size: Added
gnutls_record_overhead_size2: Added
+gnutls_handshake_set_hook_function: Added
+gnutls_handshake_description_get_name: Added
* Version 3.2.1 (released 2013-06-01)
}
}
+/**
+ * gnutls_handshake_description_get_name:
+ * @type: is a handshake message description
+ *
+ * Convert a #gnutls_handshake_description_t value to a string.
+ *
+ * Returns: a string that contains the name of the specified handshake
+ * message or %NULL.
+ **/
const char *
-_gnutls_handshake2str (gnutls_handshake_description_t handshake)
+gnutls_handshake_description_get_name (gnutls_handshake_description_t type)
{
-
- switch (handshake)
+ switch (type)
{
case GNUTLS_HANDSHAKE_HELLO_REQUEST:
return "HELLO REQUEST";
break;
default:
return "Unknown Handshake packet";
-
}
}
*/
const char *_gnutls_packet2str (content_type_t packet);
-const char *_gnutls_handshake2str (gnutls_handshake_description_t handshake);
+inline static const char* _gnutls_handshake2str(unsigned x)
+{
+const char* s = gnutls_handshake_description_get_name(x);
+ if (s == NULL) return "Unknown Handshake packet";
+ else return s;
+}
void _gnutls_dump_mpi (const char *prefix, bigint_t a);
void _gnutls_dump_vector (const char *prefix, const uint8_t *a, size_t a_size);
return _gnutls_send_handshake (session, bufel, type);
}
+inline
+static int call_hook_func(gnutls_session_t session, gnutls_handshake_description_t type,
+ unsigned post, unsigned incoming)
+{
+ if (session->internals.h_hook == NULL)
+ return 0;
+ else
+ {
+ if (session->internals.h_type == type || session->internals.h_type == GNUTLS_HANDSHAKE_ANY)
+ return session->internals.h_hook(session, type, post, incoming);
-
+ return 0;
+ }
+}
/* This function sends a handshake message of type 'type' containing the
* data specified here. If the previous _gnutls_send_handshake() returned
return ret;
}
+ ret = call_hook_func(session, type, 0, 0);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _mbuffer_xfree(&bufel);
+ return ret;
+ }
+
session->internals.last_handshake_out = type;
ret = _gnutls_handshake_io_cache_int (session, type, bufel);
break;
}
+ ret = call_hook_func(session, type, 1, 0);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
return ret;
}
return 0;
}
-
/* This function will receive handshake messages of the given types,
* and will pass the message to the right place in order to be processed.
* E.g. for the SERVER_HELLO message (if it is expected), it will be
session->internals.last_handshake_in = hsk.htype;
+ ret = call_hook_func(session, hsk.htype, 0, 1);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
ret = _gnutls_handshake_hash_add_recvd (session, hsk.htype,
hsk.header, hsk.header_size,
hsk.data.data, hsk.data.length);
goto cleanup;
}
- goto cleanup; /* caller doesn't need dataptr */
-
break;
case GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST:
ret = _gnutls_recv_hello_verify_request (session, hsk.data.data, hsk.data.length);
and ClientHello needs to be sent again. */
ret = 1;
- goto cleanup; /* caller doesn't need dataptr */
-
break;
case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
if (hsk.data.length == 0)
goto cleanup;
}
+ ret = call_hook_func(session, hsk.htype, 1, 1);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
if (buf)
{
*buf = hsk.data;
unsigned int packets_dropped;
} dtls_st;
-
typedef union
{
void *ptr;
/* post client hello callback (server side only)
*/
gnutls_handshake_post_client_hello_func user_hello_func;
+ /* handshake hook function */
+ gnutls_handshake_hook_func h_hook;
+ unsigned int h_type; /* the hooked type */
/* holds the selected certificate and key.
* use _gnutls_selected_certs_deinit() and _gnutls_selected_certs_set()
_gnutls_mpi_release (&session->key.rsa[1]);
_gnutls_mpi_release (&session->key.dh_secret);
-
+
gnutls_free (session);
}
session->internals.user_hello_func = func;
}
+
/**
* gnutls_session_enable_compatibility_mode:
* @session: is a #gnutls_session_t structure.
return 0;
}
+/**
+ * gnutls_handshake_set_hook_function:
+ * @session: is a #gnutls_session_t structure.
+ * @htype: the %gnutls_handshake_description_t of the message to hook at.
+ * @func: is the function to be called
+ *
+ * This function will set a callback to be called after or before the specified
+ * handshake message has been received or generated. This is a
+ * generalization of gnutls_handshake_set_post_client_hello_function().
+ *
+ * This callback must return 0 on success or a gnutls error code to
+ * terminate the handshake.
+ *
+ * Note to hook at all handshake messages use an @htype of %GNUTLS_HANDSHAKE_ANY.
+ *
+ * Warning: You should not use this function to terminate the
+ * handshake based on client input unless you know what you are
+ * doing. Before the handshake is finished there is no way to know if
+ * there is a man-in-the-middle attack being performed.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
+ **/
+void
+gnutls_handshake_set_hook_function (gnutls_session_t session,
+ unsigned int htype,
+ gnutls_handshake_hook_func func)
+{
+ session->internals.h_hook = func;
+ session->internals.h_type = htype;
+}
+
GNUTLS_HANDSHAKE_CLIENT_HELLO_V2 = 1024,
} gnutls_handshake_description_t;
+#define GNUTLS_HANDSHAKE_ANY ((unsigned int)-1)
+
+const char *
+gnutls_handshake_description_get_name (gnutls_handshake_description_t type);
+
/**
* gnutls_certificate_status_t:
* @GNUTLS_CERT_INVALID: The certificate is not signed by one of the
gnutls_datum_t session_entry);
time_t gnutls_db_check_entry_time (gnutls_datum_t *entry);
+ /**
+ * gnutls_handshake_hook_func:
+ * @session: the current session
+ * @htype: the type of the handshake message (%gnutls_handshake_description_t)
+ * @post: non zero if this is an post-process/generation call and zero otherwise
+ * @incoming: non zero if this is an incoming message and zero if this is an outgoing message
+ *
+ * Function prototype for handshake hooks. It is set using
+ * gnutls_handshake_set_hook_function().
+ *
+ * Returns: Non zero on error.
+ */
+
+ typedef int (*gnutls_handshake_hook_func) (gnutls_session_t, unsigned int htype, unsigned int post, unsigned int incoming);
+ void gnutls_handshake_set_hook_function (gnutls_session_t session,
+ unsigned int htype,
+ gnutls_handshake_hook_func func);
+
typedef int (*gnutls_handshake_post_client_hello_func) (gnutls_session_t);
void
gnutls_handshake_set_post_client_hello_function (gnutls_session_t session,
gnutls_cipher_get_tag_size;
gnutls_record_overhead_size;
gnutls_record_overhead_size2;
+ gnutls_handshake_set_hook_function;
+ gnutls_handshake_description_get_name;
} GNUTLS_3_0_0;
GNUTLS_PRIVATE {
return 0;
}
+unsigned int msg_order[] = {
+ GNUTLS_HANDSHAKE_CLIENT_HELLO,
+ GNUTLS_HANDSHAKE_SERVER_HELLO,
+ GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
+ GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE,
+ GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST,
+ GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
+ GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
+ GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE,
+ GNUTLS_HANDSHAKE_FINISHED,
+ GNUTLS_HANDSHAKE_FINISHED,
+};
+
+static int handshake_callback (gnutls_session_t session, unsigned int htype, unsigned int post, unsigned int incoming)
+{
+static unsigned idx = 0;
+
+ if (post > 0)
+ {
+ if (msg_order[idx] != htype)
+ {
+ fail("%s: %s, expected %s\n", incoming!=0?"Received":"Sent", gnutls_handshake_description_get_name(htype), gnutls_handshake_description_get_name(msg_order[idx]));
+ exit(1);
+ }
+ idx++;
+ }
+ return 0;
+}
+
static int
server_callback (gnutls_session_t session)
{
gnutls_certificate_set_verify_function (serverx509cred, server_callback);
gnutls_certificate_server_set_request (server, GNUTLS_CERT_REQUEST);
gnutls_handshake_set_post_client_hello_function (server, post_client_hello_callback);
+ gnutls_handshake_set_hook_function (server, GNUTLS_HANDSHAKE_ANY, handshake_callback);
/* Init client */
gnutls_certificate_allocate_credentials (&clientx509cred);