aboutsummaryrefslogtreecommitdiff
path: root/ssl/t1_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/t1_lib.c')
-rw-r--r--ssl/t1_lib.c291
1 files changed, 188 insertions, 103 deletions
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 7831046b9261..e60c88bd5b27 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -132,6 +132,9 @@ static int ssl_check_clienthello_tlsext_early(SSL *s);
int ssl_check_serverhello_tlsext(SSL *s);
#endif
+#define CHECKLEN(curr, val, limit) \
+ (((curr) >= (limit)) || (size_t)((limit) - (curr)) < (size_t)(val))
+
SSL3_ENC_METHOD TLSv1_enc_data = {
tls1_enc,
tls1_mac,
@@ -1263,8 +1266,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
if (s->tlsext_hostname != NULL) {
/* Add TLS extension servername to the Client Hello message */
- unsigned long size_str;
- long lenmax;
+ size_t size_str;
/*-
* check for enough space.
@@ -1274,10 +1276,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
* 2 for hostname length
* + hostname length
*/
-
- if ((lenmax = limit - ret - 9) < 0
- || (size_str =
- strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
+ size_str = strlen(s->tlsext_hostname);
+ if (CHECKLEN(ret, 9 + size_str, limit))
return NULL;
/* extension type and length */
@@ -1321,7 +1321,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
if (s->srp_ctx.login != NULL) { /* Add TLS extension SRP username to the
* Client Hello message */
- int login_len = strlen(s->srp_ctx.login);
+ size_t login_len = strlen(s->srp_ctx.login);
if (login_len > 255 || login_len == 0) {
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
@@ -1333,7 +1333,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
* 1 for the srp user identity
* + srp user identity length
*/
- if ((limit - ret - 5 - login_len) < 0)
+ if (CHECKLEN(ret, 5 + login_len, limit))
return NULL;
/* fill in the extension */
@@ -1350,20 +1350,23 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
/*
* Add TLS extension ECPointFormats to the ClientHello message
*/
- long lenmax;
const unsigned char *pcurves, *pformats;
size_t num_curves, num_formats, curves_list_len;
tls1_get_formatlist(s, &pformats, &num_formats);
- if ((lenmax = limit - ret - 5) < 0)
- return NULL;
- if (num_formats > (size_t)lenmax)
- return NULL;
if (num_formats > 255) {
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
+ /*-
+ * check for enough space.
+ * 4 bytes for the ec point formats type and extension length
+ * 1 byte for the length of the formats
+ * + formats length
+ */
+ if (CHECKLEN(ret, 5 + num_formats, limit))
+ return NULL;
s2n(TLSEXT_TYPE_ec_point_formats, ret);
/* The point format list has 1-byte length. */
@@ -1379,15 +1382,20 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves))
return NULL;
- if ((lenmax = limit - ret - 6) < 0)
- return NULL;
- if (num_curves > (size_t)lenmax / 2)
- return NULL;
if (num_curves > 65532 / 2) {
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
curves_list_len = 2 * num_curves;
+ /*-
+ * check for enough space.
+ * 4 bytes for the ec curves type and extension length
+ * 2 bytes for the curve list length
+ * + curve list length
+ */
+ if (CHECKLEN(ret, 6 + curves_list_len, limit))
+ return NULL;
+
s2n(TLSEXT_TYPE_elliptic_curves, ret);
s2n(curves_list_len + 2, ret);
s2n(curves_list_len, ret);
@@ -1397,7 +1405,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
# endif /* OPENSSL_NO_EC */
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
- int ticklen;
+ size_t ticklen;
if (!s->new_session && s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
else if (s->session && s->tlsext_session_ticket &&
@@ -1418,11 +1426,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
* Check for enough room 2 for extension type, 2 for len rest for
* ticket
*/
- if ((long)(limit - ret - 4 - ticklen) < 0)
+ if (CHECKLEN(ret, 4 + ticklen, limit))
return NULL;
s2n(TLSEXT_TYPE_session_ticket, ret);
s2n(ticklen, ret);
- if (ticklen) {
+ if (ticklen > 0) {
memcpy(ret, s->session->tlsext_tick, ticklen);
ret += ticklen;
}
@@ -1433,7 +1441,14 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
size_t salglen;
const unsigned char *salg;
salglen = tls12_get_psigalgs(s, &salg);
- if ((size_t)(limit - ret) < salglen + 6)
+
+ /*-
+ * check for enough space.
+ * 4 bytes for the sigalgs type and extension length
+ * 2 bytes for the sigalg list length
+ * + sigalg list length
+ */
+ if (CHECKLEN(ret, salglen + 6, limit))
return NULL;
s2n(TLSEXT_TYPE_signature_algorithms, ret);
s2n(salglen + 2, ret);
@@ -1460,30 +1475,42 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
int i;
- long extlen, idlen, itmp;
+ size_t extlen, idlen;
+ int lentmp;
OCSP_RESPID *id;
idlen = 0;
for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
- itmp = i2d_OCSP_RESPID(id, NULL);
- if (itmp <= 0)
+ lentmp = i2d_OCSP_RESPID(id, NULL);
+ if (lentmp <= 0)
return NULL;
- idlen += itmp + 2;
+ idlen += (size_t)lentmp + 2;
}
if (s->tlsext_ocsp_exts) {
- extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
- if (extlen < 0)
+ lentmp = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+ if (lentmp < 0)
return NULL;
+ extlen = (size_t)lentmp;
} else
extlen = 0;
- if ((long)(limit - ret - 7 - extlen - idlen) < 0)
- return NULL;
- s2n(TLSEXT_TYPE_status_request, ret);
if (extlen + idlen > 0xFFF0)
return NULL;
+ /*
+ * 2 bytes for status request type
+ * 2 bytes for status request len
+ * 1 byte for OCSP request type
+ * 2 bytes for length of ids
+ * 2 bytes for length of extensions
+ * + length of ids
+ * + length of extensions
+ */
+ if (CHECKLEN(ret, 9 + idlen + extlen, limit))
+ return NULL;
+
+ s2n(TLSEXT_TYPE_status_request, ret);
s2n(extlen + idlen + 5, ret);
*(ret++) = TLSEXT_STATUSTYPE_ocsp;
s2n(idlen, ret);
@@ -1493,9 +1520,9 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
/* skip over id len */
ret += 2;
- itmp = i2d_OCSP_RESPID(id, &ret);
+ lentmp = i2d_OCSP_RESPID(id, &ret);
/* write id len */
- s2n(itmp, q);
+ s2n(lentmp, q);
}
s2n(extlen, ret);
if (extlen > 0)
@@ -1503,8 +1530,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
}
# ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension */
- if ((limit - ret - 4 - 1) < 0)
+
+ /*-
+ * check for enough space.
+ * 4 bytes for the heartbeat ext type and extension length
+ * 1 byte for the mode
+ */
+ if (CHECKLEN(ret, 5, limit))
return NULL;
+
s2n(TLSEXT_TYPE_heartbeat, ret);
s2n(1, ret);
/*-
@@ -1524,7 +1558,12 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
* The client advertises an emtpy extension to indicate its support
* for Next Protocol Negotiation
*/
- if (limit - ret - 4 < 0)
+
+ /*-
+ * check for enough space.
+ * 4 bytes for the NPN ext type and extension length
+ */
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_next_proto_neg, ret);
s2n(0, ret);
@@ -1532,7 +1571,13 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
# endif
if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) {
- if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
+ /*-
+ * check for enough space.
+ * 4 bytes for the ALPN type and extension length
+ * 2 bytes for the ALPN protocol list length
+ * + ALPN protocol list length
+ */
+ if (CHECKLEN(ret, 6 + s->alpn_client_proto_list_len, limit))
return NULL;
s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
s2n(2 + s->alpn_client_proto_list_len, ret);
@@ -1547,7 +1592,12 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
- if ((limit - ret - 4 - el) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the SRTP type and extension length
+ * + SRTP profiles length
+ */
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_use_srtp, ret);
@@ -1587,6 +1637,17 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
else
hlen = 0;
+ /*-
+ * check for enough space. Strictly speaking we know we've already
+ * got enough space because to get here the message size is < 0x200,
+ * but we know that we've allocated far more than that in the buffer
+ * - but for consistency and robustness we're going to check anyway.
+ *
+ * 4 bytes for the padding type and extension length
+ * + padding length
+ */
+ if (CHECKLEN(ret, 4 + hlen, limit))
+ return NULL;
s2n(TLSEXT_TYPE_padding, ret);
s2n(hlen, ret);
memset(ret, 0, hlen);
@@ -1644,7 +1705,12 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
return NULL;
}
- if ((limit - ret - 4 - el) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the reneg type and extension length
+ * + reneg data length
+ */
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_renegotiate, ret);
@@ -1664,19 +1730,23 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
/*
* Add TLS extension ECPointFormats to the ServerHello message
*/
- long lenmax;
tls1_get_formatlist(s, &plist, &plistlen);
- if ((lenmax = limit - ret - 5) < 0)
- return NULL;
- if (plistlen > (size_t)lenmax)
- return NULL;
if (plistlen > 255) {
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
+ /*-
+ * check for enough space.
+ * 4 bytes for the ec points format type and extension length
+ * 1 byte for the points format list length
+ * + length of points format list
+ */
+ if (CHECKLEN(ret, 5 + plistlen, limit))
+ return NULL;
+
s2n(TLSEXT_TYPE_ec_point_formats, ret);
s2n(plistlen + 1, ret);
*(ret++) = (unsigned char)plistlen;
@@ -1691,14 +1761,22 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
# endif /* OPENSSL_NO_EC */
if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
- if ((long)(limit - ret - 4) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the Ticket type and extension length
+ */
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_session_ticket, ret);
s2n(0, ret);
}
if (s->tlsext_status_expected) {
- if ((long)(limit - ret - 4) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the Status request type and extension length
+ */
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_status_request, ret);
s2n(0, ret);
@@ -1726,7 +1804,12 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
- if ((limit - ret - 4 - el) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the SRTP profiles type and extension length
+ * + length of the SRTP profiles list
+ */
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_use_srtp, ret);
@@ -1751,16 +1834,23 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
};
- if (limit - ret < 36)
+
+ /* check for enough space. */
+ if (CHECKLEN(ret, sizeof(cryptopro_ext), limit))
return NULL;
- memcpy(ret, cryptopro_ext, 36);
- ret += 36;
+ memcpy(ret, cryptopro_ext, sizeof(cryptopro_ext));
+ ret += sizeof(cryptopro_ext);
}
# ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension if we've received one */
if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) {
- if ((limit - ret - 4 - 1) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the Heartbeat type and extension length
+ * 1 byte for the mode
+ */
+ if (CHECKLEN(ret, 5, limit))
return NULL;
s2n(TLSEXT_TYPE_heartbeat, ret);
s2n(1, ret);
@@ -1789,7 +1879,12 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
s->
ctx->next_protos_advertised_cb_arg);
if (r == SSL_TLSEXT_ERR_OK) {
- if ((long)(limit - ret - 4 - npalen) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the NPN type and extension length
+ * + length of protocols list
+ */
+ if (CHECKLEN(ret, 4 + npalen, limit))
return NULL;
s2n(TLSEXT_TYPE_next_proto_neg, ret);
s2n(npalen, ret);
@@ -1804,9 +1899,16 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
if (s->s3->alpn_selected) {
const unsigned char *selected = s->s3->alpn_selected;
- unsigned len = s->s3->alpn_selected_len;
+ size_t len = s->s3->alpn_selected_len;
- if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
+ /*-
+ * check for enough space.
+ * 4 bytes for the ALPN type and extension length
+ * 2 bytes for ALPN data length
+ * 1 byte for selected protocol length
+ * + length of the selected protocol
+ */
+ if (CHECKLEN(ret, 7 + len, limit))
return NULL;
s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
s2n(3 + len, ret);
@@ -1966,11 +2068,10 @@ static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
/*
* Process the ALPN extension in a ClientHello.
- * ret: a pointer to the TLSEXT return value: SSL_TLSEXT_ERR_*
* al: a pointer to the alert value to send in the event of a failure.
- * returns 1 on success, 0 on failure: al/ret set only on failure
+ * returns 1 on success, 0 on failure: al set only on failure
*/
-static int tls1_alpn_handle_client_hello_late(SSL *s, int *ret, int *al)
+static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
{
const unsigned char *selected = NULL;
unsigned char selected_len = 0;
@@ -1986,7 +2087,6 @@ static int tls1_alpn_handle_client_hello_late(SSL *s, int *ret, int *al)
s->s3->alpn_selected = OPENSSL_malloc(selected_len);
if (s->s3->alpn_selected == NULL) {
*al = SSL_AD_INTERNAL_ERROR;
- *ret = SSL_TLSEXT_ERR_ALERT_FATAL;
return 0;
}
memcpy(s->s3->alpn_selected, selected, selected_len);
@@ -3064,10 +3164,12 @@ int tls1_set_server_sigalgs(SSL *s)
return 0;
}
-int ssl_check_clienthello_tlsext_late(SSL *s)
+/*
+ * Upon success, returns 1.
+ * Upon failure, returns 0 and sets |al| to the appropriate fatal alert.
+ */
+int ssl_check_clienthello_tlsext_late(SSL *s, int *al)
{
- int ret = SSL_TLSEXT_ERR_OK;
- int al;
/*
* If status request then ask callback what to do. Note: this must be
@@ -3076,58 +3178,41 @@ int ssl_check_clienthello_tlsext_late(SSL *s)
* influence which certificate is sent
*/
if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) {
- int r;
+ int ret;
CERT_PKEY *certpkey;
certpkey = ssl_get_server_send_pkey(s);
/* If no certificate can't return certificate status */
- if (certpkey == NULL) {
- s->tlsext_status_expected = 0;
- return 1;
- }
- /*
- * Set current certificate to one we will use so SSL_get_certificate
- * et al can pick it up.
- */
- s->cert->key = certpkey;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (r) {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- else
+ if (certpkey != NULL) {
+ /*
+ * Set current certificate to one we will use so SSL_get_certificate
+ * et al can pick it up.
+ */
+ s->cert->key = certpkey;
+ ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (ret) {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
s->tlsext_status_expected = 0;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ default:
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
}
- } else
- s->tlsext_status_expected = 0;
-
- if (!tls1_alpn_handle_client_hello_late(s, &ret, &al)) {
- goto err;
}
- err:
- switch (ret) {
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return -1;
-
- case SSL_TLSEXT_ERR_ALERT_WARNING:
- ssl3_send_alert(s, SSL3_AL_WARNING, al);
- return 1;
-
- default:
- return 1;
+ if (!tls1_alpn_handle_client_hello_late(s, al)) {
+ return 0;
}
+
+ return 1;
}
int ssl_check_serverhello_tlsext(SSL *s)