Skip to content

Commit

Permalink
psk_client_callback, 128-byte id bug.
Browse files Browse the repository at this point in the history
Fix a bug in handling of 128 byte long PSK identity in
psk_client_callback.

OpenSSL supports PSK identities of up to (and including) 128 bytes in
length. PSK identity is obtained via the psk_client_callback,
implementors of which are expected to provide a NULL-terminated
identity. However, the callback is invoked with only 128 bytes of
storage thus making it impossible to return a 128 byte long identity and
the required additional NULL byte.

This CL fixes the issue by passing in a 129 byte long buffer into the
psk_client_callback. As a safety precaution, this CL also zeroes out the
buffer before passing it into the callback, uses strnlen for obtaining
the length of the identity returned by the callback, and aborts the
handshake if the identity (without the NULL terminator) is longer than
128 bytes.

(Original patch amended to achieve strnlen in a different way.)

Reviewed-by: Rich Salz <rsalz@openssl.org>
(cherry picked from commit be0d851)
  • Loading branch information
Adam Langley authored and ekasper committed Sep 5, 2014
1 parent 11853c5 commit 13ce52b
Showing 1 changed file with 20 additions and 9 deletions.
29 changes: 20 additions & 9 deletions ssl/s3_clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2960,7 +2960,11 @@ int ssl3_send_client_key_exchange(SSL *s)
#ifndef OPENSSL_NO_PSK
else if (alg_k & SSL_kPSK)
{
char identity[PSK_MAX_IDENTITY_LEN];
/* The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes
* to return a \0-terminated identity. The last byte
* is for us for simulating strnlen. */
char identity[PSK_MAX_IDENTITY_LEN + 2];
size_t identity_len;
unsigned char *t = NULL;
unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
unsigned int pre_ms_len = 0, psk_len = 0;
Expand All @@ -2974,8 +2978,9 @@ int ssl3_send_client_key_exchange(SSL *s)
goto err;
}

memset(identity, 0, sizeof(identity));
psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
identity, PSK_MAX_IDENTITY_LEN,
identity, sizeof(identity) - 1,
psk_or_pre_ms, sizeof(psk_or_pre_ms));
if (psk_len > PSK_MAX_PSK_LEN)
{
Expand All @@ -2989,7 +2994,14 @@ int ssl3_send_client_key_exchange(SSL *s)
SSL_R_PSK_IDENTITY_NOT_FOUND);
goto psk_err;
}

identity[PSK_MAX_IDENTITY_LEN + 1] = '\0';
identity_len = strlen(identity);
if (identity_len > PSK_MAX_IDENTITY_LEN)
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_INTERNAL_ERROR);
goto psk_err;
}
/* create PSK pre_master_secret */
pre_ms_len = 2+psk_len+2+psk_len;
t = psk_or_pre_ms;
Expand Down Expand Up @@ -3023,14 +3035,13 @@ int ssl3_send_client_key_exchange(SSL *s)
s->session->master_key_length =
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key,
psk_or_pre_ms, pre_ms_len);
n = strlen(identity);
s2n(n, p);
memcpy(p, identity, n);
n+=2;
psk_or_pre_ms, pre_ms_len);
s2n(identity_len, p);
memcpy(p, identity, identity_len);
n = 2 + identity_len;
psk_err = 0;
psk_err:
OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
OPENSSL_cleanse(identity, sizeof(identity));
OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
if (psk_err != 0)
{
Expand Down

0 comments on commit 13ce52b

Please sign in to comment.