sha1 is broken and should no longer be used. This commit introduces
the new server feature "sha256". It is announced during the handshake
with the client. The client code is patched to detect whether the
server supports the feature and uses sha256 if it does.
This change is backwards compatible. That is, old clients can still
connect to a new server (using sha1). Also new clients can connect
to an old server (and also use sha1 in this case).
return send_sb(ct, 0, command, len, SBD_COMMAND, false);
}
return send_sb(ct, 0, command, len, SBD_COMMAND, false);
}
+static bool has_feature(const char *feature, struct client_task *ct)
+{
+ return find_arg(feature, ct->features) >= 0? true : false;
+}
+
/*
* This function reads or writes to the socket file descriptor which
* corresponds to an established connection between the client and the server.
/*
* This function reads or writes to the socket file descriptor which
* corresponds to an established connection between the client and the server.
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
+ {
+ /*
+ * Use sha256 iff the server announced the feature. After 0.7.0
+ * we may request and use the feature unconditionally. After
+ * 0.8.0 we no longer need to request the feature.
+ */
+ bool has_sha256;
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return 0;
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return 0;
- sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+ has_sha256 = has_feature("sha256", ct);
+ sprintf(buf, AUTH_REQUEST_MSG "%s%s", ct->user, has_sha256?
+ " sha256" : "");
PARA_INFO_LOG("--> %s\n", buf);
ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;
return 0;
PARA_INFO_LOG("--> %s\n", buf);
ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;
return 0;
case CL_SENT_AUTH:
/*
* Receive challenge and session keys, decrypt the challenge and
case CL_SENT_AUTH:
/*
* Receive challenge and session keys, decrypt the challenge and
free(sbb.iov.iov_base);
if (ret < 0)
goto out;
free(sbb.iov.iov_base);
if (ret < 0)
goto out;
- ct->challenge_hash = para_malloc(HASH_SIZE);
- hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+ ct->challenge_hash = para_malloc(HASH2_SIZE);
+
+ if (has_feature("sha256", ct)) {
+ hash2_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+ hash2_to_asc(ct->challenge_hash, buf);
+ } else {
+ hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+ hash_to_asc(ct->challenge_hash, buf);
+ }
ct->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE, SESSION_KEY_LEN);
ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE + SESSION_KEY_LEN,
SESSION_KEY_LEN);
ct->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE, SESSION_KEY_LEN);
ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE + SESSION_KEY_LEN,
SESSION_KEY_LEN);
- hash_to_asc(ct->challenge_hash, buf);
PARA_INFO_LOG("--> %s\n", buf);
ct->status = CL_RECEIVED_CHALLENGE;
return 0;
}
case CL_RECEIVED_CHALLENGE:
PARA_INFO_LOG("--> %s\n", buf);
ct->status = CL_RECEIVED_CHALLENGE;
return 0;
}
case CL_RECEIVED_CHALLENGE:
- ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
- SBD_CHALLENGE_RESPONSE, false);
+ if (has_feature("sha256", ct))
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH2_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
+ else
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
if (ret != 0)
ct->challenge_hash = NULL;
if (ret <= 0)
if (ret != 0)
ct->challenge_hash = NULL;
if (ret <= 0)
}
struct connection_features {
}
struct connection_features {
- int dummy; /* none at the moment */
+ bool sha256_requested; /* can be removed after 0.7.0 */
};
static int parse_auth_request(char *buf, int len, const struct user **u,
};
static int parse_auth_request(char *buf, int len, const struct user **u,
continue;
if (strcmp(features[i], "aes_ctr128") == 0)
continue;
continue;
if (strcmp(features[i], "aes_ctr128") == 0)
continue;
+ /*
+ * ->sha256_requested can go away after 0.7.0 but the
+ * check has to stay until 0.9.0.
+ */
+ if (strcmp(features[i], "sha256") == 0)
+ cf->sha256_requested = true;
else {
ret = -E_BAD_FEATURE;
goto out;
else {
ret = -E_BAD_FEATURE;
goto out;
{
int ret;
unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
{
int ret;
unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
- unsigned char challenge_hash[HASH_SIZE];
+ unsigned char challenge_hash[HASH2_SIZE];
char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
/* send Welcome message */
ret = write_va_buffer(fd, "This is para_server, version "
PACKAGE_VERSION ".\n"
/* send Welcome message */
ret = write_va_buffer(fd, "This is para_server, version "
PACKAGE_VERSION ".\n"
+ "Features: sha256\n" /* no longer announce this after 0.8.0 */
);
if (ret < 0)
goto net_err;
);
if (ret < 0)
goto net_err;
* of the random data.
*/
ret = -E_BAD_AUTH;
* of the random data.
*/
ret = -E_BAD_AUTH;
- if (numbytes != HASH_SIZE)
- goto net_err;
- hash_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash);
- if (memcmp(challenge_hash, buf, HASH_SIZE))
- goto net_err;
+ if (cf.sha256_requested) {
+ if (numbytes != HASH2_SIZE)
+ goto net_err;
+ hash2_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash);
+ if (memcmp(challenge_hash, buf, HASH2_SIZE))
+ goto net_err;
+ } else { /* old client. This can be removed after 0.7.0 */
+ if (numbytes != HASH_SIZE)
+ goto net_err;
+ hash_function((char *)rand_buf, APC_CHALLENGE_SIZE, challenge_hash);
+ if (memcmp(challenge_hash, buf, HASH_SIZE))
+ goto net_err;
+ }
/* auth successful */
alarm(0);
PARA_INFO_LOG("good auth for %s\n", cc->u->name);
/* auth successful */
alarm(0);
PARA_INFO_LOG("good auth for %s\n", cc->u->name);