#include <openssl/hmac.h>
#include <openssl/ocsp.h>
#include <openssl/rand.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-# include <openssl/bn.h>
-#endif
+#include <openssl/dh.h>
+#include <openssl/bn.h>
#include "ssl_locl.h"
+#include <openssl/ct.h>
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
}
/*
- * Get a mask of disabled algorithms: an algorithm is disabled if it isn't
- * supported or doesn't appear in supported signature algorithms. Unlike
- * ssl_cipher_get_disabled this applies to a specific session and not global
- * settings.
+ * Set a mask of disabled algorithms: an algorithm is disabled if it isn't
+ * supported, doesn't appear in supported signature algorithms, isn't supported
+ * by the enabled protocol versions or by the security level.
+ *
+ * This function should only be used for checking which ciphers are supported
+ * by the client.
+ *
+ * Call ssl_cipher_disabled() to check that it's enabled or not.
*/
void ssl_set_client_disabled(SSL *s)
{
s->s3->tmp.mask_a = 0;
s->s3->tmp.mask_k = 0;
- /* Don't allow TLS 1.2 only ciphers if we don't suppport them */
- if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
- s->s3->tmp.mask_ssl = SSL_TLSV1_2;
- else
- s->s3->tmp.mask_ssl = 0;
- /* Disable TLS 1.0 ciphers if using SSL v3 */
- if (s->client_version == SSL3_VERSION)
- s->s3->tmp.mask_ssl |= SSL_TLSV1;
ssl_set_sig_mask(&s->s3->tmp.mask_a, s, SSL_SECOP_SIGALG_MASK);
+ ssl_get_client_min_max_version(s, &s->s3->tmp.min_ver, &s->s3->tmp.max_ver);
# ifndef OPENSSL_NO_PSK
/* with PSK there must be client callback set */
if (!s->psk_client_callback) {
#endif
}
+/*
+ * ssl_cipher_disabled - check that a cipher is disabled or not
+ * @s: SSL connection that you want to use the cipher on
+ * @c: cipher to check
+ * @op: Security check that you want to do
+ *
+ * Returns 1 when it's disabled, 0 when enabled.
+ */
int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op)
{
- if (c->algorithm_ssl & s->s3->tmp.mask_ssl
- || c->algorithm_mkey & s->s3->tmp.mask_k
+ if (c->algorithm_mkey & s->s3->tmp.mask_k
|| c->algorithm_auth & s->s3->tmp.mask_a)
return 1;
+ if (s->s3->tmp.max_ver == 0)
+ return 1;
+ if (!SSL_IS_DTLS(s) && ((c->min_tls > s->s3->tmp.max_ver)
+ || (c->max_tls < s->s3->tmp.min_ver)))
+ return 1;
+ if (SSL_IS_DTLS(s) && (DTLS_VERSION_GT(c->min_dtls, s->s3->tmp.max_ver)
+ || DTLS_VERSION_LT(c->max_dtls, s->s3->tmp.min_ver)))
+ return 1;
+
return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
}
ret += salglen;
}
+#ifndef OPENSSL_NO_OCSP
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
int i;
long extlen, idlen, itmp;
if (extlen > 0)
i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
}
+#endif
#ifndef OPENSSL_NO_HEARTBEATS
if (SSL_IS_DTLS(s)) {
/* Add Heartbeat extension */
}
#endif
+ /*
+ * finish_md_len is non-zero during a renegotiation, so
+ * this avoids sending ALPN during the renegotiation
+ * (see longer comment below)
+ */
if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) {
if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
return NULL;
s2n(s->alpn_client_proto_list_len, ret);
memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len);
ret += s->alpn_client_proto_list_len;
+ s->s3->alpn_sent = 1;
}
#ifndef OPENSSL_NO_SRTP
if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) {
#ifdef TLSEXT_TYPE_encrypt_then_mac
s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
s2n(0, ret);
+#endif
+#ifndef OPENSSL_NO_CT
+ if (s->ct_validation_callback != NULL) {
+ s2n(TLSEXT_TYPE_signed_certificate_timestamp, ret);
+ s2n(0, ret);
+ }
#endif
s2n(TLSEXT_TYPE_extended_master_secret, ret);
s2n(0, ret);
s2n(0, ret);
}
- if (s->s3->alpn_selected) {
+ if (s->s3->alpn_selected != NULL) {
const unsigned char *selected = s->s3->alpn_selected;
- unsigned len = s->s3->alpn_selected_len;
+ unsigned int len = s->s3->alpn_selected_len;
if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
return NULL;
}
/*
- * Process the ALPN extension in a ClientHello.
+ * Save the ALPN extension in a ClientHello.
* pkt: the contents of the ALPN extension, not including type and length.
* al: a pointer to the alert value to send in the event of a failure.
* returns: 1 on success, 0 on error.
*/
static int tls1_alpn_handle_client_hello(SSL *s, PACKET *pkt, int *al)
{
- const unsigned char *selected;
- unsigned char selected_len;
- int r;
PACKET protocol_list, save_protocol_list, protocol;
*al = SSL_AD_DECODE_ERROR;
}
} while (PACKET_remaining(&protocol_list) != 0);
- if (s->ctx->alpn_select_cb == NULL)
- return 1;
+ if (!PACKET_memdup(&save_protocol_list,
+ &s->s3->alpn_proposed,
+ &s->s3->alpn_proposed_len)) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * 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
+ */
+static int tls1_alpn_handle_client_hello_late(SSL *s, int *ret, int *al)
+{
+ const unsigned char *selected = NULL;
+ unsigned char selected_len = 0;
+
+ if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+ int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
+ s->s3->alpn_proposed,
+ s->s3->alpn_proposed_len,
+ s->ctx->alpn_select_cb_arg);
- r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
- PACKET_data(&save_protocol_list),
- PACKET_remaining(&save_protocol_list),
- s->ctx->alpn_select_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = OPENSSL_malloc(selected_len);
- if (s->s3->alpn_selected == NULL) {
- *al = SSL_AD_INTERNAL_ERROR;
+ if (r == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+ if (s->s3->alpn_selected == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ *ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ return 0;
+ }
+ s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* ALPN takes precedence over NPN. */
+ s->s3->next_proto_neg_seen = 0;
+#endif
+ } else {
+ *al = SSL_AD_NO_APPLICATION_PROTOCOL;
+ *ret = SSL_TLSEXT_ERR_ALERT_FATAL;
return 0;
}
- memcpy(s->s3->alpn_selected, selected, selected_len);
- s->s3->alpn_selected_len = selected_len;
- } else {
- *al = SSL_AD_NO_APPLICATION_PROTOCOL;
- return 0;
}
return 1;
OPENSSL_free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
+ s->s3->alpn_selected_len = 0;
+ OPENSSL_free(s->s3->alpn_proposed);
+ s->s3->alpn_proposed = NULL;
+ s->s3->alpn_proposed_len = 0;
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_DTLSEXT_HB_ENABLED |
SSL_DTLSEXT_HB_DONT_SEND_REQUESTS);
}
}
} else if (type == TLSEXT_TYPE_status_request) {
- const unsigned char *ext_data;
-
if (!PACKET_get_1(&extension,
(unsigned int *)&s->tlsext_status_type)) {
return 0;
}
+#ifndef OPENSSL_NO_OCSP
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
+ const unsigned char *ext_data;
PACKET responder_id_list, exts;
if (!PACKET_get_length_prefixed_2(&extension, &responder_id_list))
return 0;
return 0;
}
}
- /*
- * We don't know what to do with any other type * so ignore it.
- */
- } else {
+ } else
+#endif
+ {
+ /*
+ * We don't know what to do with any other type so ignore it.
+ */
s->tlsext_status_type = -1;
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
- s->s3->tmp.finish_md_len == 0 &&
- s->s3->alpn_selected == NULL) {
+ s->s3->tmp.finish_md_len == 0) {
/*-
* We shouldn't accept this extension on a
* renegotiation.
s->s3->tmp.finish_md_len == 0) {
if (!tls1_alpn_handle_client_hello(s, &extension, al))
return 0;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* ALPN takes precedence over NPN. */
- s->s3->next_proto_neg_seen = 0;
-#endif
}
/* session ticket processed earlier */
/* Set flag to expect CertificateStatus message */
s->tlsext_status_expected = 1;
}
+#ifndef OPENSSL_NO_CT
+ /*
+ * Only take it if we asked for it - i.e if there is no CT validation
+ * callback set, then a custom extension MAY be processing it, so we
+ * need to let control continue to flow to that.
+ */
+ else if (type == TLSEXT_TYPE_signed_certificate_timestamp &&
+ s->ct_validation_callback != NULL) {
+ /* Simply copy it off for later processing */
+ if (s->tlsext_scts != NULL) {
+ OPENSSL_free(s->tlsext_scts);
+ s->tlsext_scts = NULL;
+ }
+ s->tlsext_scts_len = size;
+ if (size > 0) {
+ s->tlsext_scts = OPENSSL_malloc(size);
+ if (s->tlsext_scts == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->tlsext_scts, data, size);
+ }
+ }
+#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
s->s3->tmp.finish_md_len == 0) {
else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) {
unsigned len;
/* We must have requested it. */
- if (s->alpn_client_proto_list == NULL) {
+ if (!s->s3->alpn_sent) {
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
}
int ssl_prepare_clienthello_tlsext(SSL *s)
{
-
+ s->s3->alpn_sent = 0;
return 1;
}
} 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:
if (sdec == NULL
|| EVP_DecryptUpdate(ctx, sdec, &slen, p, eticklen) <= 0) {
EVP_CIPHER_CTX_free(ctx);
+ OPENSSL_free(sdec);
return -1;
}
if (EVP_DecryptFinal(ctx, sdec + slen, &mlen) <= 0) {
if (dh_secbits >= 128) {
DH *dhp = DH_new();
+ BIGNUM *p, *g;
if (dhp == NULL)
return NULL;
- dhp->g = BN_new();
- if (dhp->g != NULL)
- BN_set_word(dhp->g, 2);
+ g = BN_new();
+ if (g != NULL)
+ BN_set_word(g, 2);
if (dh_secbits >= 192)
- dhp->p = get_rfc3526_prime_8192(NULL);
+ p = get_rfc3526_prime_8192(NULL);
else
- dhp->p = get_rfc3526_prime_3072(NULL);
- if (dhp->p == NULL || dhp->g == NULL) {
+ p = get_rfc3526_prime_3072(NULL);
+ if (p == NULL || g == NULL || !DH_set0_pqg(dhp, p, NULL, g)) {
DH_free(dhp);
+ BN_free(p);
+ BN_free(g);
return NULL;
}
return dhp;