Use sideband also for challenge response.
authorAndre Noll <maan@systemlinux.org>
Wed, 4 Jan 2012 20:47:55 +0000 (21:47 +0100)
committerAndre Noll <maan@systemlinux.org>
Sat, 5 May 2012 10:54:53 +0000 (12:54 +0200)
This changes server and client to exchange the challenge response
as a sideband packet if both ends support sideband connections. The
SBD_CHALLENGE_RESPONSE designator is used for this purpose. On the
client side the changes are less intrusive due to an additional
cleanup of the state handling.

During connection setup the client's idea of the state of
the connection is monitored in the ->status variable of struct
client_task. If the client is in the CL_SENT_AUTH state, it receives
the challenge and sends the hash of the decrypted challenge back to the
server. Either operation may fail, and it seems cleaner to separate
the two. So this patch adds the new state CL_RECEIVED_CHALLENGE. The
clients enters this state once it decrypted the received challenge.

client.h
client_common.c
command.c

index a423406238204c3ba9b86e066fc82fead3dc16d9..b841b7e1b6b6d0698a404887429840f2ea6e9a47 100644 (file)
--- a/client.h
+++ b/client.h
@@ -14,6 +14,8 @@ enum {
        CL_RECEIVED_WELCOME,
        /** Client sends the authentification request. */
        CL_SENT_AUTH,
        CL_RECEIVED_WELCOME,
        /** Client sends the authentification request. */
        CL_SENT_AUTH,
+       /** Server sends encrypted challenge. */
+       CL_RECEIVED_CHALLENGE,
        /** Client solves the challenge and sends the result. */
        CL_SENT_CH_RESPONSE,
        /** Server accepts this authentication. */
        /** Client solves the challenge and sends the result. */
        CL_SENT_CH_RESPONSE,
        /** Server accepts this authentication. */
@@ -36,6 +38,8 @@ struct client_task {
        bool use_sideband;
        /** The sideband context, ignored if \a use_sideband is false. */
        struct sb_context *sbc;
        bool use_sideband;
        /** The sideband context, ignored if \a use_sideband is false. */
        struct sb_context *sbc;
+       /** The hash value of the decrypted challenge. */
+       unsigned char *challenge_hash;
        /** The configuration (including the command). */
        struct client_args_info conf;
        /** The config file for client options. */
        /** The configuration (including the command). */
        struct client_args_info conf;
        /** The config file for client options. */
index f3cea05d45a3853c53840a66e5713fc681787ee3..eea14fa8d3a461ce9862b38af3c35a8e807e3568 100644 (file)
@@ -68,6 +68,8 @@ void client_close(struct client_task *ct)
        free(ct->config_file);
        free(ct->key_file);
        client_cmdline_parser_free(&ct->conf);
        free(ct->config_file);
        free(ct->key_file);
        client_cmdline_parser_free(&ct->conf);
+       free(ct->challenge_hash);
+       sb_free(ct->sbc);
        free(ct);
 }
 
        free(ct);
 }
 
@@ -103,6 +105,7 @@ static void client_pre_select(struct sched *s, struct task *t)
 
        case CL_RECEIVED_WELCOME:
        case CL_RECEIVED_PROCEED:
 
        case CL_RECEIVED_WELCOME:
        case CL_RECEIVED_PROCEED:
+       case CL_RECEIVED_CHALLENGE:
                para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
                return;
 
                para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
                return;
 
@@ -297,7 +300,6 @@ static void client_post_select(struct sched *s, struct task *t)
                /* decrypted challenge/session key buffer */
                unsigned char crypt_buf[1024];
                /* the SHA1 of the decrypted challenge */
                /* decrypted challenge/session key buffer */
                unsigned char crypt_buf[1024];
                /* the SHA1 of the decrypted challenge */
-               unsigned char challenge_hash[HASH_SIZE];
 
                if (ct->use_sideband) {
                        struct sb_buffer sbb;
 
                if (ct->use_sideband) {
                        struct sb_buffer sbb;
@@ -326,18 +328,31 @@ static void client_post_select(struct sched *s, struct task *t)
                        if (ret < 0)
                                goto out;
                }
                        if (ret < 0)
                                goto out;
                }
-               hash_function((char *)crypt_buf, CHALLENGE_SIZE, challenge_hash);
+               ct->challenge_hash = para_malloc(HASH_SIZE);
+               hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
                ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
                ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
                        SESSION_KEY_LEN);
                ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
                ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
                        SESSION_KEY_LEN);
-               hash_to_asc(challenge_hash, buf);
+               hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                PARA_INFO_LOG("--> %s\n", buf);
-               ret = write_all(ct->scc.fd, (char *)challenge_hash, HASH_SIZE);
-               if (ret < 0)
-                       goto out;
-               ct->status = CL_SENT_CH_RESPONSE;
+               ct->status = CL_RECEIVED_CHALLENGE;
                return;
                }
                return;
                }
+       case CL_RECEIVED_CHALLENGE:
+               if (ct->use_sideband) {
+                       ret = send_sb(ct, ct->challenge_hash, HASH_SIZE,
+                               SBD_CHALLENGE_RESPONSE, false);
+                       if (ret != 0)
+                               ct->challenge_hash = NULL;
+                       if (ret <= 0)
+                               goto out;
+               } else {
+                       ret = write_all(ct->scc.fd, (char *)ct->challenge_hash, HASH_SIZE);
+                       if (ret < 0)
+                               goto out;
+               }
+               ct->status = CL_SENT_CH_RESPONSE;
+               goto out;
        case CL_SENT_CH_RESPONSE: /* read server response */
                {
                ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
        case CL_SENT_CH_RESPONSE: /* read server response */
                {
                ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
index 5790f11d278f95d4ad09964ab76af5d0ebf9e772..5e13df66bce15a7e759ce1dd85347b9a176a5417 100644 (file)
--- a/command.c
+++ b/command.c
@@ -934,22 +934,28 @@ __noreturn void handle_connect(int fd, const char *peername)
        PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
                CHALLENGE_SIZE, numbytes);
        if (cc->use_sideband) {
        PARA_DEBUG_LOG("sending %u byte challenge + rc4 keys (%zu bytes)\n",
                CHALLENGE_SIZE, numbytes);
        if (cc->use_sideband) {
+               struct iovec iov;
                ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
                buf = NULL;
                if (ret < 0)
                        goto net_err;
                ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false);
                buf = NULL;
                if (ret < 0)
                        goto net_err;
-               buf = para_malloc(HANDSHAKE_BUFSIZE);
+               ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE,
+                       HANDSHAKE_BUFSIZE, &iov);
+               if (ret < 0)
+                       goto net_err;
+               buf = iov.iov_base;
+               numbytes = iov.iov_len;
        } else {
                ret = write_all(fd, buf, numbytes);
                if (ret < 0)
                        goto net_err;
        } else {
                ret = write_all(fd, buf, numbytes);
                if (ret < 0)
                        goto net_err;
+               /* recv challenge response */
+               ret = recv_bin_buffer(fd, buf, HASH_SIZE);
+               if (ret < 0)
+                       goto net_err;
+               numbytes = ret;
        }
        }
-       /* recv challenge response */
-       ret = recv_bin_buffer(fd, buf, HASH_SIZE);
-       if (ret < 0)
-               goto net_err;
-       numbytes = ret;
-       PARA_DEBUG_LOG("received %d bytes challenge response\n", ret);
+       PARA_DEBUG_LOG("received %zu bytes challenge response\n", numbytes);
        ret = -E_BAD_USER;
        if (!cc->u)
                goto net_err;
        ret = -E_BAD_USER;
        if (!cc->u)
                goto net_err;