#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#ifdef OPENSSL_NO_EC2M
+#include <openssl/ec.h>
+#endif
#include <openssl/ocsp.h>
#include <openssl/rand.h>
#include "ssl_locl.h"
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
tls1_export_keying_material,
+ 0,
+ SSL3_HM_HEADER_LENGTH,
+ ssl3_set_handshake_header,
+ ssl3_handshake_write
+ };
+
+SSL3_ENC_METHOD TLSv1_1_enc_data={
+ tls1_enc,
+ tls1_mac,
+ tls1_setup_key_block,
+ tls1_generate_master_secret,
+ tls1_change_cipher_state,
+ tls1_final_finish_mac,
+ TLS1_FINISH_MAC_LENGTH,
+ tls1_cert_verify_mac,
+ TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+ TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+ tls1_alert_code,
+ tls1_export_keying_material,
+ SSL_ENC_FLAG_EXPLICIT_IV,
+ SSL3_HM_HEADER_LENGTH,
+ ssl3_set_handshake_header,
+ ssl3_handshake_write
+ };
+
+SSL3_ENC_METHOD TLSv1_2_enc_data={
+ tls1_enc,
+ tls1_mac,
+ tls1_setup_key_block,
+ tls1_generate_master_secret,
+ tls1_change_cipher_state,
+ tls1_final_finish_mac,
+ TLS1_FINISH_MAC_LENGTH,
+ tls1_cert_verify_mac,
+ TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+ TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+ tls1_alert_code,
+ tls1_export_keying_material,
+ SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF
+ |SSL_ENC_FLAG_TLS1_2_CIPHERS,
+ SSL3_HM_HEADER_LENGTH,
+ ssl3_set_handshake_header,
+ ssl3_handshake_write
};
long tls1_default_timeout(void)
NID_secp256k1, /* secp256k1 (22) */
NID_X9_62_prime256v1, /* secp256r1 (23) */
NID_secp384r1, /* secp384r1 (24) */
- NID_secp521r1 /* secp521r1 (25) */
+ NID_secp521r1, /* secp521r1 (25) */
+ NID_brainpoolP256r1, /* brainpoolP256r1 (26) */
+ NID_brainpoolP384r1, /* brainpoolP384r1 (27) */
+ NID_brainpoolP512r1 /* brainpool512r1 (28) */
};
static const unsigned char eccurves_default[] =
{
+#ifndef OPENSSL_NO_EC2M
0,14, /* sect571r1 (14) */
0,13, /* sect571k1 (13) */
+#endif
0,25, /* secp521r1 (25) */
+ 0,28, /* brainpool512r1 (28) */
+#ifndef OPENSSL_NO_EC2M
0,11, /* sect409k1 (11) */
0,12, /* sect409r1 (12) */
+#endif
+ 0,27, /* brainpoolP384r1 (27) */
0,24, /* secp384r1 (24) */
+#ifndef OPENSSL_NO_EC2M
0,9, /* sect283k1 (9) */
0,10, /* sect283r1 (10) */
+#endif
+ 0,26, /* brainpoolP256r1 (26) */
0,22, /* secp256k1 (22) */
0,23, /* secp256r1 (23) */
+#ifndef OPENSSL_NO_EC2M
0,8, /* sect239k1 (8) */
0,6, /* sect233k1 (6) */
0,7, /* sect233r1 (7) */
+#endif
0,20, /* secp224k1 (20) */
0,21, /* secp224r1 (21) */
+#ifndef OPENSSL_NO_EC2M
0,4, /* sect193r1 (4) */
0,5, /* sect193r2 (5) */
+#endif
0,18, /* secp192k1 (18) */
0,19, /* secp192r1 (19) */
+#ifndef OPENSSL_NO_EC2M
0,1, /* sect163k1 (1) */
0,2, /* sect163r1 (2) */
0,3, /* sect163r2 (3) */
+#endif
0,15, /* secp160k1 (15) */
0,16, /* secp160r1 (16) */
0,17, /* secp160r2 (17) */
0, TLSEXT_curve_P_384
};
+#ifdef OPENSSL_FIPS
+/* Brainpool not allowed in FIPS mode */
+static const unsigned char fips_curves_default[] =
+ {
+#ifndef OPENSSL_NO_EC2M
+ 0,14, /* sect571r1 (14) */
+ 0,13, /* sect571k1 (13) */
+#endif
+ 0,25, /* secp521r1 (25) */
+#ifndef OPENSSL_NO_EC2M
+ 0,11, /* sect409k1 (11) */
+ 0,12, /* sect409r1 (12) */
+#endif
+ 0,24, /* secp384r1 (24) */
+#ifndef OPENSSL_NO_EC2M
+ 0,9, /* sect283k1 (9) */
+ 0,10, /* sect283r1 (10) */
+#endif
+ 0,22, /* secp256k1 (22) */
+ 0,23, /* secp256r1 (23) */
+#ifndef OPENSSL_NO_EC2M
+ 0,8, /* sect239k1 (8) */
+ 0,6, /* sect233k1 (6) */
+ 0,7, /* sect233r1 (7) */
+#endif
+ 0,20, /* secp224k1 (20) */
+ 0,21, /* secp224r1 (21) */
+#ifndef OPENSSL_NO_EC2M
+ 0,4, /* sect193r1 (4) */
+ 0,5, /* sect193r2 (5) */
+#endif
+ 0,18, /* secp192k1 (18) */
+ 0,19, /* secp192r1 (19) */
+#ifndef OPENSSL_NO_EC2M
+ 0,1, /* sect163k1 (1) */
+ 0,2, /* sect163r1 (2) */
+ 0,3, /* sect163r2 (3) */
+#endif
+ 0,15, /* secp160k1 (15) */
+ 0,16, /* secp160r1 (16) */
+ 0,17, /* secp160r2 (17) */
+ };
+#endif
+
int tls1_ec_curve_id2nid(int curve_id)
{
- /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ /* ECC curves from RFC 4492 and RFC 7027 */
if ((curve_id < 1) || ((unsigned int)curve_id >
sizeof(nid_list)/sizeof(nid_list[0])))
return 0;
int tls1_ec_nid2curve_id(int nid)
{
- /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+ /* ECC curves from RFC 4492 and RFC 7027 */
switch (nid)
{
case NID_sect163k1: /* sect163k1 (1) */
return 24;
case NID_secp521r1: /* secp521r1 (25) */
return 25;
+ case NID_brainpoolP256r1: /* brainpoolP256r1 (26) */
+ return 26;
+ case NID_brainpoolP384r1: /* brainpoolP384r1 (27) */
+ return 27;
+ case NID_brainpoolP512r1: /* brainpool512r1 (28) */
+ return 28;
default:
return 0;
}
}
-/* Get curves list, if "sess" is set return client curves otherwise
- * preferred list
+/*
+ * Get curves list, if "sess" is set return client curves otherwise
+ * preferred list.
+ * Sets |num_curves| to the number of curves in the list, i.e.,
+ * the length of |pcurves| is 2 * num_curves.
+ * Returns 1 on success and 0 if the client curves list has invalid format.
+ * The latter indicates an internal error: we should not be accepting such
+ * lists in the first place.
+ * TODO(emilia): we should really be storing the curves list in explicitly
+ * parsed form instead. (However, this would affect binary compatibility
+ * so cannot happen in the 1.0.x series.)
*/
-static void tls1_get_curvelist(SSL *s, int sess,
+static int tls1_get_curvelist(SSL *s, int sess,
const unsigned char **pcurves,
- size_t *pcurveslen)
+ size_t *num_curves)
{
+ size_t pcurveslen = 0;
if (sess)
{
*pcurves = s->session->tlsext_ellipticcurvelist;
- *pcurveslen = s->session->tlsext_ellipticcurvelist_length;
- return;
+ pcurveslen = s->session->tlsext_ellipticcurvelist_length;
}
- /* For Suite B mode only include P-256, P-384 */
- switch (tls1_suiteb(s))
+ else
{
- case SSL_CERT_FLAG_SUITEB_128_LOS:
- *pcurves = suiteb_curves;
- *pcurveslen = sizeof(suiteb_curves);
- break;
+ /* For Suite B mode only include P-256, P-384 */
+ switch (tls1_suiteb(s))
+ {
+ case SSL_CERT_FLAG_SUITEB_128_LOS:
+ *pcurves = suiteb_curves;
+ pcurveslen = sizeof(suiteb_curves);
+ break;
- case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
- *pcurves = suiteb_curves;
- *pcurveslen = 2;
- break;
+ case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+ *pcurves = suiteb_curves;
+ pcurveslen = 2;
+ break;
- case SSL_CERT_FLAG_SUITEB_192_LOS:
- *pcurves = suiteb_curves + 2;
- *pcurveslen = 2;
- break;
- default:
- *pcurves = s->tlsext_ellipticcurvelist;
- *pcurveslen = s->tlsext_ellipticcurvelist_length;
+ case SSL_CERT_FLAG_SUITEB_192_LOS:
+ *pcurves = suiteb_curves + 2;
+ pcurveslen = 2;
+ break;
+ default:
+ *pcurves = s->tlsext_ellipticcurvelist;
+ pcurveslen = s->tlsext_ellipticcurvelist_length;
+ }
+ if (!*pcurves)
+ {
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ {
+ *pcurves = fips_curves_default;
+ *pcurveslen = sizeof(fips_curves_default);
+ }
+ else
+#endif
+ {
+ *pcurves = eccurves_default;
+ pcurveslen = sizeof(eccurves_default);
+ }
+ }
+ }
+ /* We do not allow odd length arrays to enter the system. */
+ if (pcurveslen & 1)
+ {
+ SSLerr(SSL_F_TLS1_GET_CURVELIST, ERR_R_INTERNAL_ERROR);
+ *num_curves = 0;
+ return 0;
}
- if (!*pcurves)
+ else
{
- *pcurves = eccurves_default;
- *pcurveslen = sizeof(eccurves_default);
+ *num_curves = pcurveslen / 2;
+ return 1;
}
}
/* Check a curve is one of our preferences */
int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
{
const unsigned char *curves;
- size_t curveslen, i;
+ size_t num_curves, i;
unsigned int suiteb_flags = tls1_suiteb(s);
if (len != 3 || p[0] != NAMED_CURVE_TYPE)
return 0;
else /* Should never happen */
return 0;
}
- tls1_get_curvelist(s, 0, &curves, &curveslen);
- for (i = 0; i < curveslen; i += 2, curves += 2)
+ if (!tls1_get_curvelist(s, 0, &curves, &num_curves))
+ return 0;
+ for (i = 0; i < num_curves; i++, curves += 2)
{
if (p[1] == curves[0] && p[2] == curves[1])
return 1;
return 0;
}
-/* Return nth shared curve. If nmatch == -1 return number of
- * matches. For nmatch == -2 return the NID of the curve to use for
- * an EC tmp key.
+/*
+ * Return |nmatch|th shared curve or NID_undef if there is no match.
+ * For nmatch == -1, return number of matches
+ * For nmatch == -2, return the NID of the curve to use for
+ * an EC tmp key, or NID_undef if there is no match.
*/
-
int tls1_shared_curve(SSL *s, int nmatch)
{
const unsigned char *pref, *supp;
- size_t preflen, supplen, i, j;
+ size_t num_pref, num_supp, i, j;
int k;
/* Can't do anything on client side */
if (s->server == 0)
/* If not Suite B just return first preference shared curve */
nmatch = 0;
}
- tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
- &supp, &supplen);
- tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
- &pref, &preflen);
- preflen /= 2;
- supplen /= 2;
+ /*
+ * Avoid truncation. tls1_get_curvelist takes an int
+ * but s->options is a long...
+ */
+ if (!tls1_get_curvelist(s, (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0,
+ &supp, &num_supp))
+ /* In practice, NID_undef == 0 but let's be precise. */
+ return nmatch == -1 ? 0 : NID_undef;
+ if(!tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+ &pref, &num_pref))
+ return nmatch == -1 ? 0 : NID_undef;
k = 0;
- for (i = 0; i < preflen; i++, pref+=2)
+ for (i = 0; i < num_pref; i++, pref+=2)
{
const unsigned char *tsupp = supp;
- for (j = 0; j < supplen; j++, tsupp+=2)
+ for (j = 0; j < num_supp; j++, tsupp+=2)
{
if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
{
}
if (nmatch == -1)
return k;
- return 0;
+ /* Out of range (nmatch > k). */
+ return NID_undef;
}
int tls1_set_curves(unsigned char **pext, size_t *pextlen,
* while curve ids < 32
*/
unsigned long dup_list = 0;
+#ifdef OPENSSL_NO_EC2M
+ EC_GROUP *curve;
+#endif
+
clist = OPENSSL_malloc(ncurves * 2);
if (!clist)
return 0;
unsigned long idmask;
int id;
id = tls1_ec_nid2curve_id(curves[i]);
+#ifdef OPENSSL_FIPS
+ /* NB: 25 is last curve ID supported by FIPS module */
+ if (FIPS_mode() && id > 25)
+ {
+ OPENSSL_free(clist);
+ return 0;
+ }
+#endif
+#ifdef OPENSSL_NO_EC2M
+ curve = EC_GROUP_new_by_curve_name(curves[i]);
+ if(!curve ||
+ EC_METHOD_get_field_type(EC_GROUP_method_of(curve))
+ == NID_X9_62_characteristic_two_field)
+ {
+ if(curve) EC_GROUP_free(curve);
+ OPENSSL_free(clist);
+ return 0;
+ }
+ else
+ EC_GROUP_free(curve);
+#endif
idmask = 1L << id;
if (!id || (dup_list & idmask))
{
return 1;
}
-#define MAX_CURVELIST 25
+#define MAX_CURVELIST 28
typedef struct
{
ncb.nidcnt = 0;
if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
return 0;
+ if (pext == NULL)
+ return 1;
return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
}
/* For an EC key set TLS id and required compression based on parameters */
{
int is_prime, id;
const EC_GROUP *grp;
- const EC_POINT *pt;
const EC_METHOD *meth;
if (!ec)
return 0;
/* Determine if it is a prime field */
grp = EC_KEY_get0_group(ec);
- pt = EC_KEY_get0_public_key(ec);
- if (!grp || !pt)
+ if (!grp)
return 0;
meth = EC_GROUP_method_of(grp);
if (!meth)
}
if (comp_id)
{
+ if (EC_KEY_get0_public_key(ec) == NULL)
+ return 0;
if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED)
{
if (is_prime)
static int tls1_check_ec_key(SSL *s,
unsigned char *curve_id, unsigned char *comp_id)
{
- const unsigned char *p;
- size_t plen, i;
+ const unsigned char *pformats, *pcurves;
+ size_t num_formats, num_curves, i;
int j;
/* If point formats extension present check it, otherwise everything
* is supported (see RFC4492).
*/
if (comp_id && s->session->tlsext_ecpointformatlist)
{
- p = s->session->tlsext_ecpointformatlist;
- plen = s->session->tlsext_ecpointformatlist_length;
- for (i = 0; i < plen; i++, p++)
+ pformats = s->session->tlsext_ecpointformatlist;
+ num_formats = s->session->tlsext_ecpointformatlist_length;
+ for (i = 0; i < num_formats; i++, pformats++)
{
- if (*comp_id == *p)
+ if (*comp_id == *pformats)
break;
}
- if (i == plen)
+ if (i == num_formats)
return 0;
}
if (!curve_id)
/* Check curve is consistent with client and server preferences */
for (j = 0; j <= 1; j++)
{
- tls1_get_curvelist(s, j, &p, &plen);
- for (i = 0; i < plen; i+=2, p+=2)
+ if (!tls1_get_curvelist(s, j, &pcurves, &num_curves))
+ return 0;
+ for (i = 0; i < num_curves; i++, pcurves += 2)
{
- if (p[0] == curve_id[0] && p[1] == curve_id[1])
+ if (pcurves[0] == curve_id[0] &&
+ pcurves[1] == curve_id[1])
break;
}
- if (i == plen)
+ if (i == num_curves)
return 0;
/* For clients can only check sent curve list */
if (!s->server)
}
static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
- size_t *pformatslen)
+ size_t *num_formats)
{
/* If we have a custom point format list use it otherwise
* use default */
if (s->tlsext_ecpointformatlist)
{
*pformats = s->tlsext_ecpointformatlist;
- *pformatslen = s->tlsext_ecpointformatlist_length;
+ *num_formats = s->tlsext_ecpointformatlist_length;
}
else
{
*pformats = ecformats_default;
/* For Suite B we don't support char2 fields */
if (tls1_suiteb(s))
- *pformatslen = sizeof(ecformats_default) - 1;
+ *num_formats = sizeof(ecformats_default) - 1;
else
- *pformatslen = sizeof(ecformats_default);
+ *num_formats = sizeof(ecformats_default);
}
}
}
return rv;
}
+#ifndef OPENSSL_NO_ECDH
/* Check EC temporary key is compatible with client extensions */
int tls1_check_ec_tmp_key(SSL *s, unsigned long cid)
{
return tls1_check_ec_key(s, curve_id, NULL);
#endif
}
+#endif /* OPENSSL_NO_ECDH */
+
+#else
+
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
+ {
+ return 1;
+ }
#endif /* OPENSSL_NO_EC */
#ifndef OPENSSL_NO_SHA
tlsext_sigalg(TLSEXT_hash_sha1)
#endif
-#ifndef OPENSSL_NO_MD5
- tlsext_sigalg_rsa(TLSEXT_hash_md5)
-#endif
};
-
+#ifndef OPENSSL_NO_ECDSA
static unsigned char suiteb_sigalgs[] = {
tlsext_sigalg_ecdsa(TLSEXT_hash_sha256)
tlsext_sigalg_ecdsa(TLSEXT_hash_sha384)
};
-
+#endif
size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
{
/* If Suite B mode use Suite B sigalgs only, ignore any other
* preferences.
*/
+#ifndef OPENSSL_NO_EC
switch (tls1_suiteb(s))
{
case SSL_CERT_FLAG_SUITEB_128_LOS:
*psigs = suiteb_sigalgs + 2;
return 2;
}
-
+#endif
/* If server use client authentication sigalgs if not NULL */
if (s->server && s->cert->client_sigalgs)
{
else
{
*psigs = tls12_sigalgs;
-#ifdef OPENSSL_FIPS
- /* If FIPS mode don't include MD5 which is last */
- if (FIPS_mode())
- return sizeof(tls12_sigalgs) - 2;
- else
-#endif
- return sizeof(tls12_sigalgs);
+ return sizeof(tls12_sigalgs);
}
}
/* Check signature algorithm is consistent with sent supported signature
SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
return 0;
}
+#ifndef OPENSSL_NO_EC
if (pkey->type == EVP_PKEY_EC)
{
unsigned char curve_id[2], comp_id;
}
else if (tls1_suiteb(s))
return 0;
+#endif
/* Check signature matches a type we sent */
sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
c->mask_a = 0;
c->mask_k = 0;
- /* If less than TLS 1.2 don't allow TLS 1.2 only ciphers */
- if (TLS1_get_client_version(s) < TLS1_2_VERSION)
+ /* Don't allow TLS 1.2 only ciphers if we don't suppport them */
+ if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
c->mask_ssl = SSL_TLSV1_2;
else
c->mask_ssl = 0;
c->mask_k |= SSL_kPSK;
}
#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (!(s->srp_ctx.srp_Mask & SSL_kSRP))
+ {
+ c->mask_a |= SSL_aSRP;
+ c->mask_k |= SSL_kSRP;
+ }
+#endif
c->valid = 1;
}
-/* byte_compare is a compare function for qsort(3) that compares bytes. */
-static int byte_compare(const void *in_a, const void *in_b)
- {
- unsigned char a = *((const unsigned char*) in_a);
- unsigned char b = *((const unsigned char*) in_b);
-
- if (a > b)
- return 1;
- else if (a < b)
- return -1;
- return 0;
-}
-
-unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, int *al)
{
int extdatalen=0;
- unsigned char *ret = p;
+ unsigned char *orig = buf;
+ unsigned char *ret = buf;
#ifndef OPENSSL_NO_EC
/* See if we support any ECC ciphersuites */
int using_ecc = 0;
- if (s->version != DTLS1_VERSION && s->version >= TLS1_VERSION)
+ if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s))
{
int i;
unsigned long alg_k, alg_a;
/* don't add extensions for SSLv3 unless doing secure renegotiation */
if (s->client_version == SSL3_VERSION
&& !s->s3->send_connection_binding)
- return p;
+ return orig;
ret+=2;
return NULL;
}
- if((limit - p - 4 - el) < 0) return NULL;
+ if((limit - ret - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_renegotiate,ret);
s2n(el,ret);
{
/* Add TLS extension ECPointFormats to the ClientHello message */
long lenmax;
- const unsigned char *plist;
- size_t plistlen;
+ const unsigned char *pcurves, *pformats;
+ size_t num_curves, num_formats, curves_list_len;
- tls1_get_formatlist(s, &plist, &plistlen);
+ tls1_get_formatlist(s, &pformats, &num_formats);
if ((lenmax = limit - ret - 5) < 0) return NULL;
- if (plistlen > (size_t)lenmax) return NULL;
- if (plistlen > 255)
+ 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;
}
s2n(TLSEXT_TYPE_ec_point_formats,ret);
- s2n(plistlen + 1,ret);
- *(ret++) = (unsigned char)plistlen ;
- memcpy(ret, plist, plistlen);
- ret+=plistlen;
+ /* The point format list has 1-byte length. */
+ s2n(num_formats + 1,ret);
+ *(ret++) = (unsigned char)num_formats ;
+ memcpy(ret, pformats, num_formats);
+ ret+=num_formats;
/* Add TLS extension EllipticCurves to the ClientHello message */
- plist = s->tlsext_ellipticcurvelist;
- tls1_get_curvelist(s, 0, &plist, &plistlen);
+ pcurves = s->tlsext_ellipticcurvelist;
+ if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves))
+ return NULL;
if ((lenmax = limit - ret - 6) < 0) return NULL;
- if (plistlen > (size_t)lenmax) return NULL;
- if (plistlen > 65532)
+ 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;
s2n(TLSEXT_TYPE_elliptic_curves,ret);
- s2n(plistlen + 2, ret);
-
- /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
- * elliptic_curve_list, but the examples use two bytes.
- * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
- * resolves this to two bytes.
- */
- s2n(plistlen, ret);
- memcpy(ret, plist, plistlen);
- ret+=plistlen;
+ s2n(curves_list_len + 2, ret);
+ s2n(curves_list_len, ret);
+ memcpy(ret, pcurves, curves_list_len);
+ ret+=curves_list_len;
}
#endif /* OPENSSL_NO_EC */
}
skip_ext:
- if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+ if (SSL_USE_SIGALGS(s))
{
size_t salglen;
const unsigned char *salg;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->client_opaque_prf_input != NULL &&
- s->version != DTLS1_VERSION)
+ if (s->s3->client_opaque_prf_input != NULL)
{
size_t col = s->s3->client_opaque_prf_input_len;
}
#endif
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
- s->version != DTLS1_VERSION)
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
{
int i;
long extlen, idlen, itmp;
#ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension */
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
s2n(TLSEXT_TYPE_heartbeat,ret);
s2n(1,ret);
/* Set mode:
}
#endif
- if(SSL_get_srtp_profiles(s))
+ 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(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
+ s2n(2 + s->alpn_client_proto_list_len,ret);
+ 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;
+ }
+
+ if(SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s))
{
int el;
ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
- if((limit - p - 4 - el) < 0) return NULL;
+ if((limit - ret - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_use_srtp,ret);
s2n(el,ret);
}
ret += el;
}
+ custom_ext_init(&s->cert->cli_ext);
+ /* Add custom TLS Extensions to ClientHello */
+ if (!custom_ext_add(s, 0, &ret, limit, al))
+ return NULL;
- /* Add TLS extension Server_Authz_DataFormats to the ClientHello */
- /* 2 bytes for extension type */
- /* 2 bytes for extension length */
- /* 1 byte for the list length */
- /* 1 byte for the list (we only support audit proofs) */
- if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+ /* Add padding to workaround bugs in F5 terminators.
+ * See https://tools.ietf.org/html/draft-agl-tls-padding-03
+ *
+ * NB: because this code works out the length of all existing
+ * extensions it MUST always appear last.
+ */
+ if (s->options & SSL_OP_TLSEXT_PADDING)
{
- const unsigned short ext_len = 2;
- const unsigned char list_len = 1;
-
- if (limit < ret + 6)
- return NULL;
+ int hlen = ret - (unsigned char *)s->init_buf->data;
+ /* The code in s23_clnt.c to build ClientHello messages
+ * includes the 5-byte record header in the buffer, while
+ * the code in s3_clnt.c does not.
+ */
+ if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+ hlen -= 5;
+ if (hlen > 0xff && hlen < 0x200)
+ {
+ hlen = 0x200 - hlen;
+ if (hlen >= 4)
+ hlen -= 4;
+ else
+ hlen = 0;
- s2n(TLSEXT_TYPE_server_authz, ret);
- /* Extension length: 2 bytes */
- s2n(ext_len, ret);
- *(ret++) = list_len;
- *(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
+ s2n(TLSEXT_TYPE_padding, ret);
+ s2n(hlen, ret);
+ memset(ret, 0, hlen);
+ ret += hlen;
+ }
}
- if ((extdatalen = ret-p-2) == 0)
- return p;
+ if ((extdatalen = ret-orig-2)== 0)
+ return orig;
- s2n(extdatalen,p);
+ s2n(extdatalen, orig);
return ret;
}
-unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, int *al)
{
int extdatalen=0;
- unsigned char *ret = p;
+ unsigned char *orig = buf;
+ unsigned char *ret = buf;
#ifndef OPENSSL_NO_NEXTPROTONEG
int next_proto_neg_seen;
#endif
+#ifndef OPENSSL_NO_EC
unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-
+#endif
/* don't add extensions for SSLv3, unless doing secure renegotiation */
if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
- return p;
+ return orig;
ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
return NULL;
}
- if((limit - p - 4 - el) < 0) return NULL;
+ if((limit - ret - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_renegotiate,ret);
s2n(el,ret);
}
#ifndef OPENSSL_NO_EC
- if (using_ecc && s->version != DTLS1_VERSION)
+ if (using_ecc)
{
const unsigned char *plist;
size_t plistlen;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->server_opaque_prf_input != NULL &&
- s->version != DTLS1_VERSION)
+ if (s->s3->server_opaque_prf_input != NULL)
{
size_t sol = s->s3->server_opaque_prf_input_len;
}
#endif
- if(s->srtp_profile)
+ if(SSL_IS_DTLS(s) && s->srtp_profile)
{
int el;
ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
- if((limit - p - 4 - el) < 0) return NULL;
+ if((limit - ret - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_use_srtp,ret);
s2n(el,ret);
/* Add Heartbeat extension if we've received one */
if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
{
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
s2n(TLSEXT_TYPE_heartbeat,ret);
s2n(1,ret);
/* Set mode:
}
}
#endif
+ if (!custom_ext_add(s, 1, &ret, limit, al))
+ return NULL;
- /* If the client supports authz then see whether we have any to offer
- * to it. */
- if (s->s3->tlsext_authz_client_types_len)
+ if (s->s3->alpn_selected)
{
- size_t authz_length;
- /* By now we already know the new cipher, so we can look ahead
- * to see whether the cert we are going to send
- * has any authz data attached to it. */
- const unsigned char* authz = ssl_get_authz_data(s, &authz_length);
- const unsigned char* const orig_authz = authz;
- size_t i;
- unsigned authz_count = 0;
-
- /* The authz data contains a number of the following structures:
- * uint8_t authz_type
- * uint16_t length
- * uint8_t data[length]
- *
- * First we walk over it to find the number of authz elements. */
- for (i = 0; i < authz_length; i++)
- {
- unsigned short length;
- unsigned char type;
-
- type = *(authz++);
- if (memchr(s->s3->tlsext_authz_client_types,
- type,
- s->s3->tlsext_authz_client_types_len) != NULL)
- authz_count++;
-
- n2s(authz, length);
- /* n2s increments authz by 2 */
- i += 2;
- authz += length;
- i += length;
- }
-
- if (authz_count)
- {
- /* Add TLS extension server_authz to the ServerHello message
- * 2 bytes for extension type
- * 2 bytes for extension length
- * 1 byte for the list length
- * n bytes for the list */
- const unsigned short ext_len = 1 + authz_count;
-
- if ((long)(limit - ret - 4 - ext_len) < 0) return NULL;
- s2n(TLSEXT_TYPE_server_authz, ret);
- s2n(ext_len, ret);
- *(ret++) = authz_count;
- s->s3->tlsext_authz_promised_to_client = 1;
- }
+ const unsigned char *selected = s->s3->alpn_selected;
+ unsigned len = s->s3->alpn_selected_len;
- authz = orig_authz;
- for (i = 0; i < authz_length; i++)
- {
- unsigned short length;
- unsigned char type;
-
- authz_count++;
- type = *(authz++);
- if (memchr(s->s3->tlsext_authz_client_types,
- type,
- s->s3->tlsext_authz_client_types_len) != NULL)
- *(ret++) = type;
- n2s(authz, length);
- /* n2s increments authz by 2 */
- i += 2;
- authz += length;
- i += length;
- }
+ if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
+ s2n(3 + len,ret);
+ s2n(1 + len,ret);
+ *ret++ = len;
+ memcpy(ret, selected, len);
+ ret += len;
}
- if ((extdatalen = ret-p-2)== 0)
- return p;
+ if ((extdatalen = ret-orig-2)== 0)
+ return orig;
- s2n(extdatalen,p);
+ s2n(extdatalen, orig);
return ret;
}
+#ifndef OPENSSL_NO_EC
+/* ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ * SNI,
+ * elliptic_curves
+ * ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
+ unsigned short type, size;
+ static const unsigned char kSafariExtensionsBlock[] = {
+ 0x00, 0x0a, /* elliptic_curves extension */
+ 0x00, 0x08, /* 8 bytes */
+ 0x00, 0x06, /* 6 bytes of curve ids */
+ 0x00, 0x17, /* P-256 */
+ 0x00, 0x18, /* P-384 */
+ 0x00, 0x19, /* P-521 */
+
+ 0x00, 0x0b, /* ec_point_formats */
+ 0x00, 0x02, /* 2 bytes */
+ 0x01, /* 1 point format */
+ 0x00, /* uncompressed */
+ };
+
+ /* The following is only present in TLS 1.2 */
+ static const unsigned char kSafariTLS12ExtensionsBlock[] = {
+ 0x00, 0x0d, /* signature_algorithms */
+ 0x00, 0x0c, /* 12 bytes */
+ 0x00, 0x0a, /* 10 bytes */
+ 0x05, 0x01, /* SHA-384/RSA */
+ 0x04, 0x01, /* SHA-256/RSA */
+ 0x02, 0x01, /* SHA-1/RSA */
+ 0x04, 0x03, /* SHA-256/ECDSA */
+ 0x02, 0x03, /* SHA-1/ECDSA */
+ };
+
+ if (data >= (d+n-2))
+ return;
+ data += 2;
+
+ if (data > (d+n-4))
+ return;
+ n2s(data,type);
+ n2s(data,size);
+
+ if (type != TLSEXT_TYPE_server_name)
+ return;
+
+ if (data+size > d+n)
+ return;
+ data += size;
+
+ if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+ {
+ const size_t len1 = sizeof(kSafariExtensionsBlock);
+ const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
+
+ if (data + len1 + len2 != d+n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+ return;
+ if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+ return;
+ }
+ else
+ {
+ const size_t len = sizeof(kSafariExtensionsBlock);
+
+ if (data + len != d+n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+ return;
+ }
+
+ s->s3->is_probably_safari = 1;
+}
+#endif /* !OPENSSL_NO_EC */
+
+/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
+ * ClientHello.
+ * data: the contents of the extension, not including the type and length.
+ * data_len: the number of bytes in |data|
+ * al: a pointer to the alert value to send in the event of a non-zero
+ * return.
+ *
+ * returns: 0 on success. */
+static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
+ unsigned data_len, int *al)
+ {
+ unsigned i;
+ unsigned proto_len;
+ const unsigned char *selected;
+ unsigned char selected_len;
+ int r;
+
+ if (s->ctx->alpn_select_cb == NULL)
+ return 0;
+
+ if (data_len < 2)
+ goto parse_error;
+
+ /* data should contain a uint16 length followed by a series of 8-bit,
+ * length-prefixed strings. */
+ i = ((unsigned) data[0]) << 8 |
+ ((unsigned) data[1]);
+ data_len -= 2;
+ data += 2;
+ if (data_len != i)
+ goto parse_error;
+
+ if (data_len < 2)
+ goto parse_error;
+
+ for (i = 0; i < data_len;)
+ {
+ proto_len = data[i];
+ i++;
+
+ if (proto_len == 0)
+ goto parse_error;
+
+ if (i + proto_len < i || i + proto_len > data_len)
+ goto parse_error;
+
+ i += proto_len;
+ }
+
+ r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len,
+ s->ctx->alpn_select_cb_arg);
+ if (r == SSL_TLSEXT_ERR_OK) {
+ if (s->s3->alpn_selected)
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_malloc(selected_len);
+ if (!s->s3->alpn_selected)
+ {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return -1;
+ }
+ memcpy(s->s3->alpn_selected, selected, selected_len);
+ s->s3->alpn_selected_len = selected_len;
+ }
+ return 0;
+
+parse_error:
+ *al = SSL_AD_DECODE_ERROR;
+ return -1;
+ }
+
static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
{
unsigned short type;
unsigned short len;
unsigned char *data = *p;
int renegotiate_seen = 0;
- size_t i;
s->servername_done = 0;
s->tlsext_status_type = -1;
s->s3->next_proto_neg_seen = 0;
#endif
+ if (s->s3->alpn_selected)
+ {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
+ }
+
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
#endif
+
+#ifndef OPENSSL_NO_EC
+ if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+ ssl_check_for_safari(s, data, d, n);
+#endif /* !OPENSSL_NO_EC */
+
/* Clear any signature algorithms extension received */
if (s->cert->peer_sigalgs)
{
OPENSSL_free(s->cert->peer_sigalgs);
s->cert->peer_sigalgs = NULL;
}
- /* Clear any shared sigtnature algorithms */
- if (s->cert->shared_sigalgs)
- {
- OPENSSL_free(s->cert->shared_sigalgs);
- s->cert->shared_sigalgs = NULL;
- }
- /* Clear certificate digests and validity flags */
- for (i = 0; i < SSL_PKEY_NUM; i++)
+
+#ifndef OPENSSL_NO_SRP
+ if (s->srp_ctx.login != NULL)
{
- s->cert->pkeys[i].digest = NULL;
- s->cert->pkeys[i].valid_flags = 0;
+ OPENSSL_free(s->srp_ctx.login);
+ s->srp_ctx.login = NULL;
}
+#endif
+
+ s->srtp_profile = NULL;
if (data >= (d+n-2))
goto ri_check;
#endif
#ifndef OPENSSL_NO_EC
- else if (type == TLSEXT_TYPE_ec_point_formats &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_ec_point_formats)
{
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
fprintf(stderr,"\n");
#endif
}
- else if (type == TLSEXT_TYPE_elliptic_curves &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_elliptic_curves)
{
unsigned char *sdata = data;
int ellipticcurvelist_length = (*(sdata++) << 8);
ellipticcurvelist_length += (*(sdata++));
if (ellipticcurvelist_length != size - 2 ||
- ellipticcurvelist_length < 1)
+ ellipticcurvelist_length < 1 ||
+ /* Each NamedCurve is 2 bytes. */
+ ellipticcurvelist_length & 1)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
#endif /* OPENSSL_NO_EC */
#ifdef TLSEXT_TYPE_opaque_prf_input
- else if (type == TLSEXT_TYPE_opaque_prf_input &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
*al = SSL_AD_DECODE_ERROR;
return 0;
}
- if (!tls1_process_sigalgs(s, data, dsize))
+ if (!tls1_save_sigalgs(s, data, dsize))
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
- /* If sigalgs received and no shared algorithms fatal
- * error.
- */
- if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
- {
- SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
- SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
- *al = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
}
- else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+ else if (type == TLSEXT_TYPE_status_request)
{
if (size < 5)
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
- s->s3->tmp.finish_md_len == 0)
+ s->s3->tmp.finish_md_len == 0 &&
+ s->s3->alpn_selected == NULL)
{
/* We shouldn't accept this extension on a
* renegotiation.
}
#endif
+ else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
+ s->ctx->alpn_select_cb &&
+ s->s3->tmp.finish_md_len == 0)
+ {
+ if (tls1_alpn_handle_client_hello(s, data, size, al) != 0)
+ return 0;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* ALPN takes precedence over NPN. */
+ s->s3->next_proto_neg_seen = 0;
+#endif
+ }
+
/* session ticket processed earlier */
- else if (type == TLSEXT_TYPE_use_srtp)
+ else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
+ && type == TLSEXT_TYPE_use_srtp)
{
if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
al))
return 0;
}
- else if (type == TLSEXT_TYPE_server_authz)
- {
- unsigned char *sdata = data;
- unsigned char server_authz_dataformatlist_length;
-
- if (size == 0)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
-
- server_authz_dataformatlist_length = *(sdata++);
-
- if (server_authz_dataformatlist_length != size - 1)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
-
- /* Successful session resumption uses the same authz
- * information as the original session so we ignore this
- * in the case of a session resumption. */
- if (!s->hit)
- {
- if (s->s3->tlsext_authz_client_types != NULL)
- OPENSSL_free(s->s3->tlsext_authz_client_types);
- s->s3->tlsext_authz_client_types =
- OPENSSL_malloc(server_authz_dataformatlist_length);
- if (!s->s3->tlsext_authz_client_types)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
-
- s->s3->tlsext_authz_client_types_len =
- server_authz_dataformatlist_length;
- memcpy(s->s3->tlsext_authz_client_types,
- sdata,
- server_authz_dataformatlist_length);
-
- /* Sort the types in order to check for duplicates. */
- qsort(s->s3->tlsext_authz_client_types,
- server_authz_dataformatlist_length,
- 1 /* element size */,
- byte_compare);
-
- for (i = 0; i < server_authz_dataformatlist_length; i++)
- {
- if (i > 0 &&
- s->s3->tlsext_authz_client_types[i] ==
- s->s3->tlsext_authz_client_types[i-1])
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
- }
- }
- }
-
data+=size;
}
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
- /* If no signature algorithms extension set default values */
- if (!s->cert->peer_sigalgs)
- ssl_cert_set_default_md(s->cert);
+
+ return 1;
+ }
+
+/*
+ * Parse any custom extensions found. "data" is the start of the extension data
+ * and "limit" is the end of the record. TODO: add strict syntax checking.
+ */
+
+static int ssl_scan_clienthello_custom_tlsext(SSL *s, const unsigned char *data, const unsigned char *limit, int *al)
+ {
+ unsigned short type, size, len;
+ /* If resumed session or no custom extensions nothing to do */
+ if (s->hit || s->cert->srv_ext.meths_count == 0)
+ return 1;
+
+ if (data >= limit - 2)
+ return 1;
+ n2s(data, len);
+
+ if (data > limit - len)
+ return 1;
+
+ while (data <= limit - 4)
+ {
+ n2s(data, type);
+ n2s(data, size);
+
+ if (data+size > limit)
+ return 1;
+ if (custom_ext_parse(s, 1 /* server */, type, data, size, al) <= 0)
+ return 0;
+
+ data+=size;
+ }
return 1;
}
int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
{
int al = -1;
+ unsigned char *ptmp = *p;
+ /*
+ * Internally supported extensions are parsed first so SNI can be handled
+ * before custom extensions. An application processing SNI will typically
+ * switch the parent context using SSL_set_SSL_CTX and custom extensions
+ * need to be handled by the new SSL_CTX structure.
+ */
if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0)
{
ssl3_send_alert(s,SSL3_AL_FATAL,al);
SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
return 0;
}
+
+ custom_ext_init(&s->cert->srv_ext);
+ if (ssl_scan_clienthello_custom_tlsext(s, ptmp, d + n, &al) <= 0)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return 0;
+ }
+
return 1;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
s->s3->next_proto_neg_seen = 0;
#endif
+ s->tlsext_ticket_expected = 0;
+
+ if (s->s3->alpn_selected)
+ {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
+ }
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
}
#ifndef OPENSSL_NO_EC
- else if (type == TLSEXT_TYPE_ec_point_formats &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_ec_point_formats)
{
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
- s->session->tlsext_ecpointformatlist_length = 0;
- if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
- if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ if (!s->hit)
{
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
}
- s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
- memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
#if 0
fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
sdata = s->session->tlsext_ecpointformatlist;
s->tlsext_ticket_expected = 1;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
- else if (type == TLSEXT_TYPE_opaque_prf_input &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
}
}
#endif
- else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION)
+ else if (type == TLSEXT_TYPE_status_request)
{
/* MUST be empty and only sent if we've requested
* a status request message.
s->s3->next_proto_neg_seen = 1;
}
#endif
+
+ else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation)
+ {
+ unsigned len;
+
+ /* We must have requested it. */
+ if (s->alpn_client_proto_list == NULL)
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ if (size < 4)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ /* The extension data consists of:
+ * uint16 list_length
+ * uint8 proto_length;
+ * uint8 proto[proto_length]; */
+ len = data[0];
+ len <<= 8;
+ len |= data[1];
+ if (len != (unsigned) size - 2)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ len = data[2];
+ if (len != (unsigned) size - 3)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->s3->alpn_selected)
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_malloc(len);
+ if (!s->s3->alpn_selected)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->s3->alpn_selected, data + 3, len);
+ s->s3->alpn_selected_len = len;
+ }
+
else if (type == TLSEXT_TYPE_renegotiate)
{
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
}
}
#endif
- else if (type == TLSEXT_TYPE_use_srtp)
+ else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp)
{
if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
al))
return 0;
}
-
- else if (type == TLSEXT_TYPE_server_authz)
- {
- /* We only support audit proofs. It's an error to send
- * an authz hello extension if the client
- * didn't request a proof. */
- unsigned char *sdata = data;
- unsigned char server_authz_dataformatlist_length;
-
- if (!s->ctx->tlsext_authz_server_audit_proof_cb)
- {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
-
- if (!size)
- {
- *al = TLS1_AD_DECODE_ERROR;
- return 0;
- }
-
- server_authz_dataformatlist_length = *(sdata++);
- if (server_authz_dataformatlist_length != size - 1)
- {
- *al = TLS1_AD_DECODE_ERROR;
+ /* If this extension type was not otherwise handled, but
+ * matches a custom_cli_ext_record, then send it to the c
+ * callback */
+ else if (custom_ext_parse(s, 0, type, data, size, al) <= 0)
return 0;
- }
-
- /* We only support audit proofs, so a legal ServerHello
- * authz list contains exactly one entry. */
- if (server_authz_dataformatlist_length != 1 ||
- sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof)
- {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
-
- s->s3->tlsext_authz_server_promised = 1;
- }
data += size;
}
}
}
+int tls1_set_server_sigalgs(SSL *s)
+ {
+ int al;
+ size_t i;
+ /* Clear any shared sigtnature algorithms */
+ if (s->cert->shared_sigalgs)
+ {
+ OPENSSL_free(s->cert->shared_sigalgs);
+ s->cert->shared_sigalgs = NULL;
+ }
+ /* Clear certificate digests and validity flags */
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ s->cert->pkeys[i].digest = NULL;
+ s->cert->pkeys[i].valid_flags = 0;
+ }
+
+ /* If sigalgs received process it. */
+ if (s->cert->peer_sigalgs)
+ {
+ if (!tls1_process_sigalgs(s))
+ {
+ SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS,
+ ERR_R_MALLOC_FAILURE);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ /* Fatal error is no shared signature algorithms */
+ if (!s->cert->shared_sigalgs)
+ {
+ SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS,
+ SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ goto err;
+ }
+ }
+ else
+ ssl_cert_set_default_md(s->cert);
+ return 1;
+ err:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
+ }
+
int ssl_check_clienthello_tlsext_late(SSL *s)
{
int ret = SSL_TLSEXT_ERR_OK;
if (p >= limit)
return -1;
/* Skip past DTLS cookie */
- if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ if (SSL_IS_DTLS(s))
{
i = *(p++);
p+= i;
HMAC_Update(&hctx, etick, eticklen);
HMAC_Final(&hctx, tick_hmac, NULL);
HMAC_CTX_cleanup(&hctx);
- if (memcmp(tick_hmac, etick + eticklen, mlen))
+ if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
return 2;
+ }
/* Attempt to decrypt session data */
/* Move p after IV to start of encrypted ticket, update length */
p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
}
EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ OPENSSL_free(sdec);
return 2;
+ }
slen += mlen;
EVP_CIPHER_CTX_cleanup(&ctx);
p = sdec;
TLS_SIGALGS *salgs = NULL;
CERT *c = s->cert;
unsigned int is_suiteb = tls1_suiteb(s);
+ if (c->shared_sigalgs)
+ {
+ OPENSSL_free(c->shared_sigalgs);
+ c->shared_sigalgs = NULL;
+ }
/* If client use client signature algorithms if not NULL */
if (!s->server && c->client_sigalgs && !is_suiteb)
{
/* Set preferred digest for each key type */
-int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize)
{
- int idx;
- size_t i;
- const EVP_MD *md;
CERT *c = s->cert;
- TLS_SIGALGS *sigptr;
- /* Extension ignored for TLS versions below 1.2 */
- if (TLS1_get_version(s) < TLS1_2_VERSION)
+ /* Extension ignored for inappropriate versions */
+ if (!SSL_USE_SIGALGS(s))
return 1;
/* Should never happen */
if (!c)
return 0;
+ if (c->peer_sigalgs)
+ OPENSSL_free(c->peer_sigalgs);
c->peer_sigalgs = OPENSSL_malloc(dsize);
if (!c->peer_sigalgs)
return 0;
c->peer_sigalgslen = dsize;
memcpy(c->peer_sigalgs, data, dsize);
+ return 1;
+ }
- tls1_set_shared_sigalgs(s);
+int tls1_process_sigalgs(SSL *s)
+ {
+ int idx;
+ size_t i;
+ const EVP_MD *md;
+ CERT *c = s->cert;
+ TLS_SIGALGS *sigptr;
+ if (!tls1_set_shared_sigalgs(s))
+ return 0;
#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
- /* Read type and payload length first */
- hbtype = *p++;
- n2s(p, payload);
- pl = p;
-
if (s->msg_callback)
s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
&s->s3->rrec.data[0], s->s3->rrec.length,
s, s->msg_callback_arg);
+ /* Read type and payload length first */
+ if (1 + 2 + 16 > s->s3->rrec.length)
+ return 0; /* silently discard */
+ hbtype = *p++;
+ n2s(p, payload);
+ if (1 + 2 + payload + 16 > s->s3->rrec.length)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+ pl = p;
+
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
if (check_flags)
check_flags |= CERT_PKEY_SUITEB;
ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
- if (ok != X509_V_OK)
- {
- if (check_flags)
- rv |= CERT_PKEY_SUITEB;
- else
- goto end;
- }
+ if (ok == X509_V_OK)
+ rv |= CERT_PKEY_SUITEB;
+ else if (!check_flags)
+ goto end;
}
/* Check all signature algorithms are consistent with