[gnutls-devel] handshake packet re-ordering issue during encrypted handshake

Guillaume Roguez guillaume.roguez at savoirfairelinux.com
Mon Jun 6 15:50:50 CEST 2016


>> On Fri, 2016-06-03 at 15:43 -0400, Guillaume Roguez wrote:
>>> Hi,
>>> 
>>> Using gnutls 3.4.12, I'm trying to implement an encrypted and
>>> authenticated UDP channel using DTLS.
>>> To not send the certificate in clear during the handshake, I'm doing
>>> a double hanshake, starting
>>> with an anonymous credential session, then forcing a re-handshake
>>> using a certified credential session.
>>> 
>>> My in-production code was worked well... until some users complain
>>> about the certified handshake not working.
>>> After investigation I've found that the packet containing (completely
>>> or partially) the client certificate is
>>> shift in time at server side.
>>> This packet is encryted as it's inside anonymous session, quite big
>>> (all allowed bytes used = MTU size)
>>> and re-ordered by the network.
>> 
>> Hi,
>> Could you modify tests/mini-dtls-rehandshake.c to do the same re-
>> ordering so that I can reproduce and also include it in the test suite?
>> 
> 
> For sure, I'm joining a patch to modify this test (also utils to permit
> extra arguments). It must be applied inside tests/ directory.
> Notice you need to give CA, certificate and key as arguments for x509
> authentification.
> 
> The patch gives a working version, uncomment the line:
> 
> //#define DO_PACKET_REORDERING 1
> 
> to obtain a version with a simulation of packet re-ordering.
> The second handshake will never success.
> 
>>> To not enter into a complex code (our product is https://ring.cx),
>>> I've written a simple client/server working on GNU/Linux
>>> based from samples found in gnutls documentation, added a bit of code
>>> to do the double handshake
>>> and simulate the packet re-ordering by swapping the first big packet
>>> with the next one (only in server code).
>>> Questions: What am I doing wrong? In this case, what's the good way
>>> to implement my anonymous certificate exchange?
>> 
>> I'll have to check the debugging output on what's wrong. There are
>> several tests for re-orders and lost packets (tests/dtls/dtls) but it
>> may be that a corner case is not covered (the issue may also depend on
>> packet size). The best would be to have an easy to use reproducer in
>> order for me to check it.
>> 
>> regards,
>> Nikos
> 
> Thanks,
> Guillaume


My attachment has been drop by the ML engine. I'm putting it inline right here:

--- mini-dtls-rehandshake.c
+++ mini-dtls-rehandshake.c
@@ -71,2 +71,12 @@
 
+#define FIRST_PRIORITY "SECURE192:-KX-ALL:-VERS-TLS-ALL:+VERS-DTLS-ALL:+ANON-DH:-RSA:%SERVER_PRECEDENCE:%SAFE_RENEGOTIATION"
+#define CERT_PRIORITY "SECURE192:-VERS-TLS-ALL:+VERS-DTLS-ALL:-RSA:%SERVER_PRECEDENCE:%SAFE_RENEGOTIATION"
+#define MTU 1500
+//#define DO_PACKET_REORDERING 1
+
+static int server_fd = -1;
+static char pkt_buf[MAX_BUF];
+static int pkt_found = 0;
+static int pkt_delivered = 0;
+
 static ssize_t
@@ -76,2 +86,22 @@
 
+#ifdef DO_PACKET_REORDERING
+    // simulation of packet re-ordering
+    // invert the packet that reach MTU with the next one
+    if (fd == server_fd) {
+        if (!pkt_found && len == MTU) {
+            memcpy(pkt_buf, data, len);
+            pkt_found = 1;
+            printf("*** packet delayed\n");
+            return len;
+        }
+        if (pkt_found && !pkt_delivered) {
+            int res = send(fd, data, len, 0);
+            send(fd, pkt_buf, MTU, 0);
+            pkt_delivered = 1;
+            printf("*** swap done\n");
+            return res;
+        }
+    }
+#endif
+
 	return send(fd, data, len, 0);
@@ -79,2 +109,24 @@
 
+static int
+check_certificate(gnutls_session_t session)
+{
+    if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
+        return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+    unsigned int status = 0;
+    int ret = gnutls_certificate_verify_peers2(session, &status);
+    if (ret < 0 || (status & GNUTLS_CERT_SIGNATURE_FAILURE) != 0) {
+        return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+    unsigned int cert_list_size = 0;
+    const gnutls_datum_t *cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
+    if (cert_list == NULL) {
+        return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+    return GNUTLS_E_SUCCESS;
+}
+
 static void client(int fd, int server_init)
@@ -84,2 +136,3 @@
 	gnutls_anon_client_credentials_t anoncred;
+	gnutls_certificate_credentials_t x509_cred;
 	gnutls_session_t session;
@@ -97,2 +150,8 @@
 
+	/* x509 crediandials */
+    gnutls_certificate_allocate_credentials(&x509_cred);
+	gnutls_certificate_set_x509_trust_file(x509_cred, extra_argv[0], GNUTLS_X509_FMT_PEM);
+	gnutls_certificate_set_x509_key_file(x509_cred, extra_argv[1], extra_argv[2], GNUTLS_X509_FMT_PEM);
+	gnutls_certificate_set_verify_function(x509_cred, check_certificate);
+
 	/* Initialize TLS session
@@ -100,3 +159,3 @@
 	gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
-	gnutls_dtls_set_mtu(session, 1500);
+	gnutls_dtls_set_mtu(session, MTU);
 
@@ -104,3 +163,3 @@
 	gnutls_priority_set_direct(session,
-				   "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
+							   FIRST_PRIORITY,
 				   NULL);
@@ -135,2 +194,6 @@
 
+	gnutls_priority_set_direct(session, CERT_PRIORITY, NULL);
+    gnutls_credentials_clear(session);
+    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+
 	if (!server_init) {
@@ -208,2 +271,13 @@
 
+static gnutls_dh_params_t dh_params;
+
+static void
+generate_dh_params(void)
+{
+	int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH);
+	gnutls_dh_params_init(&dh_params);
+	success("Generating DH...\n");
+	gnutls_dh_params_generate2(dh_params, bits);
+}
+
 static void server(int fd, int server_init)
@@ -213,2 +287,3 @@
 	gnutls_anon_server_credentials_t anoncred;
+	gnutls_certificate_credentials_t x509_cred;
 	gnutls_session_t session;
@@ -217,2 +292,3 @@
 	global_init();
+	generate_dh_params();
 
@@ -224,2 +300,10 @@
 	gnutls_anon_allocate_server_credentials(&anoncred);
+	gnutls_anon_set_server_dh_params(anoncred, dh_params);
+
+	/* x509 crediandials */
+    gnutls_certificate_allocate_credentials(&x509_cred);
+	gnutls_certificate_set_x509_trust_file(x509_cred, extra_argv[0], GNUTLS_X509_FMT_PEM);
+	gnutls_certificate_set_x509_key_file(x509_cred, extra_argv[1], extra_argv[2], GNUTLS_X509_FMT_PEM);
+    gnutls_certificate_set_verify_function(x509_cred, check_certificate);
+	gnutls_certificate_set_dh_params(x509_cred, dh_params);
 
@@ -232,3 +316,3 @@
 	gnutls_priority_set_direct(session,
-				   "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
+							   FIRST_PRIORITY,
 				   NULL);
@@ -236,2 +320,3 @@
 	gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
+	gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
 
@@ -259,2 +344,6 @@
 
+	gnutls_priority_set_direct(session, CERT_PRIORITY, NULL);
+    gnutls_credentials_clear(session);
+    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+
 	/* see the Getting peer's information example */
@@ -348,2 +437,5 @@
 
+	pkt_found = 0;
+    pkt_delivered = 0;
+
 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
@@ -365,2 +457,3 @@
 
+		server_fd = fd[0];
 		server(fd[0], server_initiated);
--- utils.c
+++ utils.c
@@ -222,4 +222,10 @@
 
+int extra_argc = 0;
+char ** extra_argv = NULL;
+
 int main(int argc, char *argv[])
 {
+	int extra_first = -1;
+    int copy_argc = argc;
+
 	do
@@ -238,4 +244,11 @@
 			return 1;
+		} else {
+            extra_first = argc - 1;
+        }
+	while (argc-- > 2);
+
+    if (extra_first != -1) {
+        extra_argc = copy_argc - extra_first;
+        extra_argv = argv + extra_first;
 		}
-	while (argc-- > 1) ;
 
--- utils.h
+++ utils.h
@@ -81,2 +81,5 @@
 
+extern int extra_argc;
+extern char ** extra_argv;
+
 #endif				/* UTILS_H */




More information about the Gnutls-devel mailing list