X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=f62a004cf2eb6c200ac0c65a4166de89a5e54e1f;hp=39b5e725330aebe4ea6c9e4e113df0addf33865f;hb=c46ecc3a55bcbbe4ff31da3864d015e343b0189f;hpb=ee2ffc279417f15fef3b1073c7dc81a908991516 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 39b5e72533..f62a004cf2 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -114,6 +114,7 @@ #include #include #include +#include #include "ssl_locl.h" const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; @@ -122,6 +123,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(SSL *s); +int ssl_check_serverhello_tlsext(SSL *s); #endif SSL3_ENC_METHOD TLSv1_enc_data={ @@ -136,6 +139,7 @@ SSL3_ENC_METHOD TLSv1_enc_data={ 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, }; long tls1_default_timeout(void) @@ -170,6 +174,7 @@ void tls1_clear(SSL *s) } #ifndef OPENSSL_NO_EC + static int nid_list[] = { NID_sect163k1, /* sect163k1 (1) */ @@ -198,7 +203,44 @@ static int nid_list[] = NID_secp384r1, /* secp384r1 (24) */ NID_secp521r1 /* secp521r1 (25) */ }; - + + +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,11, /* sect409k1 (11) */ + 0,12, /* sect409r1 (12) */ + 0,24, /* secp384r1 (24) */ + 0,9, /* sect283k1 (9) */ + 0,10, /* sect283r1 (10) */ + 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) */ + }; + int tls1_ec_curve_id2nid(int curve_id) { /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ @@ -267,13 +309,367 @@ int tls1_ec_nid2curve_id(int nid) 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; + } + else + { + *pcurves = s->tlsext_ellipticcurvelist; + *pcurveslen = s->tlsext_ellipticcurvelist_length; + } + /* If not set use default: for now static structure */ + if (!*pcurves) + { + *pcurves = eccurves_default; + *pcurveslen = sizeof(eccurves_default); + } + } + +/* Return nth shared curve. If nmatch == -1 return number of + * matches. + */ + +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; + 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; + } + +#define MAX_CURVELIST 25 + +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; + 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_POINT *pt; + const EC_METHOD *meth; + if (!ec) + return 0; + /* Determine if it is a prime field */ + grp = EC_KEY_get0_group(ec); + pt = EC_KEY_get0_public_key(ec); + if (!grp || !pt) + 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_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; + } + /* 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; + } + return 1; + } +/* Check EC server key is compatible with client extensions */ +int tls1_check_ec_server_key(SSL *s) + { + int rv; + CERT_PKEY *cpk = s->cert->pkeys + SSL_PKEY_ECC; + EVP_PKEY *pkey; + unsigned char comp_id, curve_id[2]; + if (!cpk->x509 || !cpk->privatekey) + return 0; + pkey = X509_get_pubkey(cpk->x509); + if (!pkey) + return 0; + rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec); + EVP_PKEY_free(pkey); + if (!rv) + return 0; + return tls1_check_ec_key(s, curve_id, &comp_id); + } +/* Check EC temporary key is compatible with client extensions */ +int tls1_check_ec_tmp_key(SSL *s) + { + unsigned char curve_id[2]; + EC_KEY *ec = s->cert->ecdh_tmp; + 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 1; + return tls1_check_ec_key(s, curve_id, NULL); + } + #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_MD5 + tlsext_sigalg_rsa(TLSEXT_hash_md5) +#endif +}; + +int tls12_get_req_sig_algs(SSL *s, unsigned char *p) + { + size_t slen = sizeof(tls12_sigalgs); +#ifdef OPENSSL_FIPS + /* If FIPS mode don't include MD5 which is last */ + if (FIPS_mode()) + slen -= 2; +#endif + if (p) + memcpy(p, tls12_sigalgs, slen); + return (int)slen; + } + 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 != DTLS1_VERSION && s->version >= TLS1_VERSION) + { + 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 @@ -317,7 +713,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } /* Add RI if renegotiating */ - if (s->new_session) + if (s->renegotiate) { int el; @@ -341,52 +737,89 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += el; } +#ifndef OPENSSL_NO_SRP + /* Add SRP username if there is one */ + if (s->srp_ctx.login != NULL) + { /* Add TLS extension SRP username to the Client Hello message */ + + int login_len = strlen(s->srp_ctx.login); + if (login_len > 255 || login_len == 0) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + /* check for enough space. + 4 for the srp type type and entension length + 1 for the srp user identity + + srp user identity length + */ + if ((limit - ret - 5 - login_len) < 0) return NULL; + + /* fill in the extension */ + s2n(TLSEXT_TYPE_srp,ret); + s2n(login_len+1,ret); + (*ret++) = (unsigned char) login_len; + memcpy(ret, s->srp_ctx.login, login_len); + ret+=login_len; + } +#endif + #ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist != NULL && - s->version != DTLS1_VERSION) + if (using_ecc) { /* Add TLS extension ECPointFormats to the ClientHello message */ long lenmax; + const unsigned char *plist; + size_t plistlen; + /* If we have a custom point format list use it otherwise + * use default */ + plist = s->tlsext_ecpointformatlist; + if (plist) + plistlen = s->tlsext_ecpointformatlist_length; + else + { + plist = ecformats_default; + plistlen = sizeof(ecformats_default); + } if ((lenmax = limit - ret - 5) < 0) return NULL; - if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; - if (s->tlsext_ecpointformatlist_length > 255) + if (plistlen > (size_t)lenmax) return NULL; + if (plistlen > 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 && - s->version != DTLS1_VERSION) - { + s2n(plistlen + 1,ret); + *(ret++) = (unsigned char)plistlen ; + memcpy(ret, plist, plistlen); + ret+=plistlen; + /* Add TLS extension EllipticCurves to the ClientHello message */ - long lenmax; + plist = s->tlsext_ellipticcurvelist; + tls1_get_curvelist(s, 0, &plist, &plistlen); if ((lenmax = limit - ret - 6) < 0) return NULL; - if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; - if (s->tlsext_ellipticcurvelist_length > 65532) + if (plistlen > (size_t)lenmax) return NULL; + if (plistlen > 65532) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); return NULL; } s2n(TLSEXT_TYPE_elliptic_curves,ret); - s2n(s->tlsext_ellipticcurvelist_length + 2, 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(s->tlsext_ellipticcurvelist_length, ret); - memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); - ret+=s->tlsext_ellipticcurvelist_length; + s2n(plistlen, ret); + memcpy(ret, plist, plistlen); + ret+=plistlen; } #endif /* OPENSSL_NO_EC */ @@ -426,6 +859,17 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } skip_ext: + if (TLS1_get_client_version(s) >= TLS1_2_VERSION) + { + if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 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); + } + #ifdef TLSEXT_TYPE_opaque_prf_input if (s->s3->client_opaque_prf_input != NULL && s->version != DTLS1_VERSION) @@ -494,7 +938,21 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); } -#ifndef OPENSSL_NO_NPN +#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 @@ -506,6 +964,25 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif + 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)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; + } + if ((extdatalen = ret-p-2)== 0) return p; @@ -517,8 +994,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha { int extdatalen=0; unsigned char *ret = p; -#ifndef OPENSSL_NO_NPN - char next_proto_neg_seen; +#ifndef OPENSSL_NO_NEXTPROTONEG + int next_proto_neg_seen; #endif /* don't add extensions for SSLv3, unless doing secure renegotiation */ @@ -618,6 +1095,26 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha 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)) + { + SSLerr(SSL_F_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] = { @@ -633,7 +1130,25 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } -#ifndef OPENSSL_NO_NPN +#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) @@ -662,16 +1177,25 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha return ret; } -int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) - { +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; + int sigalg_seen = 0; s->servername_done = 0; s->tlsext_status_type = -1; +#ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +#endif + +#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; @@ -751,14 +1275,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in switch (servname_type) { case TLSEXT_NAMETYPE_host_name: - if (s->session->tlsext_hostname == NULL) + if (!s->hit) { - if (len > TLSEXT_MAXLEN_host_name || - ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)) + 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) { @@ -771,7 +1304,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } else - s->servername_done = strlen(s->session->tlsext_hostname) == len + s->servername_done = s->session->tlsext_hostname + && strlen(s->session->tlsext_hostname) == len && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0; break; @@ -789,6 +1323,31 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } +#ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) + { + if (size <= 0 || ((len = data[0])) != (size -1)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->srp_ctx.login != NULL) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL) + return -1; + memcpy(s->srp_ctx.login, &data[1], len); + s->srp_ctx.login[len]='\0'; + + if (strlen(s->srp_ctx.login) != len) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } +#endif #ifndef OPENSSL_NO_EC else if (type == TLSEXT_TYPE_ec_point_formats && @@ -802,15 +1361,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in *al = TLS1_AD_DECODE_ERROR; return 0; } - s->session->tlsext_ecpointformatlist_length = 0; - if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); - if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL) + if (!s->hit) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; + 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); } - 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; @@ -831,15 +1397,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in *al = TLS1_AD_DECODE_ERROR; return 0; } - s->session->tlsext_ellipticcurvelist_length = 0; - if (s->session->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->session->tlsext_ellipticcurvelist); - if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL) + if (!s->hit) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; + 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); } - 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; @@ -895,6 +1468,28 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in return 0; renegotiate_seen = 1; } + else if (type == TLSEXT_TYPE_signature_algorithms) + { + int dsize; + if (sigalg_seen || size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sigalg_seen = 1; + n2s(data,dsize); + size -= 2; + if (dsize != size || dsize & 1) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!tls1_process_sigalgs(s, data, dsize)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_status_request && s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) { @@ -930,6 +1525,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } n2s(data, idsize); dsize -= 2 + idsize; + size -= 2 + idsize; if (dsize < 0) { *al = SSL_AD_DECODE_ERROR; @@ -968,9 +1564,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } /* Read in request_extensions */ + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } n2s(data,dsize); size -= 2; - if (dsize > size) + if (dsize != size) { *al = SSL_AD_DECODE_ERROR; return 0; @@ -978,6 +1579,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in 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); @@ -995,7 +1602,24 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else s->tlsext_status_type = -1; } -#ifndef OPENSSL_NO_NPN +#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) { @@ -1019,6 +1643,13 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in #endif /* session ticket processed earlier */ + else if (type == TLSEXT_TYPE_use_srtp) + { + if(ssl_parse_clienthello_use_srtp_ext(s, data, size, + al)) + return 0; + } + data+=size; } @@ -1028,11 +1659,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in /* Need RI if renegotiating */ - if (!renegotiate_seen && s->new_session && + 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; } @@ -1040,11 +1671,28 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in return 1; } -#ifndef OPENSSL_NO_NPN +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(s) <= 0) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_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) +static int ssl_next_proto_validate(unsigned char *d, unsigned len) { unsigned int off = 0; @@ -1060,7 +1708,7 @@ 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; @@ -1069,6 +1717,15 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in int tlsext_servername = 0; int renegotiate_seen = 0; +#ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +#endif + +#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; @@ -1194,8 +1851,9 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in /* Set flag to expect CertificateStatus message */ s->tlsext_status_expected = 1; } -#ifndef OPENSSL_NO_NPN - else if (type == TLSEXT_TYPE_next_proto_neg) +#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; @@ -1225,6 +1883,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } 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_renegotiate) @@ -1233,6 +1892,30 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in 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; + } + data+=size; } @@ -1279,7 +1962,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in && !(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; } @@ -1290,56 +1973,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in 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 draft-ietf-tls-ecc-12 */ - if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist); - s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_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 = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= - sizeof(nid_list)/sizeof(nid_list[0]); i++) - s2n(i,j); - } -#endif /* OPENSSL_NO_EC */ #ifdef TLSEXT_TYPE_opaque_prf_input { @@ -1409,7 +2042,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s) return 1; } -int ssl_check_clienthello_tlsext(SSL *s) +static int ssl_check_clienthello_tlsext(SSL *s) { int ret=SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -1540,23 +2173,20 @@ int ssl_check_serverhello_tlsext(SSL *s) int al = SSL_AD_UNRECOGNIZED_NAME; #ifndef OPENSSL_NO_EC - /* If we are client and using an elliptic curve cryptography cipher suite, then server - * must return a an EC point formats lists containing uncompressed. + /* If we are client and using an elliptic curve cryptography cipher + * suite, then if server returns an EC point formats lists extension + * it must contain uncompressed. */ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && + (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA))) { /* we are using an ECC cipher */ size_t i; unsigned char *list; int found_uncompressed = 0; - if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length == 0)) - { - SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); - return -1; - } list = s->session->tlsext_ecpointformatlist; for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) { @@ -1649,26 +2279,75 @@ int ssl_check_serverhello_tlsext(SSL *s) } } -/* Since the server cache lookup is done early on in the processing of client - * hello and other operations depend on the result we need to handle any TLS - * session ticket extension at the same time. - */ +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 + * any TLS session ticket extension at the same time. + * + * session_id: points at the session ID in the ClientHello. This code will + * read past the end of this in order to parse out the session ticket + * extension, if any. + * len: the length of the session ID. + * limit: a pointer to the first byte after the ClientHello. + * ret: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * If s->tls_session_secret_cb is set then we are expecting a pre-shared key + * ciphersuite, in which case we have no use for session tickets and one will + * never be decrypted, nor will s->tlsext_ticket_expected be set to 1. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 0: no ticket was found (or was ignored, based on settings). + * 1: a zero length extension was found, indicating that the client supports + * session tickets but doesn't currently have one to offer. + * 2: either s->tls_session_secret_cb was set, or a ticket was offered but + * couldn't be decrypted because of a non-fatal error. + * 3: a ticket was successfully decrypted and *ret was set. + * + * Side effects: + * Sets s->tlsext_ticket_expected to 1 if the server will have to issue + * a new session ticket to the client because the client indicated support + * (and s->tls_session_secret_cb is NULL) but the client either doesn't have + * a session ticket or we couldn't use the one it gave us, or if + * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket. + * Otherwise, s->tlsext_ticket_expected is set to 0. + */ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, - const unsigned char *limit, SSL_SESSION **ret) + const unsigned char *limit, SSL_SESSION **ret) { /* Point after session ID in client hello */ const unsigned char *p = session_id + len; unsigned short i; + *ret = NULL; + s->tlsext_ticket_expected = 0; + /* If tickets disabled behave as if no ticket present - * to permit stateful resumption. - */ + * to permit stateful resumption. + */ if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 1; - + return 0; if ((s->version <= SSL3_VERSION) || !limit) - return 1; + return 0; if (p >= limit) return -1; /* Skip past DTLS cookie */ @@ -1691,7 +2370,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, return -1; /* Now at start of extensions */ if ((p + 2) >= limit) - return 1; + return 0; n2s(p, i); while ((p + 4) <= limit) { @@ -1699,39 +2378,61 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, n2s(p, type); n2s(p, size); if (p + size > limit) - return 1; + return 0; if (type == TLSEXT_TYPE_session_ticket) { - /* If tickets disabled indicate cache miss which will - * trigger a full handshake - */ - if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 1; - /* If zero length note client will accept a ticket - * and indicate cache miss to trigger full handshake - */ + int r; if (size == 0) { + /* The client will accept a ticket but doesn't + * currently have one. */ s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ + return 1; } if (s->tls_session_secret_cb) { - /* Indicate cache miss here and instead of - * generating the session from ticket now, - * trigger abbreviated handshake based on - * external mechanism to calculate the master - * secret later. */ - return 0; + /* Indicate that the ticket couldn't be + * decrypted rather than generating the session + * from ticket now, trigger abbreviated + * handshake based on external mechanism to + * calculate the master secret later. */ + return 2; + } + r = tls_decrypt_ticket(s, p, size, session_id, len, ret); + switch (r) + { + case 2: /* ticket couldn't be decrypted */ + s->tlsext_ticket_expected = 1; + return 2; + case 3: /* ticket was decrypted */ + return r; + case 4: /* ticket decrypted but need to renew */ + s->tlsext_ticket_expected = 1; + return 3; + default: /* fatal error */ + return -1; } - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); } p += size; } - return 1; + return 0; } +/* tls_decrypt_ticket attempts to decrypt a session ticket. + * + * etick: points to the body of the session ticket extension. + * eticklen: the length of the session tickets extenion. + * sess_id: points at the session ID. + * sesslen: the length of the session ID. + * psess: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 2: the ticket couldn't be decrypted. + * 3: a ticket was successfully decrypted and *psess was set. + * 4: same as 3, but the ticket needs to be renewed. + */ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, const unsigned char *sess_id, int sesslen, SSL_SESSION **psess) @@ -1746,7 +2447,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, SSL_CTX *tctx = s->initial_ctx; /* Need at least keyname + iv + some encrypted data */ if (eticklen < 48) - goto tickerr; + return 2; /* Initialize session ticket encryption and HMAC contexts */ HMAC_CTX_init(&hctx); EVP_CIPHER_CTX_init(&ctx); @@ -1758,7 +2459,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, if (rv < 0) return -1; if (rv == 0) - goto tickerr; + return 2; if (rv == 2) renew_ticket = 1; } @@ -1766,15 +2467,15 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, { /* Check key name matches */ if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) - goto tickerr; + return 2; HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL); EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, tctx->tlsext_tick_aes_key, etick + 16); } /* Attempt to process session ticket, first conduct sanity and - * integrity checks on ticket. - */ + * integrity checks on ticket. + */ mlen = HMAC_size(&hctx); if (mlen < 0) { @@ -1787,7 +2488,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); if (memcmp(tick_hmac, etick + eticklen, mlen)) - goto tickerr; + return 2; /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); @@ -1800,33 +2501,404 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, } EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) - goto tickerr; + return 2; slen += mlen; EVP_CIPHER_CTX_cleanup(&ctx); p = sdec; - + sess = d2i_SSL_SESSION(NULL, &p, slen); OPENSSL_free(sdec); if (sess) { - /* The session ID if non-empty is used by some clients to - * detect that the ticket has been accepted. So we copy it to - * the session structure. If it is empty set length to zero - * as required by standard. - */ + /* The session ID, if non-empty, is used by some clients to + * detect that the ticket has been accepted. So we copy it to + * the session structure. If it is empty set length to zero + * as required by standard. + */ if (sesslen) memcpy(sess->session_id, sess_id, sesslen); sess->session_id_length = sesslen; *psess = sess; - s->tlsext_ticket_expected = renew_ticket; + if (renew_ticket) + return 4; + else + return 3; + } + ERR_clear_error(); + /* For session parse failure, indicate that we need to send a new + * ticket. */ + return 2; + } + +/* Tables to translate from NIDs to TLS v1.2 ids */ + +typedef struct + { + int nid; + int id; + } tls12_lookup; + +static tls12_lookup tls12_md[] = { + {NID_md5, TLSEXT_hash_md5}, + {NID_sha1, TLSEXT_hash_sha1}, + {NID_sha224, TLSEXT_hash_sha224}, + {NID_sha256, TLSEXT_hash_sha256}, + {NID_sha384, TLSEXT_hash_sha384}, + {NID_sha512, TLSEXT_hash_sha512} +}; + +static tls12_lookup tls12_sig[] = { + {EVP_PKEY_RSA, TLSEXT_signature_rsa}, + {EVP_PKEY_DSA, TLSEXT_signature_dsa}, + {EVP_PKEY_EC, TLSEXT_signature_ecdsa} +}; + +static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen) + { + size_t i; + for (i = 0; i < tlen; i++) + { + if (table[i].nid == nid) + return table[i].id; + } + return -1; + } + +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) + return table[i].nid; + } + return NID_undef; + } + +int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md) + { + int sig_id, md_id; + if (!md) + return 0; + md_id = tls12_find_id(EVP_MD_type(md), tls12_md, + sizeof(tls12_md)/sizeof(tls12_lookup)); + if (md_id == -1) + return 0; + sig_id = tls12_get_sigid(pk); + if (sig_id == -1) + return 0; + p[0] = (unsigned char)md_id; + p[1] = (unsigned char)sig_id; + return 1; + } + +int tls12_get_sigid(const EVP_PKEY *pk) + { + return tls12_find_id(pk->type, tls12_sig, + sizeof(tls12_sig)/sizeof(tls12_lookup)); + } + +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(); +#endif +#ifndef OPENSSL_NO_SHA256 + case TLSEXT_hash_sha224: + return EVP_sha224(); + + case TLSEXT_hash_sha256: + return EVP_sha256(); +#endif +#ifndef OPENSSL_NO_SHA512 + case TLSEXT_hash_sha384: + return EVP_sha384(); + + case TLSEXT_hash_sha512: + return EVP_sha512(); +#endif + default: + return NULL; + + } + } + +/* Set preferred digest for each key type */ + +int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) + { + int i, idx; + const EVP_MD *md; + CERT *c = s->cert; + TLS_SIGALGS *sigptr; + /* Extension ignored for TLS versions below 1.2 */ + if (TLS1_get_version(s) < TLS1_2_VERSION) 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->sigalgs) + OPENSSL_free(c->sigalgs); + c->sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS)); + if (!c->sigalgs) + return 0; + c->sigalgslen = dsize/2; + + for (i = 0, sigptr = c->sigalgs; i < dsize; i += 2, sigptr++) + { + sigptr->rhash = data[i]; + sigptr->rsign = data[i + 1]; + sigptr->hash_nid = tls12_find_nid(sigptr->rhash, tls12_md, + sizeof(tls12_md)/sizeof(tls12_lookup)); + sigptr->sign_nid = tls12_find_nid(sigptr->rsign, tls12_sig, + sizeof(tls12_sig)/sizeof(tls12_lookup)); + if (!OBJ_find_sigid_by_algs(&sigptr->signandhash_nid, + sigptr->hash_nid, + sigptr->sign_nid)) + sigptr->signandhash_nid = NID_undef; + switch(sigptr->rsign) + { +#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; + } + + if (c->pkeys[idx].digest == NULL) + { + md = tls12_get_hash(sigptr->rhash); + if (md) + { + c->pkeys[idx].digest = md; + if (idx == SSL_PKEY_RSA_SIGN) + c->pkeys[SSL_PKEY_RSA_ENC].digest = md; + } + } + } - /* If session decrypt failure indicate a cache miss and set state to - * send a new ticket - */ - tickerr: - s->tlsext_ticket_expected = 1; + + + /* 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_dss1(); +#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(); + } +#endif +#ifndef OPENSSL_NO_ECDSA + if (!c->pkeys[SSL_PKEY_ECC].digest) + c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa(); +#endif + return 1; + } + +#endif + +int SSL_get_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignandhash, + unsigned char *rsig, unsigned char *rhash) + { + if (s->cert->sigalgs == NULL) + return 0; + if (idx >= 0) + { + TLS_SIGALGS *psig; + if (idx >= (int)s->cert->sigalgslen) + return 0; + psig = s->cert->sigalgs + idx; + if (psign) + *psign = psig->sign_nid; + if (phash) + *phash = psig->hash_nid; + if (psignandhash) + *psignandhash = psig->signandhash_nid; + if (rsig) + *rsig = psig->rsign; + if (rhash) + *rhash = psig->rhash; + } + return s->cert->sigalgslen; + } + + +#ifndef OPENSSL_NO_HEARTBEATS +int +tls1_process_heartbeat(SSL *s) + { + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + /* Read type and payload length first */ + hbtype = *p++; + n2s(p, payload); + pl = p; + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, + &s->s3->rrec.data[0], s->s3->rrec.length, + s, s->msg_callback_arg); + + if (hbtype == TLS1_HB_REQUEST) + { + unsigned char *buffer, *bp; + int r; + + /* Allocate memory for the response, size is 1 bytes + * message type, plus 2 bytes payload length, plus + * payload, plus padding + */ + buffer = OPENSSL_malloc(1 + 2 + payload + padding); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buffer, 3 + payload + padding, + s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } + else if (hbtype == TLS1_HB_RESPONSE) + { + unsigned int seq; + + /* We only send sequence numbers (2 bytes unsigned int), + * and 16 random bytes, so we just try to read the + * sequence number */ + n2s(pl, seq); + + if (payload == 18 && seq == s->tlsext_hb_seq) + { + s->tlsext_hb_seq++; + s->tlsext_hb_pending = 0; + } + } + return 0; } +int +tls1_heartbeat(SSL *s) + { + unsigned char *buf, *p; + int ret; + unsigned int payload = 18; /* Sequence number + random bytes */ + unsigned int padding = 16; /* Use minimum padding */ + + /* Only send if peer supports and accepts HB requests... */ + if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || + s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) + { + SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); + return -1; + } + + /* ...and there is none in flight yet... */ + if (s->tlsext_hb_pending) + { + SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING); + return -1; + } + + /* ...and no handshake in progress. */ + if (SSL_in_init(s) || s->in_handshake) + { + SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE); + return -1; + } + + /* Check if padding is too long, payload and padding + * must not exceed 2^14 - 3 = 16381 bytes in total. + */ + OPENSSL_assert(payload + padding <= 16381); + + /* Create HeartBeat message, we just use a sequence number + * as payload to distuingish different messages and add + * some random stuff. + * - Message Type, 1 byte + * - Payload Length, 2 bytes (unsigned int) + * - Payload, the sequence number (2 bytes uint) + * - Payload, random bytes (16 bytes uint) + * - Padding + */ + buf = OPENSSL_malloc(1 + 2 + payload + padding); + p = buf; + /* Message Type */ + *p++ = TLS1_HB_REQUEST; + /* Payload length (18 bytes here) */ + s2n(payload, p); + /* Sequence number */ + s2n(s->tlsext_hb_seq, p); + /* 16 random bytes */ + RAND_pseudo_bytes(p, 16); + p += 16; + /* Random padding */ + RAND_pseudo_bytes(p, padding); + + ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); + if (ret >= 0) + { + if (s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buf, 3 + payload + padding, + s, s->msg_callback_arg); + + s->tlsext_hb_pending = 1; + } + + OPENSSL_free(buf); + + return ret; + } #endif