summaryrefslogtreecommitdiffstats
path: root/drivers/builtin_openssl2/ssl/t1_lib.c
diff options
context:
space:
mode:
authormrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
committermrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
commite97922f22038e9049ed4c2db5b3736dfaa0edde3 (patch)
tree37e036a343e7482a387b7acd0a88509af78a69eb /drivers/builtin_openssl2/ssl/t1_lib.c
parent880f4abda44a42532abb6f15999a90bc85f6264a (diff)
downloadredot-engine-e97922f22038e9049ed4c2db5b3736dfaa0edde3.tar.gz
Update OpenSSL to version 1.0.2g
Diffstat (limited to 'drivers/builtin_openssl2/ssl/t1_lib.c')
-rw-r--r--drivers/builtin_openssl2/ssl/t1_lib.c2223
1 files changed, 1961 insertions, 262 deletions
diff --git a/drivers/builtin_openssl2/ssl/t1_lib.c b/drivers/builtin_openssl2/ssl/t1_lib.c
index 2e9b65b3fd..d9ba99d735 100644
--- a/drivers/builtin_openssl2/ssl/t1_lib.c
+++ b/drivers/builtin_openssl2/ssl/t1_lib.c
@@ -113,6 +113,11 @@
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#ifndef OPENSSL_NO_EC
+#ifdef OPENSSL_NO_EC2M
+# include <openssl/ec.h>
+#endif
+#endif
#include <openssl/ocsp.h>
#include <openssl/rand.h>
#include "ssl_locl.h"
@@ -123,6 +128,8 @@ const char tls1_version_str[] = "TLSv1" OPENSSL_VERSION_PTEXT;
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
SSL_SESSION **psess);
+static int ssl_check_clienthello_tlsext_early(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
#endif
SSL3_ENC_METHOD TLSv1_enc_data = {
@@ -138,6 +145,49 @@ SSL3_ENC_METHOD TLSv1_enc_data = {
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)
@@ -200,52 +250,133 @@ static int nid_list[] = {
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 int pref_list[] = {
-# ifndef OPENSSL_NO_EC2M
- NID_sect571r1, /* sect571r1 (14) */
- NID_sect571k1, /* sect571k1 (13) */
-# endif
- NID_secp521r1, /* secp521r1 (25) */
-# ifndef OPENSSL_NO_EC2M
- NID_sect409k1, /* sect409k1 (11) */
- NID_sect409r1, /* sect409r1 (12) */
-# endif
- NID_secp384r1, /* secp384r1 (24) */
-# ifndef OPENSSL_NO_EC2M
- NID_sect283k1, /* sect283k1 (9) */
- NID_sect283r1, /* sect283r1 (10) */
-# endif
- NID_secp256k1, /* secp256k1 (22) */
- NID_X9_62_prime256v1, /* secp256r1 (23) */
+static const unsigned char ecformats_default[] = {
+ TLSEXT_ECPOINTFORMAT_uncompressed,
+ TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+ TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+};
+
+/* The client's default curves / the server's 'auto' curves. */
+static const unsigned char eccurves_auto[] = {
+ /* Prefer P-256 which has the fastest and most secure implementations. */
+ 0, 23, /* secp256r1 (23) */
+ /* Other >= 256-bit prime curves. */
+ 0, 25, /* secp521r1 (25) */
+ 0, 28, /* brainpool512r1 (28) */
+ 0, 27, /* brainpoolP384r1 (27) */
+ 0, 24, /* secp384r1 (24) */
+ 0, 26, /* brainpoolP256r1 (26) */
+ 0, 22, /* secp256k1 (22) */
# ifndef OPENSSL_NO_EC2M
- NID_sect239k1, /* sect239k1 (8) */
- NID_sect233k1, /* sect233k1 (6) */
- NID_sect233r1, /* sect233r1 (7) */
+ /* >= 256-bit binary curves. */
+ 0, 14, /* sect571r1 (14) */
+ 0, 13, /* sect571k1 (13) */
+ 0, 11, /* sect409k1 (11) */
+ 0, 12, /* sect409r1 (12) */
+ 0, 9, /* sect283k1 (9) */
+ 0, 10, /* sect283r1 (10) */
# endif
- NID_secp224k1, /* secp224k1 (20) */
- NID_secp224r1, /* secp224r1 (21) */
+};
+
+static const unsigned char eccurves_all[] = {
+ /* Prefer P-256 which has the fastest and most secure implementations. */
+ 0, 23, /* secp256r1 (23) */
+ /* Other >= 256-bit prime curves. */
+ 0, 25, /* secp521r1 (25) */
+ 0, 28, /* brainpool512r1 (28) */
+ 0, 27, /* brainpoolP384r1 (27) */
+ 0, 24, /* secp384r1 (24) */
+ 0, 26, /* brainpoolP256r1 (26) */
+ 0, 22, /* secp256k1 (22) */
# ifndef OPENSSL_NO_EC2M
- NID_sect193r1, /* sect193r1 (4) */
- NID_sect193r2, /* sect193r2 (5) */
+ /* >= 256-bit binary curves. */
+ 0, 14, /* sect571r1 (14) */
+ 0, 13, /* sect571k1 (13) */
+ 0, 11, /* sect409k1 (11) */
+ 0, 12, /* sect409r1 (12) */
+ 0, 9, /* sect283k1 (9) */
+ 0, 10, /* sect283r1 (10) */
# endif
- NID_secp192k1, /* secp192k1 (18) */
- NID_X9_62_prime192v1, /* secp192r1 (19) */
+ /*
+ * Remaining curves disabled by default but still permitted if set
+ * via an explicit callback or parameters.
+ */
+ 0, 20, /* secp224k1 (20) */
+ 0, 21, /* secp224r1 (21) */
+ 0, 18, /* secp192k1 (18) */
+ 0, 19, /* secp192r1 (19) */
+ 0, 15, /* secp160k1 (15) */
+ 0, 16, /* secp160r1 (16) */
+ 0, 17, /* secp160r2 (17) */
# ifndef OPENSSL_NO_EC2M
- NID_sect163k1, /* sect163k1 (1) */
- NID_sect163r1, /* sect163r1 (2) */
- NID_sect163r2, /* sect163r2 (3) */
+ 0, 8, /* sect239k1 (8) */
+ 0, 6, /* sect233k1 (6) */
+ 0, 7, /* sect233r1 (7) */
+ 0, 4, /* sect193r1 (4) */
+ 0, 5, /* sect193r2 (5) */
+ 0, 1, /* sect163k1 (1) */
+ 0, 2, /* sect163r1 (2) */
+ 0, 3, /* sect163r2 (3) */
# endif
- NID_secp160k1, /* secp160k1 (15) */
- NID_secp160r1, /* secp160r1 (16) */
- NID_secp160r2, /* secp160r2 (17) */
};
+static const unsigned char suiteb_curves[] = {
+ 0, TLSEXT_curve_P_256,
+ 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 RFC 4492 */
+ /* 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;
@@ -254,7 +385,7 @@ int tls1_ec_curve_id2nid(int curve_id)
int tls1_ec_nid2curve_id(int nid)
{
- /* ECC curves from RFC 4492 */
+ /* ECC curves from RFC 4492 and RFC 7027 */
switch (nid) {
case NID_sect163k1: /* sect163k1 (1) */
return 1;
@@ -306,10 +437,548 @@ int tls1_ec_nid2curve_id(int nid)
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.
+ * 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 int tls1_get_curvelist(SSL *s, int sess,
+ const unsigned char **pcurves,
+ size_t *num_curves)
+{
+ size_t pcurveslen = 0;
+ if (sess) {
+ *pcurves = s->session->tlsext_ellipticcurvelist;
+ pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+ } else {
+ /* 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_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
+ {
+ if (!s->server || s->cert->ecdh_tmp_auto) {
+ *pcurves = eccurves_auto;
+ pcurveslen = sizeof(eccurves_auto);
+ } else {
+ *pcurves = eccurves_all;
+ pcurveslen = sizeof(eccurves_all);
+ }
+ }
+ }
+ }
+ /* 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;
+ } else {
+ *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 num_curves, i;
+ unsigned int suiteb_flags = tls1_suiteb(s);
+ if (len != 3 || p[0] != NAMED_CURVE_TYPE)
+ return 0;
+ /* Check curve matches Suite B preferences */
+ if (suiteb_flags) {
+ unsigned long cid = s->s3->tmp.new_cipher->id;
+ if (p[1])
+ return 0;
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) {
+ if (p[2] != TLSEXT_curve_P_256)
+ return 0;
+ } else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) {
+ if (p[2] != TLSEXT_curve_P_384)
+ return 0;
+ } else /* Should never happen */
+ return 0;
+ }
+ 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 |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 num_pref, num_supp, i, j;
+ int k;
+ /* Can't do anything on client side */
+ if (s->server == 0)
+ return -1;
+ if (nmatch == -2) {
+ if (tls1_suiteb(s)) {
+ /*
+ * For Suite B ciphersuite determines curve: we already know
+ * these are acceptable due to previous checks.
+ */
+ unsigned long cid = s->s3->tmp.new_cipher->id;
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+ return NID_X9_62_prime256v1; /* P-256 */
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+ return NID_secp384r1; /* P-384 */
+ /* Should never happen */
+ return NID_undef;
+ }
+ /* If not Suite B just return first preference shared curve */
+ nmatch = 0;
+ }
+ /*
+ * 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;
+
+ /*
+ * If the client didn't send the elliptic_curves extension all of them
+ * are allowed.
+ */
+ if (num_supp == 0 && (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0) {
+ supp = eccurves_all;
+ num_supp = sizeof(eccurves_all) / 2;
+ } else if (num_pref == 0 &&
+ (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0) {
+ pref = eccurves_all;
+ num_pref = sizeof(eccurves_all) / 2;
+ }
+
+ k = 0;
+ for (i = 0; i < num_pref; i++, pref += 2) {
+ const unsigned char *tsupp = supp;
+ for (j = 0; j < num_supp; j++, tsupp += 2) {
+ if (pref[0] == tsupp[0] && pref[1] == tsupp[1]) {
+ if (nmatch == k) {
+ int id = (pref[0] << 8) | pref[1];
+ return tls1_ec_curve_id2nid(id);
+ }
+ k++;
+ }
+ }
+ }
+ if (nmatch == -1)
+ return k;
+ /* Out of range (nmatch > k). */
+ return NID_undef;
+}
+
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+ int *curves, size_t ncurves)
+{
+ unsigned char *clist, *p;
+ size_t i;
+ /*
+ * Bitmap of curves included to detect duplicates: only works 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;
+ for (i = 0, p = clist; i < ncurves; i++) {
+ 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)) {
+ OPENSSL_free(clist);
+ return 0;
+ }
+ dup_list |= idmask;
+ s2n(id, p);
+ }
+ if (*pext)
+ OPENSSL_free(*pext);
+ *pext = clist;
+ *pextlen = ncurves * 2;
+ return 1;
+}
+
+# define MAX_CURVELIST 28
+
+typedef struct {
+ size_t nidcnt;
+ int nid_arr[MAX_CURVELIST];
+} nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+{
+ nid_cb_st *narg = arg;
+ size_t i;
+ int nid;
+ char etmp[20];
+ if (elem == NULL)
+ return 0;
+ if (narg->nidcnt == MAX_CURVELIST)
+ return 0;
+ if (len > (int)(sizeof(etmp) - 1))
+ return 0;
+ memcpy(etmp, elem, len);
+ etmp[len] = 0;
+ nid = EC_curve_nist2nid(etmp);
+ if (nid == NID_undef)
+ nid = OBJ_sn2nid(etmp);
+ if (nid == NID_undef)
+ nid = OBJ_ln2nid(etmp);
+ if (nid == NID_undef)
+ return 0;
+ for (i = 0; i < narg->nidcnt; i++)
+ if (narg->nid_arr[i] == nid)
+ return 0;
+ narg->nid_arr[narg->nidcnt++] = nid;
+ return 1;
+}
+
+/* Set curves based on a colon separate list */
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen,
+ const char *str)
+{
+ nid_cb_st ncb;
+ 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 */
+static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id,
+ EC_KEY *ec)
+{
+ int is_prime, id;
+ const EC_GROUP *grp;
+ const EC_METHOD *meth;
+ if (!ec)
+ return 0;
+ /* Determine if it is a prime field */
+ grp = EC_KEY_get0_group(ec);
+ if (!grp)
+ return 0;
+ meth = EC_GROUP_method_of(grp);
+ if (!meth)
+ return 0;
+ if (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field)
+ is_prime = 1;
+ else
+ is_prime = 0;
+ /* Determine curve ID */
+ id = EC_GROUP_get_curve_name(grp);
+ id = tls1_ec_nid2curve_id(id);
+ /* If we have an ID set it, otherwise set arbitrary explicit curve */
+ if (id) {
+ curve_id[0] = 0;
+ curve_id[1] = (unsigned char)id;
+ } else {
+ curve_id[0] = 0xff;
+ if (is_prime)
+ curve_id[1] = 0x01;
+ else
+ curve_id[1] = 0x02;
+ }
+ 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)
+ *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+ else
+ *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+ } else
+ *comp_id = TLSEXT_ECPOINTFORMAT_uncompressed;
+ }
+ return 1;
+}
+
+/* Check an EC key is compatible with extensions */
+static int tls1_check_ec_key(SSL *s,
+ unsigned char *curve_id, unsigned char *comp_id)
+{
+ 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) {
+ pformats = s->session->tlsext_ecpointformatlist;
+ num_formats = s->session->tlsext_ecpointformatlist_length;
+ for (i = 0; i < num_formats; i++, pformats++) {
+ if (*comp_id == *pformats)
+ break;
+ }
+ if (i == num_formats)
+ return 0;
+ }
+ if (!curve_id)
+ return 1;
+ /* Check curve is consistent with client and server preferences */
+ for (j = 0; j <= 1; j++) {
+ if (!tls1_get_curvelist(s, j, &pcurves, &num_curves))
+ return 0;
+ if (j == 1 && num_curves == 0) {
+ /*
+ * If we've not received any curves then skip this check.
+ * RFC 4492 does not require the supported elliptic curves extension
+ * so if it is not sent we can just choose any curve.
+ * It is invalid to send an empty list in the elliptic curves
+ * extension, so num_curves == 0 always means no extension.
+ */
+ break;
+ }
+ for (i = 0; i < num_curves; i++, pcurves += 2) {
+ if (pcurves[0] == curve_id[0] && pcurves[1] == curve_id[1])
+ break;
+ }
+ if (i == num_curves)
+ return 0;
+ /* For clients can only check sent curve list */
+ if (!s->server)
+ return 1;
+ }
+ return 1;
+}
+
+static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+ 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;
+ *num_formats = s->tlsext_ecpointformatlist_length;
+ } else {
+ *pformats = ecformats_default;
+ /* For Suite B we don't support char2 fields */
+ if (tls1_suiteb(s))
+ *num_formats = sizeof(ecformats_default) - 1;
+ else
+ *num_formats = sizeof(ecformats_default);
+ }
+}
+
+/*
+ * Check cert parameters compatible with extensions: currently just checks EC
+ * certificates have compatible curves and compression.
+ */
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
+{
+ unsigned char comp_id, curve_id[2];
+ EVP_PKEY *pkey;
+ int rv;
+ pkey = X509_get_pubkey(x);
+ if (!pkey)
+ return 0;
+ /* If not EC nothing to do */
+ if (pkey->type != EVP_PKEY_EC) {
+ EVP_PKEY_free(pkey);
+ return 1;
+ }
+ rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec);
+ EVP_PKEY_free(pkey);
+ if (!rv)
+ return 0;
+ /*
+ * Can't check curve_id for client certs as we don't have a supported
+ * curves extension.
+ */
+ rv = tls1_check_ec_key(s, s->server ? curve_id : NULL, &comp_id);
+ if (!rv)
+ return 0;
+ /*
+ * Special case for suite B. We *MUST* sign using SHA256+P-256 or
+ * SHA384+P-384, adjust digest if necessary.
+ */
+ if (set_ee_md && tls1_suiteb(s)) {
+ int check_md;
+ size_t i;
+ CERT *c = s->cert;
+ if (curve_id[0])
+ return 0;
+ /* Check to see we have necessary signing algorithm */
+ if (curve_id[1] == TLSEXT_curve_P_256)
+ check_md = NID_ecdsa_with_SHA256;
+ else if (curve_id[1] == TLSEXT_curve_P_384)
+ check_md = NID_ecdsa_with_SHA384;
+ else
+ return 0; /* Should never happen */
+ for (i = 0; i < c->shared_sigalgslen; i++)
+ if (check_md == c->shared_sigalgs[i].signandhash_nid)
+ break;
+ if (i == c->shared_sigalgslen)
+ return 0;
+ if (set_ee_md == 2) {
+ if (check_md == NID_ecdsa_with_SHA256)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha256();
+ else
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha384();
+ }
+ }
+ 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)
+{
+ unsigned char curve_id[2];
+ EC_KEY *ec = s->cert->ecdh_tmp;
+# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ /* Allow any curve: not just those peer supports */
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+ return 1;
+# endif
+ /*
+ * If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384, no other
+ * curves permitted.
+ */
+ if (tls1_suiteb(s)) {
+ /* Curve to check determined by ciphersuite */
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+ curve_id[1] = TLSEXT_curve_P_256;
+ else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+ curve_id[1] = TLSEXT_curve_P_384;
+ else
+ return 0;
+ curve_id[0] = 0;
+ /* Check this curve is acceptable */
+ if (!tls1_check_ec_key(s, curve_id, NULL))
+ return 0;
+ /* If auto or setting curve from callback assume OK */
+ if (s->cert->ecdh_tmp_auto || s->cert->ecdh_tmp_cb)
+ return 1;
+ /* Otherwise check curve is acceptable */
+ else {
+ unsigned char curve_tmp[2];
+ if (!ec)
+ return 0;
+ if (!tls1_set_ec_id(curve_tmp, NULL, ec))
+ return 0;
+ if (!curve_tmp[0] || curve_tmp[1] == curve_id[1])
+ return 1;
+ return 0;
+ }
+
+ }
+ if (s->cert->ecdh_tmp_auto) {
+ /* Need a shared curve */
+ if (tls1_shared_curve(s, 0))
+ return 1;
+ else
+ return 0;
+ }
+ if (!ec) {
+ if (s->cert->ecdh_tmp_cb)
+ return 1;
+ else
+ return 0;
+ }
+ if (!tls1_set_ec_id(curve_id, NULL, ec))
+ return 0;
+/* Set this to allow use of invalid curves for testing */
+# if 0
+ return 1;
+# else
+ 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_TLSEXT
@@ -357,20 +1026,231 @@ static unsigned char tls12_sigalgs[] = {
# endif
};
-int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
+# 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)
{
- size_t slen = sizeof(tls12_sigalgs);
- if (p)
- memcpy(p, tls12_sigalgs, slen);
- return (int)slen;
+ /*
+ * 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;
+ return sizeof(suiteb_sigalgs);
+
+ case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+ *psigs = suiteb_sigalgs;
+ return 2;
+
+ case SSL_CERT_FLAG_SUITEB_192_LOS:
+ *psigs = suiteb_sigalgs + 2;
+ return 2;
+ }
+# endif
+ /* If server use client authentication sigalgs if not NULL */
+ if (s->server && s->cert->client_sigalgs) {
+ *psigs = s->cert->client_sigalgs;
+ return s->cert->client_sigalgslen;
+ } else if (s->cert->conf_sigalgs) {
+ *psigs = s->cert->conf_sigalgs;
+ return s->cert->conf_sigalgslen;
+ } else {
+ *psigs = tls12_sigalgs;
+ return sizeof(tls12_sigalgs);
+ }
+}
+
+/*
+ * Check signature algorithm is consistent with sent supported signature
+ * algorithms and if so return relevant digest.
+ */
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+ const unsigned char *sig, EVP_PKEY *pkey)
+{
+ const unsigned char *sent_sigs;
+ size_t sent_sigslen, i;
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ return -1;
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)sig[1]) {
+ 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;
+ /* Check compression and curve matches extensions */
+ if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec))
+ return 0;
+ if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id)) {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
+ return 0;
+ }
+ /* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
+ if (tls1_suiteb(s)) {
+ if (curve_id[0])
+ return 0;
+ if (curve_id[1] == TLSEXT_curve_P_256) {
+ if (sig[0] != TLSEXT_hash_sha256) {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+ SSL_R_ILLEGAL_SUITEB_DIGEST);
+ return 0;
+ }
+ } else if (curve_id[1] == TLSEXT_curve_P_384) {
+ if (sig[0] != TLSEXT_hash_sha384) {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+ SSL_R_ILLEGAL_SUITEB_DIGEST);
+ return 0;
+ }
+ } else
+ return 0;
+ }
+ } else if (tls1_suiteb(s))
+ return 0;
+# endif
+
+ /* Check signature matches a type we sent */
+ sent_sigslen = tls12_get_psigalgs(s, &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;
+ }
+ /* Allow fallback to SHA1 if not strict mode */
+ if (i == sent_sigslen
+ && (sig[0] != TLSEXT_hash_sha1
+ || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+ *pmd = tls12_get_hash(sig[0]);
+ if (*pmd == NULL) {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_UNKNOWN_DIGEST);
+ return 0;
+ }
+ /*
+ * Store the digest used so applications can retrieve it if they wish.
+ */
+ if (s->session && s->session->sess_cert)
+ s->session->sess_cert->peer_key->digest = *pmd;
+ return 1;
+}
+
+/*
+ * 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.
+ */
+void ssl_set_client_disabled(SSL *s)
+{
+ CERT *c = s->cert;
+ const unsigned char *sigalgs;
+ size_t i, sigalgslen;
+ int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
+ c->mask_a = 0;
+ c->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))
+ c->mask_ssl = SSL_TLSV1_2;
+ else
+ c->mask_ssl = 0;
+ /*
+ * 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);
+ for (i = 0; i < sigalgslen; i += 2, sigalgs += 2) {
+ switch (sigalgs[1]) {
+# ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ have_rsa = 1;
+ break;
+# endif
+# ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ have_dsa = 1;
+ break;
+# endif
+# ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ have_ecdsa = 1;
+ break;
+# endif
+ }
+ }
+ /*
+ * Disable auth and static DH if we don't include any appropriate
+ * signature algorithms.
+ */
+ if (!have_rsa) {
+ c->mask_a |= SSL_aRSA;
+ c->mask_k |= SSL_kDHr | SSL_kECDHr;
+ }
+ if (!have_dsa) {
+ c->mask_a |= SSL_aDSS;
+ c->mask_k |= SSL_kDHd;
+ }
+ if (!have_ecdsa) {
+ c->mask_a |= SSL_aECDSA;
+ c->mask_k |= SSL_kECDHe;
+ }
+# ifndef OPENSSL_NO_KRB5
+ if (!kssl_tgt_is_available(s->kssl_ctx)) {
+ c->mask_a |= SSL_aKRB5;
+ c->mask_k |= SSL_kKRB5;
+ }
+# endif
+# ifndef OPENSSL_NO_PSK
+ /* with PSK there must be client callback set */
+ if (!s->psk_client_callback) {
+ c->mask_a |= SSL_aPSK;
+ 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;
}
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
- unsigned char *limit)
+ unsigned char *limit, int *al)
{
int extdatalen = 0;
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 >= TLS1_VERSION || SSL_IS_DTLS(s)) {
+ int i;
+ unsigned long alg_k, alg_a;
+ STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+ for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
+ SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+ alg_k = c->algorithm_mkey;
+ alg_a = c->algorithm_auth;
+ if ((alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)
+ || (alg_a & SSL_aECDSA))) {
+ using_ecc = 1;
+ break;
+ }
+ }
+ }
+# endif
/* don't add extensions for SSLv3 unless doing secure renegotiation */
if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding)
@@ -466,50 +1346,53 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
# endif
# ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist != NULL) {
+ if (using_ecc) {
/*
* 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 (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax)
+ if (num_formats > (size_t)lenmax)
return NULL;
- if (s->tlsext_ecpointformatlist_length > 255) {
+ 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(s->tlsext_ecpointformatlist_length + 1, ret);
- *(ret++) = (unsigned char)s->tlsext_ecpointformatlist_length;
- memcpy(ret, s->tlsext_ecpointformatlist,
- s->tlsext_ecpointformatlist_length);
- ret += s->tlsext_ecpointformatlist_length;
- }
- if (s->tlsext_ellipticcurvelist != NULL) {
+ /* 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
*/
- long lenmax;
+ pcurves = s->tlsext_ellipticcurvelist;
+ if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves))
+ return NULL;
if ((lenmax = limit - ret - 6) < 0)
return NULL;
- if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax)
+ if (num_curves > (size_t)lenmax / 2)
return NULL;
- if (s->tlsext_ellipticcurvelist_length > 65532) {
+ 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(s->tlsext_ellipticcurvelist_length + 2, ret);
-
- s2n(s->tlsext_ellipticcurvelist_length, ret);
- memcpy(ret, s->tlsext_ellipticcurvelist,
- s->tlsext_ellipticcurvelist_length);
- ret += s->tlsext_ellipticcurvelist_length;
+ 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 */
@@ -546,17 +1429,20 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
}
skip_ext:
- if (TLS1_get_client_version(s) >= TLS1_2_VERSION) {
- if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
+ if (SSL_USE_SIGALGS(s)) {
+ size_t salglen;
+ const unsigned char *salg;
+ salglen = tls12_get_psigalgs(s, &salg);
+ if ((size_t)(limit - ret) < salglen + 6)
return NULL;
s2n(TLSEXT_TYPE_signature_algorithms, ret);
- s2n(sizeof(tls12_sigalgs) + 2, ret);
- s2n(sizeof(tls12_sigalgs), ret);
- memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
- ret += sizeof(tls12_sigalgs);
+ s2n(salglen + 2, ret);
+ s2n(salglen, ret);
+ memcpy(ret, salg, salglen);
+ ret += salglen;
}
# 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;
if ((long)(limit - ret - 6 - col < 0))
@@ -572,8 +1458,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
}
# 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;
OCSP_RESPID *id;
@@ -646,6 +1531,15 @@ 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)
+ 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;
+ }
# ifndef OPENSSL_NO_SRTP
if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) {
int el;
@@ -665,6 +1559,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
ret += el;
}
# endif
+ 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 padding to workaround bugs in F5 terminators. See
* https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
@@ -702,7 +1601,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
}
unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
- unsigned char *limit)
+ unsigned char *limit, int *al)
{
int extdatalen = 0;
unsigned char *orig = buf;
@@ -710,7 +1609,13 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *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
*/
@@ -752,27 +1657,30 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
ret += el;
}
# ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist != NULL) {
+ if (using_ecc) {
+ const unsigned char *plist;
+ size_t plistlen;
/*
* 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 (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax)
+ if (plistlen > (size_t)lenmax)
return NULL;
- if (s->tlsext_ecpointformatlist_length > 255) {
+ if (plistlen > 255) {
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
s2n(TLSEXT_TYPE_ec_point_formats, ret);
- s2n(s->tlsext_ecpointformatlist_length + 1, ret);
- *(ret++) = (unsigned char)s->tlsext_ecpointformatlist_length;
- memcpy(ret, s->tlsext_ecpointformatlist,
- s->tlsext_ecpointformatlist_length);
- ret += s->tlsext_ecpointformatlist_length;
+ s2n(plistlen + 1, ret);
+ *(ret++) = (unsigned char)plistlen;
+ memcpy(ret, plist, plistlen);
+ ret += plistlen;
}
/*
@@ -795,7 +1703,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
s2n(0, ret);
}
# 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;
if ((long)(limit - ret - 6 - sol) < 0)
@@ -890,6 +1798,22 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
}
}
# endif
+ if (!custom_ext_add(s, 1, &ret, limit, al))
+ return NULL;
+
+ if (s->s3->alpn_selected) {
+ const unsigned char *selected = s->s3->alpn_selected;
+ unsigned len = s->s3->alpn_selected_len;
+
+ 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 - orig - 2) == 0)
return orig;
@@ -981,15 +1905,82 @@ static void ssl_check_for_safari(SSL *s, const unsigned char *data,
}
# endif /* !OPENSSL_NO_EC */
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
- unsigned char *limit, int *al)
+/*
+ * 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 *limit, int *al)
{
unsigned short type;
unsigned short size;
unsigned short len;
unsigned char *data = *p;
int renegotiate_seen = 0;
- int sigalg_seen = 0;
s->servername_done = 0;
s->tlsext_status_type = -1;
@@ -997,6 +1988,10 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
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);
@@ -1007,6 +2002,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
ssl_check_for_safari(s, data, limit);
# 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;
+ }
# ifndef OPENSSL_NO_SRP
if (s->srp_ctx.login != NULL) {
OPENSSL_free(s->srp_ctx.login);
@@ -1149,7 +2149,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
- if (ecpointformatlist_length != size - 1)
+ if (ecpointformatlist_length != size - 1 ||
+ ecpointformatlist_length < 1)
goto err;
if (!s->hit) {
if (s->session->tlsext_ecpointformatlist) {
@@ -1214,8 +2215,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
}
# 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;
if (size < 2) {
@@ -1259,17 +2259,15 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
renegotiate_seen = 1;
} else if (type == TLSEXT_TYPE_signature_algorithms) {
int dsize;
- if (sigalg_seen || size < 2)
+ if (s->cert->peer_sigalgs || size < 2)
goto err;
- sigalg_seen = 1;
n2s(data, dsize);
size -= 2;
- if (dsize != size || dsize & 1)
+ if (dsize != size || dsize & 1 || !dsize)
goto err;
- if (!tls1_process_sigalgs(s, data, dsize))
+ if (!tls1_save_sigalgs(s, data, dsize))
goto err;
- } else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION) {
+ } else if (type == TLSEXT_TYPE_status_request) {
if (size < 5)
goto err;
@@ -1361,7 +2359,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
# 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.
@@ -1383,6 +2382,16 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
}
# 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 */
# ifndef OPENSSL_NO_SRTP
else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
@@ -1408,7 +2417,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
if (!renegotiate_seen && s->renegotiate &&
!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
*al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+ SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
@@ -1419,6 +2428,73 @@ err:
return 0;
}
+/*
+ * 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 *limit)
+{
+ 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, limit, &al) <= 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
+ }
+
+ if (ssl_check_clienthello_tlsext_early(s) <= 0) {
+ 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, limit, &al) <= 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
+ }
+
+ return 1;
+}
+
# ifndef OPENSSL_NO_NEXTPROTONEG
/*
* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
@@ -1440,8 +2516,8 @@ static char ssl_next_proto_validate(unsigned char *d, unsigned len)
}
# endif
-int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
- int n, int *al)
+static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p,
+ unsigned char *d, int n, int *al)
{
unsigned short length;
unsigned short type;
@@ -1455,6 +2531,10 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
# 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 |
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
@@ -1491,8 +2571,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
- if (ecpointformatlist_length != size - 1 ||
- ecpointformatlist_length < 1) {
+ if (ecpointformatlist_length != size - 1) {
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
@@ -1537,8 +2616,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
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;
if (size < 2) {
@@ -1569,8 +2647,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
}
}
# 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.
@@ -1616,6 +2693,48 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
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))
return 0;
@@ -1643,6 +2762,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
return 0;
}
# endif
+ /*
+ * 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;
data += size;
}
@@ -1682,7 +2807,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
&& !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
*al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+ SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
@@ -1692,63 +2817,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
int ssl_prepare_clienthello_tlsext(SSL *s)
{
-# ifndef OPENSSL_NO_EC
- /*
- * If we are client and using an elliptic curve cryptography cipher
- * suite, send the point formats and elliptic curves we support.
- */
- int using_ecc = 0;
- int i;
- unsigned char *j;
- unsigned long alg_k, alg_a;
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
- for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
- alg_k = c->algorithm_mkey;
- alg_a = c->algorithm_auth;
- if ((alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)
- || (alg_a & SSL_aECDSA))) {
- using_ecc = 1;
- break;
- }
- }
- using_ecc = using_ecc && (s->version >= TLS1_VERSION);
- if (using_ecc) {
- if (s->tlsext_ecpointformatlist != NULL)
- OPENSSL_free(s->tlsext_ecpointformatlist);
- if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) {
- SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,
- ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->tlsext_ecpointformatlist_length = 3;
- s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
- s->tlsext_ecpointformatlist[1] =
- TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
- s->tlsext_ecpointformatlist[2] =
- TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
-
- /* we support all named elliptic curves in RFC 4492 */
- if (s->tlsext_ellipticcurvelist != NULL)
- OPENSSL_free(s->tlsext_ellipticcurvelist);
- s->tlsext_ellipticcurvelist_length =
- sizeof(pref_list) / sizeof(pref_list[0]) * 2;
- if ((s->tlsext_ellipticcurvelist =
- OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) {
- s->tlsext_ellipticcurvelist_length = 0;
- SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,
- ERR_R_MALLOC_FAILURE);
- return -1;
- }
- for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i <
- sizeof(pref_list) / sizeof(pref_list[0]); i++) {
- int id = tls1_ec_nid2curve_id(pref_list[i]);
- s2n(id, j);
- }
- }
-# endif /* OPENSSL_NO_EC */
# ifdef TLSEXT_TYPE_opaque_prf_input
{
@@ -1800,40 +2868,10 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
int ssl_prepare_serverhello_tlsext(SSL *s)
{
-# ifndef OPENSSL_NO_EC
- /*
- * If we are server and using an ECC cipher suite, send the point formats
- * we support if the client sent us an ECPointsFormat extension. Note
- * that the server is not supposed to send an EllipticCurves extension.
- */
-
- 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);
-
- if (using_ecc) {
- if (s->tlsext_ecpointformatlist != NULL)
- OPENSSL_free(s->tlsext_ecpointformatlist);
- if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) {
- SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,
- ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->tlsext_ecpointformatlist_length = 3;
- s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
- s->tlsext_ecpointformatlist[1] =
- TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
- s->tlsext_ecpointformatlist[2] =
- TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
- }
-# endif /* OPENSSL_NO_EC */
-
return 1;
}
-int ssl_check_clienthello_tlsext_early(SSL *s)
+static int ssl_check_clienthello_tlsext_early(SSL *s)
{
int ret = SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -1943,6 +2981,44 @@ int ssl_check_clienthello_tlsext_early(SSL *s)
}
}
+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;
+ s->cert->shared_sigalgslen = 0;
+ }
+ /* 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;
@@ -1950,9 +3026,9 @@ int ssl_check_clienthello_tlsext_late(SSL *s)
/*
* If status request then ask callback what to do. Note: this must be
- * called after servername callbacks in case the certificate has
- * changed, and must be called after the cipher has been chosen because
- * this may influence which certificate is sent
+ * called after servername callbacks in case the certificate has changed,
+ * and must be called after the cipher has been chosen because this may
+ * influence which certificate is sent
*/
if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) {
int r;
@@ -2122,6 +3198,24 @@ int ssl_check_serverhello_tlsext(SSL *s)
}
}
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
+ int n)
+{
+ int al = -1;
+ if (s->version < SSL3_VERSION)
+ return 1;
+ if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
+ }
+
+ if (ssl_check_serverhello_tlsext(s) <= 0) {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_SERVERHELLO_TLSEXT);
+ return 0;
+ }
+ return 1;
+}
+
/*-
* Since the server cache lookup is done early on in the processing of the
* ClientHello, and other operations depend on the result, we need to handle
@@ -2177,7 +3271,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
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;
if (p >= limit)
@@ -2371,32 +3465,18 @@ typedef struct {
} tls12_lookup;
static tls12_lookup tls12_md[] = {
-# ifndef OPENSSL_NO_MD5
{NID_md5, TLSEXT_hash_md5},
-# endif
-# ifndef OPENSSL_NO_SHA
{NID_sha1, TLSEXT_hash_sha1},
-# endif
-# ifndef OPENSSL_NO_SHA256
{NID_sha224, TLSEXT_hash_sha224},
{NID_sha256, TLSEXT_hash_sha256},
-# endif
-# ifndef OPENSSL_NO_SHA512
{NID_sha384, TLSEXT_hash_sha384},
{NID_sha512, TLSEXT_hash_sha512}
-# endif
};
static tls12_lookup tls12_sig[] = {
-# ifndef OPENSSL_NO_RSA
{EVP_PKEY_RSA, TLSEXT_signature_rsa},
-# endif
-# ifndef OPENSSL_NO_DSA
{EVP_PKEY_DSA, TLSEXT_signature_dsa},
-# endif
-# ifndef OPENSSL_NO_ECDSA
{EVP_PKEY_EC, TLSEXT_signature_ecdsa}
-# endif
};
static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
@@ -2409,17 +3489,15 @@ static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
return -1;
}
-# if 0
static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
{
size_t i;
for (i = 0; i < tlen; i++) {
- if (table[i].id == id)
+ if ((table[i].id) == id)
return table[i].nid;
}
- return -1;
+ return NID_undef;
}
-# endif
int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
const EVP_MD *md)
@@ -2448,6 +3526,14 @@ int tls12_get_sigid(const EVP_PKEY *pk)
const EVP_MD *tls12_get_hash(unsigned char hash_alg)
{
switch (hash_alg) {
+# ifndef OPENSSL_NO_MD5
+ case TLSEXT_hash_md5:
+# ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ return NULL;
+# endif
+ return EVP_md5();
+# endif
# ifndef OPENSSL_NO_SHA
case TLSEXT_hash_sha1:
return EVP_sha1();
@@ -2472,83 +3558,274 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg)
}
}
+static int tls12_get_pkey_idx(unsigned char sig_alg)
+{
+ switch (sig_alg) {
+# ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ return SSL_PKEY_RSA_SIGN;
+# endif
+# ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ return SSL_PKEY_DSA_SIGN;
+# endif
+# ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ return SSL_PKEY_ECC;
+# endif
+ }
+ return -1;
+}
+
+/* Convert TLS 1.2 signature algorithm extension values into NIDs */
+static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
+ int *psignhash_nid, const unsigned char *data)
+{
+ int sign_nid = NID_undef, hash_nid = NID_undef;
+ if (!phash_nid && !psign_nid && !psignhash_nid)
+ return;
+ if (phash_nid || psignhash_nid) {
+ hash_nid = tls12_find_nid(data[0], tls12_md,
+ sizeof(tls12_md) / sizeof(tls12_lookup));
+ if (phash_nid)
+ *phash_nid = hash_nid;
+ }
+ if (psign_nid || psignhash_nid) {
+ sign_nid = tls12_find_nid(data[1], tls12_sig,
+ sizeof(tls12_sig) / sizeof(tls12_lookup));
+ if (psign_nid)
+ *psign_nid = sign_nid;
+ }
+ if (psignhash_nid) {
+ if (sign_nid == NID_undef || hash_nid == NID_undef
+ || OBJ_find_sigid_by_algs(psignhash_nid, hash_nid,
+ sign_nid) <= 0)
+ *psignhash_nid = NID_undef;
+ }
+}
+
+/* Given preference and allowed sigalgs set shared sigalgs */
+static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
+ const unsigned char *pref, size_t preflen,
+ const unsigned char *allow,
+ size_t allowlen)
+{
+ const unsigned char *ptmp, *atmp;
+ size_t i, j, nmatch = 0;
+ for (i = 0, ptmp = pref; i < preflen; i += 2, ptmp += 2) {
+ /* Skip disabled hashes or signature algorithms */
+ if (tls12_get_hash(ptmp[0]) == NULL)
+ continue;
+ if (tls12_get_pkey_idx(ptmp[1]) == -1)
+ continue;
+ for (j = 0, atmp = allow; j < allowlen; j += 2, atmp += 2) {
+ if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1]) {
+ nmatch++;
+ if (shsig) {
+ shsig->rhash = ptmp[0];
+ shsig->rsign = ptmp[1];
+ tls1_lookup_sigalg(&shsig->hash_nid,
+ &shsig->sign_nid,
+ &shsig->signandhash_nid, ptmp);
+ shsig++;
+ }
+ break;
+ }
+ }
+ }
+ return nmatch;
+}
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+{
+ const unsigned char *pref, *allow, *conf;
+ size_t preflen, allowlen, conflen;
+ size_t nmatch;
+ 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;
+ c->shared_sigalgslen = 0;
+ }
+ /* If client use client signature algorithms if not NULL */
+ if (!s->server && c->client_sigalgs && !is_suiteb) {
+ conf = c->client_sigalgs;
+ conflen = c->client_sigalgslen;
+ } else if (c->conf_sigalgs && !is_suiteb) {
+ conf = c->conf_sigalgs;
+ conflen = c->conf_sigalgslen;
+ } else
+ conflen = tls12_get_psigalgs(s, &conf);
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb) {
+ pref = conf;
+ preflen = conflen;
+ allow = c->peer_sigalgs;
+ allowlen = c->peer_sigalgslen;
+ } else {
+ allow = conf;
+ allowlen = conflen;
+ pref = c->peer_sigalgs;
+ preflen = c->peer_sigalgslen;
+ }
+ nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
+ if (nmatch) {
+ salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+ if (!salgs)
+ return 0;
+ nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
+ } else {
+ salgs = NULL;
+ }
+ c->shared_sigalgs = salgs;
+ c->shared_sigalgslen = nmatch;
+ return 1;
+}
+
/* 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 i, idx;
- const EVP_MD *md;
CERT *c = s->cert;
- /* 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;
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
- c->pkeys[SSL_PKEY_ECC].digest = NULL;
+ 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;
+}
- for (i = 0; i < dsize; i += 2) {
- unsigned char hash_alg = data[i], sig_alg = data[i + 1];
+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;
- switch (sig_alg) {
-# ifndef OPENSSL_NO_RSA
- case TLSEXT_signature_rsa:
- idx = SSL_PKEY_RSA_SIGN;
- break;
-# endif
-# ifndef OPENSSL_NO_DSA
- case TLSEXT_signature_dsa:
- idx = SSL_PKEY_DSA_SIGN;
- break;
-# endif
-# ifndef OPENSSL_NO_ECDSA
- case TLSEXT_signature_ecdsa:
- idx = SSL_PKEY_ECC;
- break;
-# endif
- default:
- continue;
+# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) {
+ /*
+ * Use first set signature preference to force message digest,
+ * ignoring any peer preferences.
+ */
+ const unsigned char *sigs = NULL;
+ if (s->server)
+ sigs = c->conf_sigalgs;
+ else
+ sigs = c->client_sigalgs;
+ if (sigs) {
+ idx = tls12_get_pkey_idx(sigs[1]);
+ md = tls12_get_hash(sigs[0]);
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN) {
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags =
+ CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
}
+ }
+# endif
- if (c->pkeys[idx].digest == NULL) {
- md = tls12_get_hash(hash_alg);
- if (md) {
- c->pkeys[idx].digest = md;
- if (idx == SSL_PKEY_RSA_SIGN)
- c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ for (i = 0, sigptr = c->shared_sigalgs;
+ i < c->shared_sigalgslen; i++, sigptr++) {
+ idx = tls12_get_pkey_idx(sigptr->rsign);
+ if (idx > 0 && c->pkeys[idx].digest == NULL) {
+ md = tls12_get_hash(sigptr->rhash);
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN) {
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags =
+ CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
}
}
}
-
/*
- * Set any remaining keys to default values. NOTE: if alg is not
- * supported it stays as NULL.
+ * In strict mode leave unset digests as NULL to indicate we can't use
+ * the certificate for signing.
*/
+ if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) {
+ /*
+ * Set any remaining keys to default values. NOTE: if alg is not
+ * supported it stays as NULL.
+ */
# ifndef OPENSSL_NO_DSA
- if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+ if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
+ c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
# endif
# ifndef OPENSSL_NO_RSA
- if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest) {
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
- c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
- }
+ if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest) {
+ c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+ }
# endif
# ifndef OPENSSL_NO_ECDSA
- if (!c->pkeys[SSL_PKEY_ECC].digest)
- c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+ if (!c->pkeys[SSL_PKEY_ECC].digest)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
# endif
+ }
return 1;
}
-#endif
+int SSL_get_sigalgs(SSL *s, int idx,
+ int *psign, int *phash, int *psignhash,
+ unsigned char *rsig, unsigned char *rhash)
+{
+ const unsigned char *psig = s->cert->peer_sigalgs;
+ if (psig == NULL)
+ return 0;
+ if (idx >= 0) {
+ idx <<= 1;
+ if (idx >= (int)s->cert->peer_sigalgslen)
+ return 0;
+ psig += idx;
+ if (rhash)
+ *rhash = psig[0];
+ if (rsig)
+ *rsig = psig[1];
+ tls1_lookup_sigalg(phash, psign, psignhash, psig);
+ }
+ return s->cert->peer_sigalgslen / 2;
+}
-#ifndef OPENSSL_NO_HEARTBEATS
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+ int *psign, int *phash, int *psignhash,
+ unsigned char *rsig, unsigned char *rhash)
+{
+ TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
+ if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen)
+ return 0;
+ shsigalgs += idx;
+ if (phash)
+ *phash = shsigalgs->hash_nid;
+ if (psign)
+ *psign = shsigalgs->sign_nid;
+ if (psignhash)
+ *psignhash = shsigalgs->signandhash_nid;
+ if (rsig)
+ *rsig = shsigalgs->rsign;
+ if (rhash)
+ *rhash = shsigalgs->rhash;
+ return s->cert->shared_sigalgslen;
+}
+
+# ifndef OPENSSL_NO_HEARTBEATS
int tls1_process_heartbeat(SSL *s)
{
unsigned char *p = &s->s3->rrec.data[0], *pl;
@@ -2699,4 +3976,426 @@ err:
return ret;
}
+# endif
+
+# define MAX_SIGALGLEN (TLSEXT_hash_num * TLSEXT_signature_num * 2)
+
+typedef struct {
+ size_t sigalgcnt;
+ int sigalgs[MAX_SIGALGLEN];
+} sig_cb_st;
+
+static int sig_cb(const char *elem, int len, void *arg)
+{
+ sig_cb_st *sarg = arg;
+ size_t i;
+ char etmp[20], *p;
+ int sig_alg, hash_alg;
+ if (elem == NULL)
+ return 0;
+ if (sarg->sigalgcnt == MAX_SIGALGLEN)
+ return 0;
+ if (len > (int)(sizeof(etmp) - 1))
+ return 0;
+ memcpy(etmp, elem, len);
+ etmp[len] = 0;
+ p = strchr(etmp, '+');
+ if (!p)
+ return 0;
+ *p = 0;
+ p++;
+ if (!*p)
+ return 0;
+
+ if (!strcmp(etmp, "RSA"))
+ sig_alg = EVP_PKEY_RSA;
+ else if (!strcmp(etmp, "DSA"))
+ sig_alg = EVP_PKEY_DSA;
+ else if (!strcmp(etmp, "ECDSA"))
+ sig_alg = EVP_PKEY_EC;
+ else
+ return 0;
+
+ hash_alg = OBJ_sn2nid(p);
+ if (hash_alg == NID_undef)
+ hash_alg = OBJ_ln2nid(p);
+ if (hash_alg == NID_undef)
+ return 0;
+
+ for (i = 0; i < sarg->sigalgcnt; i += 2) {
+ if (sarg->sigalgs[i] == sig_alg && sarg->sigalgs[i + 1] == hash_alg)
+ return 0;
+ }
+ sarg->sigalgs[sarg->sigalgcnt++] = hash_alg;
+ sarg->sigalgs[sarg->sigalgcnt++] = sig_alg;
+ return 1;
+}
+
+/*
+ * Set suppored signature algorithms based on a colon separated list of the
+ * form sig+hash e.g. RSA+SHA512:DSA+SHA512
+ */
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
+{
+ sig_cb_st sig;
+ sig.sigalgcnt = 0;
+ if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+ return 0;
+ if (c == NULL)
+ return 1;
+ return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
+}
+
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen,
+ int client)
+{
+ unsigned char *sigalgs, *sptr;
+ int rhash, rsign;
+ size_t i;
+ if (salglen & 1)
+ return 0;
+ sigalgs = OPENSSL_malloc(salglen);
+ if (sigalgs == NULL)
+ return 0;
+ for (i = 0, sptr = sigalgs; i < salglen; i += 2) {
+ rhash = tls12_find_id(*psig_nids++, tls12_md,
+ sizeof(tls12_md) / sizeof(tls12_lookup));
+ rsign = tls12_find_id(*psig_nids++, tls12_sig,
+ sizeof(tls12_sig) / sizeof(tls12_lookup));
+
+ if (rhash == -1 || rsign == -1)
+ goto err;
+ *sptr++ = rhash;
+ *sptr++ = rsign;
+ }
+
+ if (client) {
+ if (c->client_sigalgs)
+ OPENSSL_free(c->client_sigalgs);
+ c->client_sigalgs = sigalgs;
+ c->client_sigalgslen = salglen;
+ } else {
+ if (c->conf_sigalgs)
+ OPENSSL_free(c->conf_sigalgs);
+ c->conf_sigalgs = sigalgs;
+ c->conf_sigalgslen = salglen;
+ }
+
+ return 1;
+
+ err:
+ OPENSSL_free(sigalgs);
+ return 0;
+}
+
+static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid)
+{
+ int sig_nid;
+ size_t i;
+ if (default_nid == -1)
+ return 1;
+ sig_nid = X509_get_signature_nid(x);
+ if (default_nid)
+ return sig_nid == default_nid ? 1 : 0;
+ for (i = 0; i < c->shared_sigalgslen; i++)
+ if (sig_nid == c->shared_sigalgs[i].signandhash_nid)
+ return 1;
+ return 0;
+}
+
+/* Check to see if a certificate issuer name matches list of CA names */
+static int ssl_check_ca_name(STACK_OF(X509_NAME) *names, X509 *x)
+{
+ X509_NAME *nm;
+ int i;
+ nm = X509_get_issuer_name(x);
+ for (i = 0; i < sk_X509_NAME_num(names); i++) {
+ if (!X509_NAME_cmp(nm, sk_X509_NAME_value(names, i)))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Check certificate chain is consistent with TLS extensions and is usable by
+ * server. This servers two purposes: it allows users to check chains before
+ * passing them to the server and it allows the server to check chains before
+ * attempting to use them.
+ */
+
+/* Flags which need to be set for a certificate when stict mode not set */
+
+# define CERT_PKEY_VALID_FLAGS \
+ (CERT_PKEY_EE_SIGNATURE|CERT_PKEY_EE_PARAM)
+/* Strict mode flags */
+# define CERT_PKEY_STRICT_FLAGS \
+ (CERT_PKEY_VALID_FLAGS|CERT_PKEY_CA_SIGNATURE|CERT_PKEY_CA_PARAM \
+ | CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE)
+
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+ int idx)
+{
+ int i;
+ int rv = 0;
+ int check_flags = 0, strict_mode;
+ CERT_PKEY *cpk = NULL;
+ CERT *c = s->cert;
+ unsigned int suiteb_flags = tls1_suiteb(s);
+ /* idx == -1 means checking server chains */
+ if (idx != -1) {
+ /* idx == -2 means checking client certificate chains */
+ if (idx == -2) {
+ cpk = c->key;
+ idx = cpk - c->pkeys;
+ } else
+ cpk = c->pkeys + idx;
+ x = cpk->x509;
+ pk = cpk->privatekey;
+ chain = cpk->chain;
+ strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
+ /* If no cert or key, forget it */
+ if (!x || !pk)
+ goto end;
+# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ /* Allow any certificate to pass test */
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) {
+ rv = CERT_PKEY_STRICT_FLAGS | CERT_PKEY_EXPLICIT_SIGN |
+ CERT_PKEY_VALID | CERT_PKEY_SIGN;
+ cpk->valid_flags = rv;
+ return rv;
+ }
+# endif
+ } else {
+ if (!x || !pk)
+ return 0;
+ idx = ssl_cert_type(x, pk);
+ if (idx == -1)
+ return 0;
+ cpk = c->pkeys + idx;
+ if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+ check_flags = CERT_PKEY_STRICT_FLAGS;
+ else
+ check_flags = CERT_PKEY_VALID_FLAGS;
+ strict_mode = 1;
+ }
+
+ if (suiteb_flags) {
+ int ok;
+ if (check_flags)
+ check_flags |= CERT_PKEY_SUITEB;
+ ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
+ if (ok == X509_V_OK)
+ rv |= CERT_PKEY_SUITEB;
+ else if (!check_flags)
+ goto end;
+ }
+
+ /*
+ * Check all signature algorithms are consistent with signature
+ * algorithms extension if TLS 1.2 or later and strict mode.
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION && strict_mode) {
+ int default_nid;
+ unsigned char rsign = 0;
+ if (c->peer_sigalgs)
+ default_nid = 0;
+ /* If no sigalgs extension use defaults from RFC5246 */
+ else {
+ switch (idx) {
+ case SSL_PKEY_RSA_ENC:
+ case SSL_PKEY_RSA_SIGN:
+ case SSL_PKEY_DH_RSA:
+ rsign = TLSEXT_signature_rsa;
+ default_nid = NID_sha1WithRSAEncryption;
+ break;
+
+ case SSL_PKEY_DSA_SIGN:
+ case SSL_PKEY_DH_DSA:
+ rsign = TLSEXT_signature_dsa;
+ default_nid = NID_dsaWithSHA1;
+ break;
+
+ case SSL_PKEY_ECC:
+ rsign = TLSEXT_signature_ecdsa;
+ default_nid = NID_ecdsa_with_SHA1;
+ break;
+
+ default:
+ default_nid = -1;
+ break;
+ }
+ }
+ /*
+ * If peer sent no signature algorithms extension and we have set
+ * preferred signature algorithms check we support sha1.
+ */
+ if (default_nid > 0 && c->conf_sigalgs) {
+ size_t j;
+ const unsigned char *p = c->conf_sigalgs;
+ for (j = 0; j < c->conf_sigalgslen; j += 2, p += 2) {
+ if (p[0] == TLSEXT_hash_sha1 && p[1] == rsign)
+ break;
+ }
+ if (j == c->conf_sigalgslen) {
+ if (check_flags)
+ goto skip_sigs;
+ else
+ goto end;
+ }
+ }
+ /* Check signature algorithm of each cert in chain */
+ if (!tls1_check_sig_alg(c, x, default_nid)) {
+ if (!check_flags)
+ goto end;
+ } else
+ rv |= CERT_PKEY_EE_SIGNATURE;
+ rv |= CERT_PKEY_CA_SIGNATURE;
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ if (!tls1_check_sig_alg(c, sk_X509_value(chain, i), default_nid)) {
+ if (check_flags) {
+ rv &= ~CERT_PKEY_CA_SIGNATURE;
+ break;
+ } else
+ goto end;
+ }
+ }
+ }
+ /* Else not TLS 1.2, so mark EE and CA signing algorithms OK */
+ else if (check_flags)
+ rv |= CERT_PKEY_EE_SIGNATURE | CERT_PKEY_CA_SIGNATURE;
+ skip_sigs:
+ /* Check cert parameters are consistent */
+ if (tls1_check_cert_param(s, x, check_flags ? 1 : 2))
+ rv |= CERT_PKEY_EE_PARAM;
+ else if (!check_flags)
+ goto end;
+ if (!s->server)
+ rv |= CERT_PKEY_CA_PARAM;
+ /* In strict mode check rest of chain too */
+ else if (strict_mode) {
+ rv |= CERT_PKEY_CA_PARAM;
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ X509 *ca = sk_X509_value(chain, i);
+ if (!tls1_check_cert_param(s, ca, 0)) {
+ if (check_flags) {
+ rv &= ~CERT_PKEY_CA_PARAM;
+ break;
+ } else
+ goto end;
+ }
+ }
+ }
+ if (!s->server && strict_mode) {
+ STACK_OF(X509_NAME) *ca_dn;
+ int check_type = 0;
+ switch (pk->type) {
+ case EVP_PKEY_RSA:
+ check_type = TLS_CT_RSA_SIGN;
+ break;
+ case EVP_PKEY_DSA:
+ check_type = TLS_CT_DSS_SIGN;
+ break;
+ case EVP_PKEY_EC:
+ check_type = TLS_CT_ECDSA_SIGN;
+ break;
+ case EVP_PKEY_DH:
+ case EVP_PKEY_DHX:
+ {
+ int cert_type = X509_certificate_type(x, pk);
+ if (cert_type & EVP_PKS_RSA)
+ check_type = TLS_CT_RSA_FIXED_DH;
+ if (cert_type & EVP_PKS_DSA)
+ check_type = TLS_CT_DSS_FIXED_DH;
+ }
+ }
+ if (check_type) {
+ const unsigned char *ctypes;
+ int ctypelen;
+ if (c->ctypes) {
+ ctypes = c->ctypes;
+ ctypelen = (int)c->ctype_num;
+ } else {
+ ctypes = (unsigned char *)s->s3->tmp.ctype;
+ ctypelen = s->s3->tmp.ctype_num;
+ }
+ for (i = 0; i < ctypelen; i++) {
+ if (ctypes[i] == check_type) {
+ rv |= CERT_PKEY_CERT_TYPE;
+ break;
+ }
+ }
+ if (!(rv & CERT_PKEY_CERT_TYPE) && !check_flags)
+ goto end;
+ } else
+ rv |= CERT_PKEY_CERT_TYPE;
+
+ ca_dn = s->s3->tmp.ca_names;
+
+ if (!sk_X509_NAME_num(ca_dn))
+ rv |= CERT_PKEY_ISSUER_NAME;
+
+ if (!(rv & CERT_PKEY_ISSUER_NAME)) {
+ if (ssl_check_ca_name(ca_dn, x))
+ rv |= CERT_PKEY_ISSUER_NAME;
+ }
+ if (!(rv & CERT_PKEY_ISSUER_NAME)) {
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ X509 *xtmp = sk_X509_value(chain, i);
+ if (ssl_check_ca_name(ca_dn, xtmp)) {
+ rv |= CERT_PKEY_ISSUER_NAME;
+ break;
+ }
+ }
+ }
+ if (!check_flags && !(rv & CERT_PKEY_ISSUER_NAME))
+ goto end;
+ } else
+ rv |= CERT_PKEY_ISSUER_NAME | CERT_PKEY_CERT_TYPE;
+
+ if (!check_flags || (rv & check_flags) == check_flags)
+ rv |= CERT_PKEY_VALID;
+
+ end:
+
+ if (TLS1_get_version(s) >= TLS1_2_VERSION) {
+ if (cpk->valid_flags & CERT_PKEY_EXPLICIT_SIGN)
+ rv |= CERT_PKEY_EXPLICIT_SIGN | CERT_PKEY_SIGN;
+ else if (cpk->digest)
+ rv |= CERT_PKEY_SIGN;
+ } else
+ rv |= CERT_PKEY_SIGN | CERT_PKEY_EXPLICIT_SIGN;
+
+ /*
+ * When checking a CERT_PKEY structure all flags are irrelevant if the
+ * chain is invalid.
+ */
+ if (!check_flags) {
+ if (rv & CERT_PKEY_VALID)
+ cpk->valid_flags = rv;
+ else {
+ /* Preserve explicit sign flag, clear rest */
+ cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;
+ return 0;
+ }
+ }
+ return rv;
+}
+
+/* Set validity of certificates in an SSL structure */
+void tls1_set_cert_validity(SSL *s)
+{
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_ENC);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_SIGN);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_RSA);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_DSA);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
+}
+
+/* User level utiity function to check a chain is suitable */
+int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+{
+ return tls1_check_chain(s, x, pk, chain, -1);
+}
+
#endif