blob: ec4137f774d5134105d0fb24011ee6d9392ddd8f [file] [log] [blame]
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <stdio.h>
#include <assert.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
#include "ssl_locl.h"
#ifndef OPENSSL_NO_TLSEXT
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={
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,
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)
{
/* 2 hours, the 24 hours mentioned in the TLSv1 spec
* is way too long for http, the cache would over fill */
return(60*60*2);
}
int tls1_new(SSL *s)
{
if (!ssl3_new(s)) return(0);
s->method->ssl_clear(s);
return(1);
}
void tls1_free(SSL *s)
{
#ifndef OPENSSL_NO_TLSEXT
if (s->tlsext_session_ticket)
{
OPENSSL_free(s->tlsext_session_ticket);
}
#endif /* OPENSSL_NO_TLSEXT */
ssl3_free(s);
}
void tls1_clear(SSL *s)
{
ssl3_clear(s);
s->version = s->method->version;
}
#ifndef OPENSSL_NO_EC
static int nid_list[] =
{
NID_sect163k1, /* sect163k1 (1) */
NID_sect163r1, /* sect163r1 (2) */
NID_sect163r2, /* sect163r2 (3) */
NID_sect193r1, /* sect193r1 (4) */
NID_sect193r2, /* sect193r2 (5) */
NID_sect233k1, /* sect233k1 (6) */
NID_sect233r1, /* sect233r1 (7) */
NID_sect239k1, /* sect239k1 (8) */
NID_sect283k1, /* sect283k1 (9) */
NID_sect283r1, /* sect283r1 (10) */
NID_sect409k1, /* sect409k1 (11) */
NID_sect409r1, /* sect409r1 (12) */
NID_sect571k1, /* sect571k1 (13) */
NID_sect571r1, /* sect571r1 (14) */
NID_secp160k1, /* secp160k1 (15) */
NID_secp160r1, /* secp160r1 (16) */
NID_secp160r2, /* secp160r2 (17) */
NID_secp192k1, /* secp192k1 (18) */
NID_X9_62_prime192v1, /* secp192r1 (19) */
NID_secp224k1, /* secp224k1 (20) */
NID_secp224r1, /* secp224r1 (21) */
NID_secp256k1, /* secp256k1 (22) */
NID_X9_62_prime256v1, /* secp256r1 (23) */
NID_secp384r1, /* secp384r1 (24) */
NID_secp521r1, /* secp521r1 (25) */
NID_brainpoolP256r1, /* brainpoolP256r1 (26) */
NID_brainpoolP384r1, /* brainpoolP384r1 (27) */
NID_brainpoolP512r1 /* brainpool512r1 (28) */
};
static const unsigned char ecformats_default[] =
{
TLSEXT_ECPOINTFORMAT_uncompressed,
TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
};
static const unsigned char eccurves_default[] =
{
0,14, /* sect571r1 (14) */
0,13, /* sect571k1 (13) */
0,25, /* secp521r1 (25) */
0,28, /* brainpool512r1 (28) */
0,11, /* sect409k1 (11) */
0,12, /* sect409r1 (12) */
0,27, /* brainpoolP384r1 (27) */
0,24, /* secp384r1 (24) */
0,9, /* sect283k1 (9) */
0,10, /* sect283r1 (10) */
0,26, /* brainpoolP256r1 (26) */
0,22, /* secp256k1 (22) */
0,23, /* secp256r1 (23) */
0,8, /* sect239k1 (8) */
0,6, /* sect233k1 (6) */
0,7, /* sect233r1 (7) */
0,20, /* secp224k1 (20) */
0,21, /* secp224r1 (21) */
0,4, /* sect193r1 (4) */
0,5, /* sect193r2 (5) */
0,18, /* secp192k1 (18) */
0,19, /* secp192r1 (19) */
0,1, /* sect163k1 (1) */
0,2, /* sect163r1 (2) */
0,3, /* sect163r2 (3) */
0,15, /* secp160k1 (15) */
0,16, /* secp160r1 (16) */
0,17, /* secp160r2 (17) */
};
static const unsigned char suiteb_curves[] =
{
0, TLSEXT_curve_P_256,
0, TLSEXT_curve_P_384
};
int tls1_ec_curve_id2nid(int curve_id)
{
/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
if ((curve_id < 1) || ((unsigned int)curve_id >
sizeof(nid_list)/sizeof(nid_list[0])))
return 0;
return nid_list[curve_id-1];
}
int tls1_ec_nid2curve_id(int nid)
{
/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
switch (nid)
{
case NID_sect163k1: /* sect163k1 (1) */
return 1;
case NID_sect163r1: /* sect163r1 (2) */
return 2;
case NID_sect163r2: /* sect163r2 (3) */
return 3;
case NID_sect193r1: /* sect193r1 (4) */
return 4;
case NID_sect193r2: /* sect193r2 (5) */
return 5;
case NID_sect233k1: /* sect233k1 (6) */
return 6;
case NID_sect233r1: /* sect233r1 (7) */
return 7;
case NID_sect239k1: /* sect239k1 (8) */
return 8;
case NID_sect283k1: /* sect283k1 (9) */
return 9;
case NID_sect283r1: /* sect283r1 (10) */
return 10;
case NID_sect409k1: /* sect409k1 (11) */
return 11;
case NID_sect409r1: /* sect409r1 (12) */
return 12;
case NID_sect571k1: /* sect571k1 (13) */
return 13;
case NID_sect571r1: /* sect571r1 (14) */
return 14;
case NID_secp160k1: /* secp160k1 (15) */
return 15;
case NID_secp160r1: /* secp160r1 (16) */
return 16;
case NID_secp160r2: /* secp160r2 (17) */
return 17;
case NID_secp192k1: /* secp192k1 (18) */
return 18;
case NID_X9_62_prime192v1: /* secp192r1 (19) */
return 19;
case NID_secp224k1: /* secp224k1 (20) */
return 20;
case NID_secp224r1: /* secp224r1 (21) */
return 21;
case NID_secp256k1: /* secp256k1 (22) */
return 22;
case NID_X9_62_prime256v1: /* secp256r1 (23) */
return 23;
case NID_secp384r1: /* secp384r1 (24) */
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
*/
static void tls1_get_curvelist(SSL *s, int sess,
const unsigned char **pcurves,
size_t *pcurveslen)
{
if (sess)
{
*pcurves = s->session->tlsext_ellipticcurvelist;
*pcurveslen = s->session->tlsext_ellipticcurvelist_length;
return;
}
/* 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)
{
*pcurves = eccurves_default;
*pcurveslen = sizeof(eccurves_default);
}
}
/* 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;
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;
}
tls1_get_curvelist(s, 0, &curves, &curveslen);
for (i = 0; i < curveslen; i += 2, 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.
*/
int tls1_shared_curve(SSL *s, int nmatch)
{
const unsigned char *pref, *supp;
size_t preflen, supplen, 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;
}
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;
k = 0;
for (i = 0; i < preflen; i++, pref+=2)
{
const unsigned char *tsupp = supp;
for (j = 0; j < supplen; 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;
return 0;
}
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;
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]);
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;
}
/* TODO(fork): remove */
#if 0
#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 (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);
}
#endif
/* 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 = 1, id;
const EC_GROUP *grp;
if (!ec)
return 0;
/* TODO(fork): remove. All curves are prime now. */
grp = EC_KEY_get0_group(ec);
if (!grp)
return 0;
#if 0
/* Determine if it is a prime field */
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;
#endif
/* 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 *p;
size_t plen, 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++)
{
if (*comp_id == *p)
break;
}
if (i == plen)
return 0;
}
if (!curve_id)
return 1;
/* 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 (p[0] == curve_id[0] && p[1] == curve_id[1])
break;
}
if (i == plen)
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 *pformatslen)
{
/* 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;
}
else
{
*pformats = ecformats_default;
/* For Suite B we don't support char2 fields */
if (tls1_suiteb(s))
*pformatslen = sizeof(ecformats_default) - 1;
else
*pformatslen = 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;
}
/* 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
}
#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
/* List of supported signature algorithms and hashes. Should make this
* customisable at some point, for now include everything we support.
*/
#ifdef OPENSSL_NO_RSA
#define tlsext_sigalg_rsa(md) /* */
#else
#define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa,
#endif
#ifdef OPENSSL_NO_DSA
#define tlsext_sigalg_dsa(md) /* */
#else
#define tlsext_sigalg_dsa(md) md, TLSEXT_signature_dsa,
#endif
#ifdef OPENSSL_NO_ECDSA
#define tlsext_sigalg_ecdsa(md) /* */
#else
#define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa,
#endif
#define tlsext_sigalg(md) \
tlsext_sigalg_rsa(md) \
tlsext_sigalg_dsa(md) \
tlsext_sigalg_ecdsa(md)
static unsigned char tls12_sigalgs[] = {
#ifndef OPENSSL_NO_SHA512
tlsext_sigalg(TLSEXT_hash_sha512)
tlsext_sigalg(TLSEXT_hash_sha384)
#endif
#ifndef OPENSSL_NO_SHA256
tlsext_sigalg(TLSEXT_hash_sha256)
tlsext_sigalg(TLSEXT_hash_sha224)
#endif
#ifndef OPENSSL_NO_SHA
tlsext_sigalg(TLSEXT_hash_sha1)
#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;
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])
{
OPENSSL_PUT_ERROR(SSL, 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))
{
OPENSSL_PUT_ERROR(SSL, 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)
{
OPENSSL_PUT_ERROR(SSL, 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)
{
OPENSSL_PUT_ERROR(SSL, 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))
{
OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE);
return 0;
}
*pmd = tls12_get_hash(sig[0]);
if (*pmd == NULL)
{
OPENSSL_PUT_ERROR(SSL, 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_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 */
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)
{
int extdatalen=0;
unsigned char *ret = p;
#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)
return p;
ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
if (s->tlsext_hostname != NULL)
{
/* Add TLS extension servername to the Client Hello message */
unsigned long size_str;
long lenmax;
/* check for enough space.
4 for the servername type and entension length
2 for servernamelist length
1 for the hostname type
2 for hostname length
+ hostname length
*/
if ((lenmax = limit - ret - 9) < 0
|| (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
return NULL;
/* extension type and length */
s2n(TLSEXT_TYPE_server_name,ret);
s2n(size_str+5,ret);
/* length of servername list */
s2n(size_str+3,ret);
/* hostname type, length and hostname */
*(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
s2n(size_str,ret);
memcpy(ret, s->tlsext_hostname, size_str);
ret+=size_str;
}
/* Add RI if renegotiating */
if (s->renegotiate)
{
int el;
if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
if((limit - p - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_renegotiate,ret);
s2n(el,ret);
if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
ret += el;
}
#ifndef OPENSSL_NO_EC
if (using_ecc)
{
/* Add TLS extension ECPointFormats to the ClientHello message */
long lenmax;
const unsigned char *plist;
size_t plistlen;
tls1_get_formatlist(s, &plist, &plistlen);
if ((lenmax = limit - ret - 5) < 0) return NULL;
if (plistlen > (size_t)lenmax) return NULL;
if (plistlen > 255)
{
OPENSSL_PUT_ERROR(SSL, 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;
/* Add TLS extension EllipticCurves to the ClientHello message */
plist = s->tlsext_ellipticcurvelist;
tls1_get_curvelist(s, 0, &plist, &plistlen);
if ((lenmax = limit - ret - 6) < 0) return NULL;
if (plistlen > (size_t)lenmax) return NULL;
if (plistlen > 65532)
{
OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
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;
}
#endif /* OPENSSL_NO_EC */
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
int ticklen;
if (!s->new_session && s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
else if (s->session && s->tlsext_session_ticket &&
s->tlsext_session_ticket->data)
{
ticklen = s->tlsext_session_ticket->length;
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
if (!s->session->tlsext_tick)
return NULL;
memcpy(s->session->tlsext_tick,
s->tlsext_session_ticket->data,
ticklen);
s->session->tlsext_ticklen = ticklen;
}
else
ticklen = 0;
if (ticklen == 0 && s->tlsext_session_ticket &&
s->tlsext_session_ticket->data == NULL)
goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
s2n(TLSEXT_TYPE_session_ticket,ret);
s2n(ticklen,ret);
if (ticklen)
{
memcpy(ret, s->session->tlsext_tick, ticklen);
ret += ticklen;
}
}
skip_ext:
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(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)
{
size_t col = s->s3->client_opaque_prf_input_len;
if ((long)(limit - ret - 6 - col < 0))
return NULL;
if (col > 0xFFFD) /* can't happen */
return NULL;
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
s2n(col + 2, ret);
s2n(col, ret);
memcpy(ret, s->s3->client_opaque_prf_input, col);
ret += col;
}
#endif
/* TODO(fork): we probably want OCSP stapling, but it currently pulls in a lot of code. */
#if 0
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
{
int i;
long extlen, idlen, itmp;
OCSP_RESPID *id;
idlen = 0;
for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
{
id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
itmp = i2d_OCSP_RESPID(id, NULL);
if (itmp <= 0)
return NULL;
idlen += itmp + 2;
}
if (s->tlsext_ocsp_exts)
{
extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
if (extlen < 0)
return NULL;
}
else
extlen = 0;
if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
s2n(TLSEXT_TYPE_status_request, ret);
if (extlen + idlen > 0xFFF0)
return NULL;
s2n(extlen + idlen + 5, ret);
*(ret++) = TLSEXT_STATUSTYPE_ocsp;
s2n(idlen, ret);
for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
{
/* save position of id len */
unsigned char *q = ret;
id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
/* skip over id len */
ret += 2;
itmp = i2d_OCSP_RESPID(id, &ret);
/* write id len */
s2n(itmp, q);
}
s2n(extlen, ret);
if (extlen > 0)
i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
}
#endif
#ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension */
s2n(TLSEXT_TYPE_heartbeat,ret);
s2n(1,ret);
/* Set mode:
* 1: peer may send requests
* 2: peer not allowed to send requests
*/
if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
*(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
else
*(ret++) = SSL_TLSEXT_HB_ENABLED;
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
{
/* The client advertises an emtpy extension to indicate its
* support for Next Protocol Negotiation */
if (limit - ret - 4 < 0)
return NULL;
s2n(TLSEXT_TYPE_next_proto_neg,ret);
s2n(0,ret);
}
#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;
}
if (s->tlsext_channel_id_enabled)
{
/* The client advertises an emtpy extension to indicate its
* support for Channel ID. */
if (limit - ret - 4 < 0)
return NULL;
if (s->ctx->tlsext_channel_id_enabled_new)
s2n(TLSEXT_TYPE_channel_id_new,ret);
else
s2n(TLSEXT_TYPE_channel_id,ret);
s2n(0,ret);
}
if(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;
s2n(TLSEXT_TYPE_use_srtp,ret);
s2n(el,ret);
if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
ret += el;
}
/* 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)
{
const unsigned short ext_len = 2;
const unsigned char list_len = 1;
if (limit < ret + 6)
return NULL;
s2n(TLSEXT_TYPE_server_authz, ret);
/* Extension length: 2 bytes */
s2n(ext_len, ret);
*(ret++) = list_len;
*(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
}
/* Add custom TLS Extensions to ClientHello */
if (s->ctx->custom_cli_ext_records_count)
{
size_t i;
custom_cli_ext_record* record;
for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
{
const unsigned char* out = NULL;
unsigned short outlen = 0;
record = &s->ctx->custom_cli_ext_records[i];
/* NULL callback sends empty extension */
/* -1 from callback omits extension */
if (record->fn1)
{
int cb_retval = 0;
cb_retval = record->fn1(s, record->ext_type,
&out, &outlen,
record->arg);
if (cb_retval == 0)
return NULL; /* error */
if (cb_retval == -1)
continue; /* skip this extension */
}
if (limit < ret + 4 + outlen)
return NULL;
s2n(record->ext_type, ret);
s2n(outlen, ret);
memcpy(ret, out, outlen);
ret += outlen;
}
}
#ifdef TLSEXT_TYPE_padding
/* Add padding to workaround bugs in F5 terminators.
* See https://tools.ietf.org/html/draft-agl-tls-padding-02
*
* NB: because this code works out the length of all existing
* extensions it MUST always appear last.
*/
{
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_padding, ret);
s2n(hlen, ret);
memset(ret, 0, hlen);
ret += hlen;
}
#endif
if ((extdatalen = ret-p-2) == 0)
return p;
s2n(extdatalen,p);
return ret;
}
unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
{
int extdatalen=0;
unsigned char *ret = p;
#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;
ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
{
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_server_name,ret);
s2n(0,ret);
}
if(s->s3->send_connection_binding)
{
int el;
if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
if((limit - p - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_renegotiate,ret);
s2n(el,ret);
if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
ret += el;
}
#ifndef OPENSSL_NO_EC
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 (plistlen > (size_t)lenmax) return NULL;
if (plistlen > 255)
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_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;
}
/* Currently the server should not respond with a SupportedCurves extension */
#endif /* OPENSSL_NO_EC */
if (s->tlsext_ticket_expected
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_session_ticket,ret);
s2n(0,ret);
}
if (s->tlsext_status_expected)
{
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_status_request,ret);
s2n(0,ret);
}
#ifdef TLSEXT_TYPE_opaque_prf_input
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)
return NULL;
if (sol > 0xFFFD) /* can't happen */
return NULL;
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
s2n(sol + 2, ret);
s2n(sol, ret);
memcpy(ret, s->s3->server_opaque_prf_input, sol);
ret += sol;
}
#endif
if(s->srtp_profile)
{
int el;
ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
if((limit - p - 4 - el) < 0) return NULL;
s2n(TLSEXT_TYPE_use_srtp,ret);
s2n(el,ret);
if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
return NULL;
}
ret+=el;
}
if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81)
&& (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
{ const unsigned char cryptopro_ext[36] = {
0xfd, 0xe8, /*65000*/
0x00, 0x20, /*32 bytes length*/
0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
if (limit-ret<36) return NULL;
memcpy(ret,cryptopro_ext,36);
ret+=36;
}
#ifndef OPENSSL_NO_HEARTBEATS
/* Add Heartbeat extension if we've received one */
if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
{
s2n(TLSEXT_TYPE_heartbeat,ret);
s2n(1,ret);
/* Set mode:
* 1: peer may send requests
* 2: peer not allowed to send requests
*/
if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
*(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
else
*(ret++) = SSL_TLSEXT_HB_ENABLED;
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
next_proto_neg_seen = s->s3->next_proto_neg_seen;
s->s3->next_proto_neg_seen = 0;
if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
{
const unsigned char *npa;
unsigned int npalen;
int r;
r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
if (r == SSL_TLSEXT_ERR_OK)
{
if ((long)(limit - ret - 4 - npalen) < 0) return NULL;
s2n(TLSEXT_TYPE_next_proto_neg,ret);
s2n(npalen,ret);
memcpy(ret, npa, npalen);
ret += npalen;
s->s3->next_proto_neg_seen = 1;
}
}
#endif
/* If the client supports authz then see whether we have any to offer
* to it. */
if (s->s3->tlsext_authz_client_types_len)
{
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;
}
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 custom types were sent in ClientHello, add ServerHello responses */
if (s->s3->tlsext_custom_types_count)
{
size_t i;
for (i = 0; i < s->s3->tlsext_custom_types_count; i++)
{
size_t j;
custom_srv_ext_record *record;
for (j = 0; j < s->ctx->custom_srv_ext_records_count; j++)
{
record = &s->ctx->custom_srv_ext_records[j];
if (s->s3->tlsext_custom_types[i] == record->ext_type)
{
const unsigned char *out = NULL;
unsigned short outlen = 0;
int cb_retval = 0;
/* NULL callback or -1 omits extension */
if (!record->fn2)
break;
cb_retval = record->fn2(s, record->ext_type,
&out, &outlen,
record->arg);
if (cb_retval == 0)
return NULL; /* error */
if (cb_retval == -1)
break; /* skip this extension */
if (limit < ret + 4 + outlen)
return NULL;
s2n(record->ext_type, ret);
s2n(outlen, ret);
memcpy(ret, out, outlen);
ret += outlen;
break;
}
}
}
}
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 the client advertised support for Channel ID, and we have it
* enabled, then we want to echo it back. */
if (s->s3->tlsext_channel_id_valid)
{
if (limit - ret - 4 < 0)
return NULL;
if (s->s3->tlsext_channel_id_new)
s2n(TLSEXT_TYPE_channel_id_new,ret);
else
s2n(TLSEXT_TYPE_channel_id,ret);
s2n(0,ret);
}
if ((extdatalen = ret-p-2)== 0)
return p;
s2n(extdatalen,p);
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 size;
unsigned short len;
unsigned char *data = *p;
int renegotiate_seen = 0;
size_t i;
s->servername_done = 0;
s->tlsext_status_type = -1;
#ifndef OPENSSL_NO_NEXTPROTONEG
s->s3->next_proto_neg_seen = 0;
#endif
/* Clear observed custom extensions */
s->s3->tlsext_custom_types_count = 0;
if (s->s3->tlsext_custom_types != NULL)
{
OPENSSL_free(s->s3->tlsext_custom_types);
s->s3->tlsext_custom_types = NULL;
}
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++)
{
s->cert->pkeys[i].digest = NULL;
s->cert->pkeys[i].valid_flags = 0;
}
if (data >= (d+n-2))
goto ri_check;
n2s(data,len);
if (data > (d+n-len))
goto ri_check;
while (data <= (d+n-4))
{
n2s(data,type);
n2s(data,size);
if (data+size > (d+n))
goto ri_check;
#if 0
fprintf(stderr,"Received extension type %d size %d\n",type,size);
#endif
if (s->tlsext_debug_cb)
s->tlsext_debug_cb(s, 0, type, data, size,
s->tlsext_debug_arg);
/* The servername extension is treated as follows:
- Only the hostname type is supported with a maximum length of 255.
- The servername is rejected if too long or if it contains zeros,
in which case an fatal alert is generated.
- The servername field is maintained together with the session cache.
- When a session is resumed, the servername call back invoked in order
to allow the application to position itself to the right context.
- The servername is acknowledged if it is new for a session or when
it is identical to a previously used for the same session.
Applications can control the behaviour. They can at any time
set a 'desirable' servername for a new SSL object. This can be the
case for example with HTTPS when a Host: header field is received and
a renegotiation is requested. In this case, a possible servername
presented in the new client hello is only acknowledged if it matches
the value of the Host: field.
- Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
if they provide for changing an explicit servername context for the session,
i.e. when the session has been established with a servername extension.
- On session reconnect, the servername extension may be absent.
*/
if (type == TLSEXT_TYPE_server_name)
{
unsigned char *sdata;
int servname_type;
int dsize;
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(data,dsize);
size -= 2;
if (dsize > size )
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
sdata = data;
while (dsize > 3)
{
servname_type = *(sdata++);
n2s(sdata,len);
dsize -= 3;
if (len > dsize)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (s->servername_done == 0)
switch (servname_type)
{
case TLSEXT_NAMETYPE_host_name:
if (!s->hit)
{
if(s->session->tlsext_hostname)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (len > TLSEXT_MAXLEN_host_name)
{
*al = TLS1_AD_UNRECOGNIZED_NAME;
return 0;
}
if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
memcpy(s->session->tlsext_hostname, sdata, len);
s->session->tlsext_hostname[len]='\0';
if (strlen(s->session->tlsext_hostname) != len) {
OPENSSL_free(s->session->tlsext_hostname);
s->session->tlsext_hostname = NULL;
*al = TLS1_AD_UNRECOGNIZED_NAME;
return 0;
}
s->servername_done = 1;
}
else
s->servername_done = s->session->tlsext_hostname
&& strlen(s->session->tlsext_hostname) == len
&& strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
break;
default:
break;
}
dsize -= len;
}
if (dsize != 0)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
}
#ifndef OPENSSL_NO_EC
else if (type == TLSEXT_TYPE_ec_point_formats)
{
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
if (ecpointformatlist_length != size - 1 ||
ecpointformatlist_length < 1)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
if (!s->hit)
{
if(s->session->tlsext_ecpointformatlist)
{
OPENSSL_free(s->session->tlsext_ecpointformatlist);
s->session->tlsext_ecpointformatlist = NULL;
}
s->session->tlsext_ecpointformatlist_length = 0;
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);
}
#if 0
fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
sdata = s->session->tlsext_ecpointformatlist;
for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
fprintf(stderr,"%i ",*(sdata++));
fprintf(stderr,"\n");
#endif
}
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)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
if (!s->hit)
{
if(s->session->tlsext_ellipticcurvelist)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
s->session->tlsext_ellipticcurvelist_length = 0;
if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
}
#if 0
fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
sdata = s->session->tlsext_ellipticcurvelist;
for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
fprintf(stderr,"%i ",*(sdata++));
fprintf(stderr,"\n");
#endif
}
#endif /* OPENSSL_NO_EC */
#ifdef TLSEXT_TYPE_opaque_prf_input
else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(sdata, s->s3->client_opaque_prf_input_len);
if (s->s3->client_opaque_prf_input_len != size - 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->client_opaque_prf_input);
if (s->s3->client_opaque_prf_input_len == 0)
s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
else
s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
if (s->s3->client_opaque_prf_input == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
}
#endif
else if (type == TLSEXT_TYPE_session_ticket)
{
if (s->tls_session_ticket_ext_cb &&
!s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
}
else if (type == TLSEXT_TYPE_renegotiate)
{
if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
return 0;
renegotiate_seen = 1;
}
else if (type == TLSEXT_TYPE_signature_algorithms)
{
int dsize;
if (s->cert->peer_sigalgs || size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(data,dsize);
size -= 2;
if (dsize != size || dsize & 1 || !dsize)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (!tls1_process_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)
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
*al = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
/* TODO(fork): we probably want OCSP stapling support, but this pulls in a lot of code. */
#if 0
else if (type == TLSEXT_TYPE_status_request)
{
if (size < 5)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
s->tlsext_status_type = *data++;
size--;
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
{
const unsigned char *sdata;
int dsize;
/* Read in responder_id_list */
n2s(data,dsize);
size -= 2;
if (dsize > size )
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
while (dsize > 0)
{
OCSP_RESPID *id;
int idsize;
if (dsize < 4)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(data, idsize);
dsize -= 2 + idsize;
size -= 2 + idsize;
if (dsize < 0)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
sdata = data;
data += idsize;
id = d2i_OCSP_RESPID(NULL,
&sdata, idsize);
if (!id)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (data != sdata)
{
OCSP_RESPID_free(id);
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (!s->tlsext_ocsp_ids
&& !(s->tlsext_ocsp_ids =
sk_OCSP_RESPID_new_null()))
{
OCSP_RESPID_free(id);
*al = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (!sk_OCSP_RESPID_push(
s->tlsext_ocsp_ids, id))
{
OCSP_RESPID_free(id);
*al = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
/* Read in request_extensions */
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(data,dsize);
size -= 2;
if (dsize != size)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
sdata = data;
if (dsize > 0)
{
if (s->tlsext_ocsp_exts)
{
sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
X509_EXTENSION_free);
}
s->tlsext_ocsp_exts =
d2i_X509_EXTENSIONS(NULL,
&sdata, dsize);
if (!s->tlsext_ocsp_exts
|| (data + dsize != sdata))
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
}
}
/* We don't know what to do with any other type
* so ignore it.
*/
else
s->tlsext_status_type = -1;
}
#endif
#ifndef OPENSSL_NO_HEARTBEATS
else if (type == TLSEXT_TYPE_heartbeat)
{
switch(data[0])
{
case 0x01: /* Client allows us to send HB requests */
s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
break;
case 0x02: /* Client doesn't accept HB requests */
s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
break;
default: *al = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
s->s3->tmp.finish_md_len == 0 &&
s->s3->alpn_selected == NULL)
{
/* We shouldn't accept this extension on a
* renegotiation.
*
* s->new_session will be set on renegotiation, but we
* probably shouldn't rely that it couldn't be set on
* the initial renegotation too in certain cases (when
* there's some other reason to disallow resuming an
* earlier session -- the current code won't be doing
* anything like that, but this might change).
* A valid sign that there's been a previous handshake
* in this connection is if s->s3->tmp.finish_md_len >
* 0. (We are talking about a check that will happen
* in the Hello protocol round, well before a new
* Finished message could have been computed.) */
s->s3->next_proto_neg_seen = 1;
}
#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
}
else if (type == TLSEXT_TYPE_channel_id &&
s->tlsext_channel_id_enabled)
s->s3->tlsext_channel_id_valid = 1;
else if (type == TLSEXT_TYPE_channel_id_new &&
s->tlsext_channel_id_enabled)
{
s->s3->tlsext_channel_id_valid = 1;
s->s3->tlsext_channel_id_new = 1;
}
/* session ticket processed earlier */
else if (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;
}
}
}
}
/* If this ClientHello extension was unhandled and this is
* a nonresumed connection, check whether the extension is a
* custom TLS Extension (has a custom_srv_ext_record), and if
* so call the callback and record the extension number so that
* an appropriate ServerHello may be later returned.
*/
else if (!s->hit && s->ctx->custom_srv_ext_records_count)
{
custom_srv_ext_record *record;
for (i=0; i < s->ctx->custom_srv_ext_records_count; i++)
{
record = &s->ctx->custom_srv_ext_records[i];
if (type == record->ext_type)
{
size_t j;
/* Error on duplicate TLS Extensions */
for (j = 0; j < s->s3->tlsext_custom_types_count; j++)
{
if (type == s->s3->tlsext_custom_types[j])
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
}
/* NULL callback still notes the extension */
if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
return 0;
/* Add the (non-duplicated) entry */
s->s3->tlsext_custom_types_count++;
s->s3->tlsext_custom_types = OPENSSL_realloc(
s->s3->tlsext_custom_types,
s->s3->tlsext_custom_types_count * 2);
if (s->s3->tlsext_custom_types == NULL)
{
s->s3->tlsext_custom_types = 0;
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
s->s3->tlsext_custom_types[
s->s3->tlsext_custom_types_count - 1] = type;
}
}
}
data+=size;
}
*p = data;
ri_check:
/* Need RI if renegotiating */
if (!renegotiate_seen && s->renegotiate &&
!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
{
*al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, 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;
}
int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
{
int al = -1;
if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0)
{
ssl3_send_alert(s,SSL3_AL_FATAL,al);
return 0;
}
if (ssl_check_clienthello_tlsext_early(s) <= 0)
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_CLIENTHELLO_TLSEXT);
return 0;
}
return 1;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
* elements of zero length are allowed and the set of elements must exactly fill
* the length of the block. */
static char ssl_next_proto_validate(unsigned char *d, unsigned len)
{
unsigned int off = 0;
while (off < len)
{
if (d[off] == 0)
return 0;
off += d[off];
off++;
}
return off == len;
}
#endif
static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
{
unsigned short length;
unsigned short type;
unsigned short size;
unsigned char *data = *p;
int tlsext_servername = 0;
int renegotiate_seen = 0;
#ifndef OPENSSL_NO_NEXTPROTONEG
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
if (data >= (d+n-2))
goto ri_check;
n2s(data,length);
if (data+length != d+n)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
while(data <= (d+n-4))
{
n2s(data,type);
n2s(data,size);
if (data+size > (d+n))
goto ri_check;
if (s->tlsext_debug_cb)
s->tlsext_debug_cb(s, 1, type, data, size,
s->tlsext_debug_arg);
if (type == TLSEXT_TYPE_server_name)
{
if (s->tlsext_hostname == NULL || size > 0)
{
*al = TLS1_AD_UNRECOGNIZED_NAME;
return 0;
}
tlsext_servername = 1;
}
#ifndef OPENSSL_NO_EC
else if (type == TLSEXT_TYPE_ec_point_formats)
{
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
if (ecpointformatlist_length != size - 1)
{
*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)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
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;
for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
fprintf(stderr,"%i ",*(sdata++));
fprintf(stderr,"\n");
#endif
}
#endif /* OPENSSL_NO_EC */
else if (type == TLSEXT_TYPE_session_ticket)
{
if (s->tls_session_ticket_ext_cb &&
!s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
}
s->tlsext_ticket_expected = 1;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
else if (type == TLSEXT_TYPE_opaque_prf_input)
{
unsigned char *sdata = data;
if (size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
n2s(sdata, s->s3->server_opaque_prf_input_len);
if (s->s3->server_opaque_prf_input_len != size - 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
OPENSSL_free(s->s3->server_opaque_prf_input);
if (s->s3->server_opaque_prf_input_len == 0)
s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
else
s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
if (s->s3->server_opaque_prf_input == NULL)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
}
#endif
else if (type == TLSEXT_TYPE_status_request)
{
/* MUST be empty and only sent if we've requested
* a status request message.
*/
if ((s->tlsext_status_type == -1) || (size > 0))
{
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
}
/* Set flag to expect CertificateStatus message */
s->tlsext_status_expected = 1;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
s->s3->tmp.finish_md_len == 0)
{
unsigned char *selected;
unsigned char selected_len;
/* We must have requested it. */
if (s->ctx->next_proto_select_cb == NULL)
{
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
}
/* The data must be valid */
if (!ssl_next_proto_validate(data, size))
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
}
if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
s->next_proto_negotiated = OPENSSL_malloc(selected_len);
if (!s->next_proto_negotiated)
{
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
memcpy(s->next_proto_negotiated, selected, selected_len);
s->next_proto_negotiated_len = selected_len;
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_channel_id)
s->s3->tlsext_channel_id_valid = 1;
else if (type == TLSEXT_TYPE_channel_id_new)
{
s->s3->tlsext_channel_id_valid = 1;
s->s3->tlsext_channel_id_new = 1;
}
else if (type == TLSEXT_TYPE_renegotiate)
{
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
return 0;
renegotiate_seen = 1;
}
#ifndef OPENSSL_NO_HEARTBEATS
else if (type == TLSEXT_TYPE_heartbeat)
{
switch(data[0])
{
case 0x01: /* Server allows us to send HB requests */
s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
break;
case 0x02: /* Server doesn't accept HB requests */
s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
break;
default: *al = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
#endif
else if (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;
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;
}
/* If this extension type was not otherwise handled, but
* matches a custom_cli_ext_record, then send it to the c
* callback */
else if (s->ctx->custom_cli_ext_records_count)
{
size_t i;
custom_cli_ext_record* record;
for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
{
record = &s->ctx->custom_cli_ext_records[i];
if (record->ext_type == type)
{
if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg))
return 0;
break;
}
}
}
data += size;
}
if (data != d+n)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
if (!s->hit && tlsext_servername == 1)
{
if (s->tlsext_hostname)
{
if (s->session->tlsext_hostname == NULL)
{
s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
if (!s->session->tlsext_hostname)
{
*al = SSL_AD_UNRECOGNIZED_NAME;