b81fde02aa
than client side as we need to keep the handshake record cache frozen when it contains all the records need to process the certificate verify message. (backport from HEAD).
2063 lines
56 KiB
C
2063 lines
56 KiB
C
/* ssl/t1_lib.c */
|
|
/* 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 <openssl/objects.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/hmac.h>
|
|
#include <openssl/ocsp.h>
|
|
#include "ssl_locl.h"
|
|
|
|
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
|
|
|
|
#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);
|
|
#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,
|
|
};
|
|
|
|
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) */
|
|
};
|
|
|
|
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;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
#endif /* OPENSSL_NO_EC */
|
|
|
|
#ifndef OPENSSL_NO_TLSEXT
|
|
|
|
int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
|
|
{
|
|
if (p)
|
|
memcpy(p, tls12_sigalgs, sizeof(tls12_sigalgs));
|
|
return (int)sizeof(tls12_sigalgs);
|
|
}
|
|
|
|
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
|
|
{
|
|
int extdatalen=0;
|
|
unsigned char *ret = p;
|
|
|
|
/* 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))
|
|
{
|
|
SSLerr(SSL_F_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))
|
|
{
|
|
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
ret += el;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_SRP
|
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
|
/* we add SRP username the first time only if we have one! */
|
|
if (s->srp_ctx.login != NULL)
|
|
{/* Add TLS extension SRP username to the Client Hello message */
|
|
int login_len = MIN(strlen(s->srp_ctx.login) + 1, 255);
|
|
long lenmax;
|
|
|
|
if ((lenmax = limit - ret - 5) < 0) return NULL;
|
|
if (login_len > lenmax) return NULL;
|
|
if (login_len > 255)
|
|
{
|
|
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
|
|
return NULL;
|
|
}
|
|
s2n(TLSEXT_TYPE_srp,ret);
|
|
s2n(login_len+1,ret);
|
|
|
|
(*ret++) = (unsigned char) MIN(strlen(s->srp_ctx.login), 254);
|
|
memcpy(ret, s->srp_ctx.login, MIN(strlen(s->srp_ctx.login), 254));
|
|
ret+=login_len;
|
|
}
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
if (s->tlsext_ecpointformatlist != NULL &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
/* Add TLS extension ECPointFormats to the ClientHello message */
|
|
long lenmax;
|
|
|
|
if ((lenmax = limit - ret - 5) < 0) return NULL;
|
|
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
|
|
if (s->tlsext_ecpointformatlist_length > 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)
|
|
{
|
|
/* Add TLS extension EllipticCurves to the ClientHello message */
|
|
long lenmax;
|
|
|
|
if ((lenmax = limit - ret - 6) < 0) return NULL;
|
|
if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
|
|
if (s->tlsext_ellipticcurvelist_length > 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);
|
|
|
|
/* 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;
|
|
}
|
|
#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 (s->version >= TLS1_2_VERSION)
|
|
{
|
|
/* List of supported signature algorithms and hashes.
|
|
* Should make this customisable at some point, for
|
|
* now include everything we support.
|
|
*/
|
|
static unsigned char sigalgs[] = {
|
|
#ifndef OPENSSL_NO_RSA
|
|
# ifndef OPENSSL_NO_SHA512
|
|
TLSEXT_hash_sha512, TLSEXT_signature_rsa,
|
|
TLSEXT_hash_sha384, TLSEXT_signature_rsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA256
|
|
TLSEXT_hash_sha256, TLSEXT_signature_rsa,
|
|
TLSEXT_hash_sha224, TLSEXT_signature_rsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA
|
|
TLSEXT_hash_sha1, TLSEXT_signature_rsa,
|
|
# endif
|
|
#endif
|
|
#ifndef OPENSSL_NO_ECDSA
|
|
# ifndef OPENSSL_NO_SHA512
|
|
TLSEXT_hash_sha512, TLSEXT_signature_ecdsa,
|
|
TLSEXT_hash_sha384, TLSEXT_signature_ecdsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA256
|
|
TLSEXT_hash_sha256, TLSEXT_signature_ecdsa,
|
|
TLSEXT_hash_sha224, TLSEXT_signature_ecdsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA
|
|
TLSEXT_hash_sha1, TLSEXT_signature_ecdsa,
|
|
# endif
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
# ifndef OPENSSL_NO_SHA512
|
|
TLSEXT_hash_sha512, TLSEXT_signature_dsa,
|
|
TLSEXT_hash_sha384, TLSEXT_signature_dsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA256
|
|
TLSEXT_hash_sha256, TLSEXT_signature_dsa,
|
|
TLSEXT_hash_sha224, TLSEXT_signature_dsa,
|
|
# endif
|
|
# ifndef OPENSSL_NO_SHA
|
|
TLSEXT_hash_sha1, TLSEXT_signature_dsa
|
|
# endif
|
|
#endif
|
|
};
|
|
if ((size_t)(limit - ret) < sizeof(sigalgs) + 6)
|
|
return NULL;
|
|
s2n(TLSEXT_TYPE_signature_algorithms,ret);
|
|
s2n(sizeof(sigalgs) + 2, ret);
|
|
s2n(sizeof(sigalgs), ret);
|
|
memcpy(ret, sigalgs, sizeof(sigalgs));
|
|
ret += sizeof(sigalgs);
|
|
}
|
|
|
|
#ifdef TLSEXT_TYPE_opaque_prf_input
|
|
if (s->s3->client_opaque_prf_input != NULL &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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
|
|
|
|
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
/* 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))
|
|
{
|
|
SSLerr(SSL_F_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))
|
|
{
|
|
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
ret += el;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
if (s->tlsext_ecpointformatlist != NULL &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
/* Add TLS extension ECPointFormats to the ServerHello message */
|
|
long lenmax;
|
|
|
|
if ((lenmax = limit - ret - 5) < 0) return NULL;
|
|
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
|
|
if (s->tlsext_ecpointformatlist_length > 255)
|
|
{
|
|
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
s2n(TLSEXT_TYPE_ec_point_formats,ret);
|
|
s2n(s->tlsext_ecpointformatlist_length + 1,ret);
|
|
*(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
|
|
memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
|
|
ret+=s->tlsext_ecpointformatlist_length;
|
|
|
|
}
|
|
/* 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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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->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;
|
|
|
|
}
|
|
|
|
if ((extdatalen = ret-p-2)== 0)
|
|
return p;
|
|
|
|
s2n(extdatalen,p);
|
|
return ret;
|
|
}
|
|
|
|
int ssl_parse_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;
|
|
|
|
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_SRP
|
|
else if (type == TLSEXT_TYPE_srp)
|
|
{
|
|
if (size > 0)
|
|
{
|
|
len = data[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';
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
else if (type == TLSEXT_TYPE_ec_point_formats &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
unsigned char *sdata = data;
|
|
int ecpointformatlist_length = *(sdata++);
|
|
|
|
if (ecpointformatlist_length != size - 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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
unsigned char *sdata = data;
|
|
int ellipticcurvelist_length = (*(sdata++) << 8);
|
|
ellipticcurvelist_length += (*(sdata++));
|
|
|
|
if (ellipticcurvelist_length != size - 2)
|
|
{
|
|
*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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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 (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)
|
|
{
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* session ticket processed earlier */
|
|
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;
|
|
SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
|
|
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ssl_parse_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;
|
|
|
|
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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
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 &&
|
|
s->version != DTLS1_VERSION)
|
|
{
|
|
/* 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;
|
|
}
|
|
else if (type == TLSEXT_TYPE_renegotiate)
|
|
{
|
|
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
|
|
return 0;
|
|
renegotiate_seen = 1;
|
|
}
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*al = SSL_AD_DECODE_ERROR;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
*p = data;
|
|
|
|
ri_check:
|
|
|
|
/* Determine if we need to see RI. Strictly speaking if we want to
|
|
* avoid an attack we should *always* see RI even on initial server
|
|
* hello because the client doesn't see any renegotiation during an
|
|
* attack. However this would mean we could not connect to any server
|
|
* which doesn't support RI so for the immediate future tolerate RI
|
|
* absence on initial connect only.
|
|
*/
|
|
if (!renegotiate_seen
|
|
&& !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
|
|
&& !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
|
|
{
|
|
*al = SSL_AD_HANDSHAKE_FAILURE;
|
|
SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
|
|
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
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
|
|
{
|
|
int r = 1;
|
|
|
|
if (s->ctx->tlsext_opaque_prf_input_callback != 0)
|
|
{
|
|
r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
|
|
if (!r)
|
|
return -1;
|
|
}
|
|
|
|
if (s->tlsext_opaque_prf_input != NULL)
|
|
{
|
|
if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
|
|
OPENSSL_free(s->s3->client_opaque_prf_input);
|
|
|
|
if (s->tlsext_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(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
|
|
if (s->s3->client_opaque_prf_input == NULL)
|
|
{
|
|
SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
|
|
}
|
|
|
|
if (r == 2)
|
|
/* at callback's request, insist on receiving an appropriate server opaque PRF input */
|
|
s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
|
|
}
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ssl_prepare_serverhello_tlsext(SSL *s)
|
|
{
|
|
#ifndef OPENSSL_NO_EC
|
|
/* If we are server and using an ECC cipher suite, send the point formats we support
|
|
* if the client sent us an ECPointsFormat extension. Note that the server is not
|
|
* supposed to send an EllipticCurves extension.
|
|
*/
|
|
|
|
unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
|
|
unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
|
|
int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
|
|
using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
|
|
|
|
if (using_ecc)
|
|
{
|
|
if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
|
|
if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
|
|
{
|
|
SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
s->tlsext_ecpointformatlist_length = 3;
|
|
s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
|
|
s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
|
|
s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
|
|
}
|
|
#endif /* OPENSSL_NO_EC */
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ssl_check_clienthello_tlsext(SSL *s)
|
|
{
|
|
int ret=SSL_TLSEXT_ERR_NOACK;
|
|
int al = SSL_AD_UNRECOGNIZED_NAME;
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
/* The handling of the ECPointFormats extension is done elsewhere, namely in
|
|
* ssl3_choose_cipher in s3_lib.c.
|
|
*/
|
|
/* The handling of the EllipticCurves extension is done elsewhere, namely in
|
|
* ssl3_choose_cipher in s3_lib.c.
|
|
*/
|
|
#endif
|
|
|
|
if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
|
|
ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
|
|
else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
|
|
ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
|
|
|
|
/* If status request then ask callback what to do.
|
|
* Note: this must be called after servername callbacks in case
|
|
* the certificate has changed.
|
|
*/
|
|
if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
|
|
{
|
|
int r;
|
|
r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
|
|
switch (r)
|
|
{
|
|
/* We don't want to send a status request response */
|
|
case SSL_TLSEXT_ERR_NOACK:
|
|
s->tlsext_status_expected = 0;
|
|
break;
|
|
/* status request response should be sent */
|
|
case SSL_TLSEXT_ERR_OK:
|
|
if (s->tlsext_ocsp_resp)
|
|
s->tlsext_status_expected = 1;
|
|
else
|
|
s->tlsext_status_expected = 0;
|
|
break;
|
|
/* something bad happened */
|
|
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_INTERNAL_ERROR;
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
s->tlsext_status_expected = 0;
|
|
|
|
#ifdef TLSEXT_TYPE_opaque_prf_input
|
|
{
|
|
/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
|
|
* but we might be sending an alert in response to the client hello,
|
|
* so this has to happen here in ssl_check_clienthello_tlsext(). */
|
|
|
|
int r = 1;
|
|
|
|
if (s->ctx->tlsext_opaque_prf_input_callback != 0)
|
|
{
|
|
r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
|
|
if (!r)
|
|
{
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_INTERNAL_ERROR;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
|
|
OPENSSL_free(s->s3->server_opaque_prf_input);
|
|
s->s3->server_opaque_prf_input = NULL;
|
|
|
|
if (s->tlsext_opaque_prf_input != NULL)
|
|
{
|
|
if (s->s3->client_opaque_prf_input != NULL &&
|
|
s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
|
|
{
|
|
/* can only use this extension if we have a server opaque PRF input
|
|
* of the same length as the client opaque PRF input! */
|
|
|
|
if (s->tlsext_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(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
|
|
if (s->s3->server_opaque_prf_input == NULL)
|
|
{
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_INTERNAL_ERROR;
|
|
goto err;
|
|
}
|
|
s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
|
|
}
|
|
}
|
|
|
|
if (r == 2 && s->s3->server_opaque_prf_input == NULL)
|
|
{
|
|
/* The callback wants to enforce use of the extension,
|
|
* but we can't do that with the client opaque PRF input;
|
|
* abort the handshake.
|
|
*/
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_HANDSHAKE_FAILURE;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
err:
|
|
switch (ret)
|
|
{
|
|
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
|
ssl3_send_alert(s,SSL3_AL_FATAL,al);
|
|
return -1;
|
|
|
|
case SSL_TLSEXT_ERR_ALERT_WARNING:
|
|
ssl3_send_alert(s,SSL3_AL_WARNING,al);
|
|
return 1;
|
|
|
|
case SSL_TLSEXT_ERR_NOACK:
|
|
s->servername_done=0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int ssl_check_serverhello_tlsext(SSL *s)
|
|
{
|
|
int ret=SSL_TLSEXT_ERR_NOACK;
|
|
int al = SSL_AD_UNRECOGNIZED_NAME;
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
/* 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;
|
|
list = s->session->tlsext_ecpointformatlist;
|
|
for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
|
|
{
|
|
if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
|
|
{
|
|
found_uncompressed = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found_uncompressed)
|
|
{
|
|
SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
|
|
return -1;
|
|
}
|
|
}
|
|
ret = SSL_TLSEXT_ERR_OK;
|
|
#endif /* OPENSSL_NO_EC */
|
|
|
|
if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
|
|
ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
|
|
else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
|
|
ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
|
|
|
|
#ifdef TLSEXT_TYPE_opaque_prf_input
|
|
if (s->s3->server_opaque_prf_input_len > 0)
|
|
{
|
|
/* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
|
|
* So first verify that we really have a value from the server too. */
|
|
|
|
if (s->s3->server_opaque_prf_input == NULL)
|
|
{
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_HANDSHAKE_FAILURE;
|
|
}
|
|
|
|
/* Anytime the server *has* sent an opaque PRF input, we need to check
|
|
* that we have a client opaque PRF input of the same size. */
|
|
if (s->s3->client_opaque_prf_input == NULL ||
|
|
s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
|
|
{
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
al = SSL_AD_ILLEGAL_PARAMETER;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* If we've requested certificate status and we wont get one
|
|
* tell the callback
|
|
*/
|
|
if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
|
|
&& s->ctx && s->ctx->tlsext_status_cb)
|
|
{
|
|
int r;
|
|
/* Set resp to NULL, resplen to -1 so callback knows
|
|
* there is no response.
|
|
*/
|
|
if (s->tlsext_ocsp_resp)
|
|
{
|
|
OPENSSL_free(s->tlsext_ocsp_resp);
|
|
s->tlsext_ocsp_resp = NULL;
|
|
}
|
|
s->tlsext_ocsp_resplen = -1;
|
|
r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
|
|
if (r == 0)
|
|
{
|
|
al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
}
|
|
if (r < 0)
|
|
{
|
|
al = SSL_AD_INTERNAL_ERROR;
|
|
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
}
|
|
}
|
|
|
|
switch (ret)
|
|
{
|
|
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
|
ssl3_send_alert(s,SSL3_AL_FATAL,al);
|
|
return -1;
|
|
|
|
case SSL_TLSEXT_ERR_ALERT_WARNING:
|
|
ssl3_send_alert(s,SSL3_AL_WARNING,al);
|
|
return 1;
|
|
|
|
case SSL_TLSEXT_ERR_NOACK:
|
|
s->servername_done=0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* 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 tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
|
|
const unsigned char *limit, SSL_SESSION **ret)
|
|
{
|
|
/* Point after session ID in client hello */
|
|
const unsigned char *p = session_id + len;
|
|
unsigned short i;
|
|
|
|
/* If tickets disabled behave as if no ticket present
|
|
* to permit stateful resumption.
|
|
*/
|
|
if (SSL_get_options(s) & SSL_OP_NO_TICKET)
|
|
return 1;
|
|
|
|
if ((s->version <= SSL3_VERSION) || !limit)
|
|
return 1;
|
|
if (p >= limit)
|
|
return -1;
|
|
/* Skip past DTLS cookie */
|
|
if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
|
|
{
|
|
i = *(p++);
|
|
p+= i;
|
|
if (p >= limit)
|
|
return -1;
|
|
}
|
|
/* Skip past cipher list */
|
|
n2s(p, i);
|
|
p+= i;
|
|
if (p >= limit)
|
|
return -1;
|
|
/* Skip past compression algorithm list */
|
|
i = *(p++);
|
|
p += i;
|
|
if (p > limit)
|
|
return -1;
|
|
/* Now at start of extensions */
|
|
if ((p + 2) >= limit)
|
|
return 1;
|
|
n2s(p, i);
|
|
while ((p + 4) <= limit)
|
|
{
|
|
unsigned short type, size;
|
|
n2s(p, type);
|
|
n2s(p, size);
|
|
if (p + size > limit)
|
|
return 1;
|
|
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
|
|
*/
|
|
if (size == 0)
|
|
{
|
|
s->tlsext_ticket_expected = 1;
|
|
return 0; /* Cache miss */
|
|
}
|
|
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;
|
|
}
|
|
return tls_decrypt_ticket(s, p, size, session_id, len,
|
|
ret);
|
|
}
|
|
p += size;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
|
|
const unsigned char *sess_id, int sesslen,
|
|
SSL_SESSION **psess)
|
|
{
|
|
SSL_SESSION *sess;
|
|
unsigned char *sdec;
|
|
const unsigned char *p;
|
|
int slen, mlen, renew_ticket = 0;
|
|
unsigned char tick_hmac[EVP_MAX_MD_SIZE];
|
|
HMAC_CTX hctx;
|
|
EVP_CIPHER_CTX ctx;
|
|
SSL_CTX *tctx = s->initial_ctx;
|
|
/* Need at least keyname + iv + some encrypted data */
|
|
if (eticklen < 48)
|
|
goto tickerr;
|
|
/* Initialize session ticket encryption and HMAC contexts */
|
|
HMAC_CTX_init(&hctx);
|
|
EVP_CIPHER_CTX_init(&ctx);
|
|
if (tctx->tlsext_ticket_key_cb)
|
|
{
|
|
unsigned char *nctick = (unsigned char *)etick;
|
|
int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
|
|
&ctx, &hctx, 0);
|
|
if (rv < 0)
|
|
return -1;
|
|
if (rv == 0)
|
|
goto tickerr;
|
|
if (rv == 2)
|
|
renew_ticket = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Check key name matches */
|
|
if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
|
|
goto tickerr;
|
|
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.
|
|
*/
|
|
mlen = HMAC_size(&hctx);
|
|
if (mlen < 0)
|
|
{
|
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
|
return -1;
|
|
}
|
|
eticklen -= mlen;
|
|
/* Check HMAC of encrypted ticket */
|
|
HMAC_Update(&hctx, etick, eticklen);
|
|
HMAC_Final(&hctx, tick_hmac, NULL);
|
|
HMAC_CTX_cleanup(&hctx);
|
|
if (memcmp(tick_hmac, etick + eticklen, mlen))
|
|
goto tickerr;
|
|
/* 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);
|
|
eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
|
|
sdec = OPENSSL_malloc(eticklen);
|
|
if (!sdec)
|
|
{
|
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
|
return -1;
|
|
}
|
|
EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
|
|
if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
|
|
goto tickerr;
|
|
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.
|
|
*/
|
|
if (sesslen)
|
|
memcpy(sess->session_id, sess_id, sesslen);
|
|
sess->session_id_length = sesslen;
|
|
*psess = sess;
|
|
s->tlsext_ticket_expected = renew_ticket;
|
|
return 1;
|
|
}
|
|
/* If session decrypt failure indicate a cache miss and set state to
|
|
* send a new ticket
|
|
*/
|
|
tickerr:
|
|
s->tlsext_ticket_expected = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Tables to translate from NIDs to TLS v1.2 ids */
|
|
|
|
typedef struct
|
|
{
|
|
int nid;
|
|
int id;
|
|
} tls12_lookup;
|
|
|
|
static tls12_lookup tls12_md[] = {
|
|
#ifndef OPENSSL_NO_MD5
|
|
{NID_md5, TLSEXT_hash_md5},
|
|
#endif
|
|
#ifndef OPENSSL_NO_SHA
|
|
{NID_sha1, TLSEXT_hash_sha1},
|
|
#endif
|
|
#ifndef OPENSSL_NO_SHA256
|
|
{NID_sha224, TLSEXT_hash_sha224},
|
|
{NID_sha256, TLSEXT_hash_sha256},
|
|
#endif
|
|
#ifndef OPENSSL_NO_SHA512
|
|
{NID_sha384, TLSEXT_hash_sha384},
|
|
{NID_sha512, TLSEXT_hash_sha512}
|
|
#endif
|
|
};
|
|
|
|
static tls12_lookup tls12_sig[] = {
|
|
#ifndef OPENSSL_NO_RSA
|
|
{EVP_PKEY_RSA, TLSEXT_signature_rsa},
|
|
#endif
|
|
#ifndef OPENSSL_NO_RSA
|
|
{EVP_PKEY_DSA, TLSEXT_signature_dsa},
|
|
#endif
|
|
#ifndef OPENSSL_NO_ECDSA
|
|
{EVP_PKEY_EC, TLSEXT_signature_ecdsa}
|
|
#endif
|
|
};
|
|
|
|
static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < tlen; i++)
|
|
{
|
|
if (table[i].nid == nid)
|
|
return table[i].id;
|
|
}
|
|
return -1;
|
|
}
|
|
#if 0
|
|
static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < tlen; i++)
|
|
{
|
|
if (table[i].id == id)
|
|
return table[i].nid;
|
|
}
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
|
|
{
|
|
int sig_id, md_id;
|
|
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:
|
|
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;
|
|
/* Extension ignored for TLS versions below 1.2 */
|
|
if (s->version < 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;
|
|
|
|
for (i = 0; i < dsize; i += 2)
|
|
{
|
|
unsigned char hash_alg = data[i], sig_alg = data[i+1];
|
|
|
|
switch(sig_alg)
|
|
{
|
|
#ifndef OPENSSL_NO_RSA
|
|
case TLSEXT_signature_rsa:
|
|
idx = SSL_PKEY_RSA_SIGN;
|
|
break;
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
case TLSEXT_signature_dsa:
|
|
idx = SSL_PKEY_DSA_SIGN;
|
|
break;
|
|
#endif
|
|
#ifndef OPENSSL_NO_ECDSA
|
|
case TLSEXT_signature_ecdsa:
|
|
idx = SSL_PKEY_ECC;
|
|
break;
|
|
#endif
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
if (c->pkeys[idx].digest == NULL)
|
|
{
|
|
md = tls12_get_hash(hash_alg);
|
|
if (md)
|
|
{
|
|
c->pkeys[idx].digest = md;
|
|
if (idx == SSL_PKEY_RSA_SIGN)
|
|
c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* 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
|