* [including the GNU Public Licence.]
*/
/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
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,
} else
# endif
{
- if (!s->server || s->cert->ecdh_tmp_auto) {
+ if (!s->server
+# ifndef OPENSSL_NO_ECDH
+ || s->cert->ecdh_tmp_auto
+# endif
+ ) {
*pcurves = eccurves_auto;
pcurveslen = sizeof(eccurves_auto);
} else {
tlsext_sigalg_ecdsa(TLSEXT_hash_sha384)
};
# endif
-size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
+size_t tls12_get_psigalgs(SSL *s, int sent, const unsigned char **psigs)
{
/*
* If Suite B mode use Suite B sigalgs only, ignore any other
}
# endif
/* If server use client authentication sigalgs if not NULL */
- if (s->server && s->cert->client_sigalgs) {
+ if (s->server == sent && s->cert->client_sigalgs) {
*psigs = s->cert->client_sigalgs;
return s->cert->client_sigalgslen;
} else if (s->cert->conf_sigalgs) {
# endif
/* Check signature matches a type we sent */
- sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
+ sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
for (i = 0; i < sent_sigslen; i += 2, sent_sigs += 2) {
if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1])
break;
* Now go through all signature algorithms seeing if we support any for
* RSA, DSA, ECDSA. Do this for all versions not just TLS 1.2.
*/
- sigalgslen = tls12_get_psigalgs(s, &sigalgs);
+ sigalgslen = tls12_get_psigalgs(s, 1, &sigalgs);
for (i = 0; i < sigalgslen; i += 2, sigalgs += 2) {
switch (sigalgs[1]) {
# ifndef OPENSSL_NO_RSA
* + hostname length
*/
size_str = strlen(s->tlsext_hostname);
- if (ret >= limit || (size_t)(limit - ret) < 9 + size_str)
+ if (CHECKLEN(ret, 9 + size_str, limit))
return NULL;
/* extension type and length */
* 1 for the srp user identity
* + srp user identity length
*/
- if (ret >= limit || (size_t)(limit - ret) < 5 + login_len)
+ if (CHECKLEN(ret, 5 + login_len, limit))
return NULL;
/* fill in the extension */
* 1 byte for the length of the formats
* + formats length
*/
- if (ret >= limit || (size_t)(limit - ret) < 5 + num_formats)
+ if (CHECKLEN(ret, 5 + num_formats, limit))
return NULL;
s2n(TLSEXT_TYPE_ec_point_formats, ret);
* 2 bytes for the curve list length
* + curve list length
*/
- if (ret >= limit || (size_t)(limit - ret) < 6 + curves_list_len)
+ if (CHECKLEN(ret, 6 + curves_list_len, limit))
return NULL;
s2n(TLSEXT_TYPE_elliptic_curves, ret);
* Check for enough room 2 for extension type, 2 for len rest for
* ticket
*/
- if (ret >= limit || (size_t)(limit - ret) < 4 + ticklen)
+ if (CHECKLEN(ret, 4 + ticklen, limit))
return NULL;
s2n(TLSEXT_TYPE_session_ticket, ret);
s2n(ticklen, ret);
if (SSL_CLIENT_USE_SIGALGS(s)) {
size_t salglen;
const unsigned char *salg;
- salglen = tls12_get_psigalgs(s, &salg);
+ salglen = tls12_get_psigalgs(s, 1, &salg);
/*-
* check for enough space.
* 2 bytes for the sigalg list length
* + sigalg list length
*/
- if (ret >= limit || (size_t)(limit - ret) < salglen + 6)
+ if (CHECKLEN(ret, salglen + 6, limit))
return NULL;
s2n(TLSEXT_TYPE_signature_algorithms, ret);
s2n(salglen + 2, ret);
* 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 (ret >= limit || (size_t)(limit - ret) < 9 + idlen + extlen)
+ if (CHECKLEN(ret, 9 + idlen + extlen, limit))
return NULL;
s2n(TLSEXT_TYPE_status_request, ret);
* 4 bytes for the heartbeat ext type and extension length
* 1 byte for the mode
*/
- if (ret >= limit || limit - ret < 5)
+ if (CHECKLEN(ret, 5, limit))
return NULL;
s2n(TLSEXT_TYPE_heartbeat, ret);
* check for enough space.
* 4 bytes for the NPN ext type and extension length
*/
- if (ret >= limit || limit - ret < 4)
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_next_proto_neg, ret);
s2n(0, ret);
* 2 bytes for the ALPN protocol list length
* + ALPN protocol list length
*/
- if (ret >= limit || limit - ret < 6 + s->alpn_client_proto_list_len)
+ 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);
* 4 bytes for the SRTP type and extension length
* + SRTP profiles length
*/
- if (ret >= limit || limit - ret < 4 + el)
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_use_srtp, ret);
* 4 bytes for the padding type and extension length
* + padding length
*/
- if (ret >= limit || limit - ret < 4 + hlen)
+ if (CHECKLEN(ret, 4 + hlen, limit))
return NULL;
s2n(TLSEXT_TYPE_padding, ret);
s2n(hlen, ret);
* 4 bytes for the reneg type and extension length
* + reneg data length
*/
- if (ret >= limit || limit - ret < 4 + el)
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_renegotiate, ret);
* 1 byte for the points format list length
* + length of points format list
*/
- if (ret >= limit || (size_t)(limit - ret) < 5 + plistlen)
+ if (CHECKLEN(ret, 5 + plistlen, limit))
return NULL;
s2n(TLSEXT_TYPE_ec_point_formats, ret);
* check for enough space.
* 4 bytes for the Ticket type and extension length
*/
- if (ret >= limit || limit - ret < 4)
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_session_ticket, ret);
s2n(0, ret);
+ } else {
+ /* if we don't add the above TLSEXT, we can't add a session ticket later */
+ s->tlsext_ticket_expected = 0;
}
if (s->tlsext_status_expected) {
* check for enough space.
* 4 bytes for the Status request type and extension length
*/
- if (ret >= limit || limit - ret < 4)
+ if (CHECKLEN(ret, 4, limit))
return NULL;
s2n(TLSEXT_TYPE_status_request, ret);
s2n(0, ret);
* 4 bytes for the SRTP profiles type and extension length
* + length of the SRTP profiles list
*/
- if (ret >= limit || limit - ret < 4 + el)
+ if (CHECKLEN(ret, 4 + el, limit))
return NULL;
s2n(TLSEXT_TYPE_use_srtp, ret);
};
/* check for enough space. */
- if (ret >= limit || (size_t)(limit - ret) < sizeof(cryptopro_ext))
+ if (CHECKLEN(ret, sizeof(cryptopro_ext), limit))
return NULL;
memcpy(ret, cryptopro_ext, sizeof(cryptopro_ext));
ret += sizeof(cryptopro_ext);
* 4 bytes for the Heartbeat type and extension length
* 1 byte for the mode
*/
- if (ret >= limit || limit - ret < 5)
+ if (CHECKLEN(ret, 5, limit))
return NULL;
s2n(TLSEXT_TYPE_heartbeat, ret);
s2n(1, ret);
* 4 bytes for the NPN type and extension length
* + length of protocols list
*/
- if (ret >= limit || limit - ret < 4 + npalen)
+ if (CHECKLEN(ret, 4 + npalen, limit))
return NULL;
s2n(TLSEXT_TYPE_next_proto_neg, ret);
s2n(npalen, ret);
* 1 byte for selected protocol length
* + length of the selected protocol
*/
- if (ret >= limit || (size_t)(limit - ret) < 7 + len)
+ if (CHECKLEN(ret, 7 + len, limit))
return NULL;
s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
s2n(3 + len, ret);
s2n(1 + len, ret);
- *ret++ = len;
+ *ret++ = (unsigned char)len;
memcpy(ret, selected, len);
ret += len;
}
/*
* 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;
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);
# ifndef OPENSSL_NO_EC
else if (type == TLSEXT_TYPE_ec_point_formats) {
unsigned char *sdata = data;
- int ecpointformatlist_length = *(sdata++);
+ int ecpointformatlist_length;
+ if (size == 0)
+ goto err;
+
+ ecpointformatlist_length = *(sdata++);
if (ecpointformatlist_length != size - 1 ||
ecpointformatlist_length < 1)
goto err;
goto err;
if (!tls1_save_sigalgs(s, data, dsize))
goto err;
- } else if (type == TLSEXT_TYPE_status_request) {
-
+ } else if (type == TLSEXT_TYPE_status_request && !s->hit) {
if (size < 5)
goto err;
# ifndef OPENSSL_NO_EC
else if (type == TLSEXT_TYPE_ec_point_formats) {
unsigned char *sdata = data;
- int ecpointformatlist_length = *(sdata++);
+ int ecpointformatlist_length;
+
+ if (size == 0) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ ecpointformatlist_length = *(sdata++);
if (ecpointformatlist_length != size - 1) {
*al = TLS1_AD_DECODE_ERROR;
return 0;
if (!s->cert->shared_sigalgs) {
SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS,
SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
- al = SSL_AD_ILLEGAL_PARAMETER;
+ al = SSL_AD_HANDSHAKE_FAILURE;
goto err;
}
} else
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
* 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)
EVP_CIPHER_CTX ctx;
SSL_CTX *tctx = s->initial_ctx;
+ /* Need at least keyname + iv */
+ if (eticklen < 16 + EVP_MAX_IV_LENGTH)
+ return 2;
+
/* Initialize session ticket encryption and HMAC contexts */
HMAC_CTX_init(&hctx);
EVP_CIPHER_CTX_init(&ctx);
int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
&ctx, &hctx, 0);
if (rv < 0)
- return -1;
- if (rv == 0)
+ goto err;
+ if (rv == 0) {
+ HMAC_CTX_cleanup(&hctx);
+ EVP_CIPHER_CTX_cleanup(&ctx);
return 2;
+ }
if (rv == 2)
renew_ticket = 1;
} else {
p = sdec;
sess = d2i_SSL_SESSION(NULL, &p, slen);
+ slen -= p - sdec;
OPENSSL_free(sdec);
if (sess) {
+ /* Some additional consistency checks */
+ if (slen != 0 || sess->session_id_length != 0) {
+ SSL_SESSION_free(sess);
+ return 2;
+ }
/*
* The session ID, if non-empty, is used by some clients to detect
* that the ticket has been accepted. So we copy it to the session
conf = c->conf_sigalgs;
conflen = c->conf_sigalgslen;
} else
- conflen = tls12_get_psigalgs(s, &conf);
+ conflen = tls12_get_psigalgs(s, 0, &conf);
if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb) {
pref = conf;
preflen = conflen;