Implement the Opaque PRF Input TLS extension
(draft-rescorla-tls-opaque-prf-input-00.txt), and do some cleanups and bugfixes on the way. In particular, this fixes the buffer bounds checks in ssl_add_clienthello_tlsext() and in ssl_add_serverhello_tlsext(). Note that the opaque PRF Input TLS extension is not compiled by default; see CHANGES.
This commit is contained in:
parent
54ef01b54b
commit
761772d7e1
16 changed files with 544 additions and 89 deletions
58
CHANGES
58
CHANGES
|
@ -4,6 +4,64 @@
|
|||
|
||||
Changes between 0.9.8f and 0.9.9 [xx XXX xxxx]
|
||||
|
||||
*) Implement Opaque PRF Input TLS extension as specified in
|
||||
draft-rescorla-tls-opaque-prf-input-00.txt. Since this is not an
|
||||
official specification yet and no extension type assignment by
|
||||
IANA exists, this extension (for now) will have to be explicitly
|
||||
enabled when building OpenSSL by providing the extension number
|
||||
to use. For example, specify an option
|
||||
|
||||
-DTLSEXT_TYPE_opaque_prf_input=0x9527
|
||||
|
||||
to the "config" or "Configure" script to enable the extension,
|
||||
assuming extension number 0x9527 (which is a completely arbitrary
|
||||
and unofficial assignment based on the MD5 hash of the Internet
|
||||
Draft). Note that by doing so, you potentially lose
|
||||
interoperability with other TLS implementations since these might
|
||||
be using the same extension number for other purposes.
|
||||
|
||||
SSL_set_tlsext_opaque_prf_input(ssl, src, len) is used to set the
|
||||
opaque PRF input value to use in the handshake. This will create
|
||||
an interal copy of the length-'len' string at 'src', and will
|
||||
return non-zero for success.
|
||||
|
||||
To get more control and flexibility, provide a callback function
|
||||
by using
|
||||
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb)
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg)
|
||||
|
||||
where
|
||||
|
||||
int (*cb)(SSL *, void *peerinput, size_t len, void *arg);
|
||||
void *arg;
|
||||
|
||||
Callback function 'cb' will be called in handshakes, and is
|
||||
expected to use SSL_set_tlsext_opaque_prf_input() as appropriate.
|
||||
Argument 'arg' is for application purposes (the value as given to
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg() will directly
|
||||
be provided to the callback function). The callback function
|
||||
has to return non-zero to report success: usually 1 to use opaque
|
||||
PRF input just if possible, or 2 to enforce use of the opaque PRF
|
||||
input. In the latter case, the library will abort the handshake
|
||||
if opaque PRF input is not successfully negotiated.
|
||||
|
||||
Arguments 'peerinput' and 'len' given to the callback function
|
||||
will always be NULL and 0 in the case of a client. A server will
|
||||
see the client's opaque PRF input through these variables if
|
||||
available (NULL and 0 otherwise). Note that if the server
|
||||
provides an opaque PRF input, the length must be the same as the
|
||||
length of the client's opaque PRF input.
|
||||
|
||||
Note that the callback function will only be called when creating
|
||||
a new session (session resumption can resume whatever was
|
||||
previously negotiated), and will not be called in SSL 2.0
|
||||
handshakes; thus, SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) or
|
||||
SSL_set_options(ssl, SSL_OP_NO_SSLv2) is especially recommended
|
||||
for applications that need to enforce opaque PRF input.
|
||||
|
||||
[Bodo Moeller]
|
||||
|
||||
*) Update ssl code to support digests other than SHA1+MD5 for handshake
|
||||
MAC.
|
||||
|
||||
|
|
|
@ -638,6 +638,11 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
|
|||
extname = "server ticket";
|
||||
break;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
case TLSEXT_TYPE_opaque_prf_input:
|
||||
extname = "opaque PRF input";
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
extname = "unknown";
|
||||
|
|
|
@ -859,6 +859,11 @@ bad:
|
|||
}
|
||||
#endif /* OPENSSL_NO_KRB5 */
|
||||
/* SSL_set_cipher_list(con,"RC4-MD5"); */
|
||||
#if 0
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
SSL_set_tlsext_opaque_prf_input(con, "Test client", 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
re_start:
|
||||
|
||||
|
@ -1073,11 +1078,13 @@ re_start:
|
|||
if (in_init)
|
||||
{
|
||||
in_init=0;
|
||||
#if 0 /* This test doesn't really work as intended (needs to be fixed) */
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
if (servername != NULL && !SSL_session_reused(con))
|
||||
{
|
||||
BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if (sess_out)
|
||||
{
|
||||
|
|
|
@ -1575,6 +1575,11 @@ static int sv_body(char *hostname, int s, unsigned char *context)
|
|||
strlen((char *)context));
|
||||
}
|
||||
SSL_clear(con);
|
||||
#if 0
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
SSL_set_tlsext_opaque_prf_input(con, "Test server", 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (SSL_version(con) == DTLS1_VERSION)
|
||||
{
|
||||
|
|
|
@ -277,6 +277,19 @@ static int ssl23_client_hello(SSL *s)
|
|||
version = SSL2_VERSION;
|
||||
}
|
||||
|
||||
if (version != SSL2_VERSION)
|
||||
{
|
||||
/* have to disable SSL 2.0 compatibility if we need TLS extensions */
|
||||
|
||||
if (s->tlsext_hostname != NULL)
|
||||
ssl2_compat = 0;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
|
||||
ssl2_compat = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
buf=(unsigned char *)s->init_buf->data;
|
||||
if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
|
||||
{
|
||||
|
@ -420,6 +433,12 @@ static int ssl23_client_hello(SSL *s)
|
|||
*(p++)=0; /* Add the NULL method */
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* TLS extensions*/
|
||||
if (ssl_prepare_clienthello_tlsext(s) <= 0)
|
||||
{
|
||||
SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
|
||||
return -1;
|
||||
}
|
||||
if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
|
||||
{
|
||||
SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
|
||||
|
|
|
@ -656,7 +656,9 @@ int ssl3_client_hello(SSL *s)
|
|||
}
|
||||
#endif
|
||||
*(p++)=0; /* Add the NULL method */
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* TLS extensions*/
|
||||
if (ssl_prepare_clienthello_tlsext(s) <= 0)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
|
||||
|
@ -853,6 +855,7 @@ int ssl3_get_server_hello(SSL *s)
|
|||
s->s3->tmp.new_compression=comp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
/* TLS extensions*/
|
||||
if (s->version > SSL3_VERSION)
|
||||
|
@ -1768,7 +1771,7 @@ int ssl3_get_new_session_ticket(SSL *s)
|
|||
if (ticklen + 6 != n)
|
||||
{
|
||||
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
|
||||
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
|
||||
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
|
||||
goto f_err;
|
||||
}
|
||||
if (s->session->tlsext_tick)
|
||||
|
@ -1779,7 +1782,7 @@ int ssl3_get_new_session_ticket(SSL *s)
|
|||
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||
if (!s->session->tlsext_tick)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
|
||||
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
memcpy(s->session->tlsext_tick, p, ticklen);
|
||||
|
|
55
ssl/s3_lib.c
55
ssl/s3_lib.c
|
@ -2083,6 +2083,13 @@ void ssl3_free(SSL *s)
|
|||
if(s == NULL)
|
||||
return;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->s3->client_opaque_prf_input != NULL)
|
||||
OPENSSL_free(s->s3->client_opaque_prf_input);
|
||||
if (s->s3->server_opaque_prf_input != NULL)
|
||||
OPENSSL_free(s->s3->server_opaque_prf_input);
|
||||
#endif
|
||||
|
||||
ssl3_cleanup_key_block(s);
|
||||
if (s->s3->rbuf.buf != NULL)
|
||||
OPENSSL_free(s->s3->rbuf.buf);
|
||||
|
@ -2115,6 +2122,15 @@ void ssl3_clear(SSL *s)
|
|||
unsigned char *rp,*wp;
|
||||
size_t rlen, wlen;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->s3->client_opaque_prf_input != NULL)
|
||||
OPENSSL_free(s->s3->client_opaque_prf_input);
|
||||
s->s3->client_opaque_prf_input = NULL;
|
||||
if (s->s3->server_opaque_prf_input != NULL)
|
||||
OPENSSL_free(s->s3->server_opaque_prf_input);
|
||||
s->s3->server_opaque_prf_input = NULL;
|
||||
#endif
|
||||
|
||||
ssl3_cleanup_key_block(s);
|
||||
if (s->s3->tmp.ca_names != NULL)
|
||||
sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
|
||||
|
@ -2337,11 +2353,33 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
|
|||
SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
|
||||
return 0;
|
||||
}
|
||||
s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
|
||||
break;
|
||||
case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
|
||||
s->tlsext_debug_arg=parg;
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT:
|
||||
if (larg > 12288) /* actual internal limit is 2^16 for the complete hello message
|
||||
* (including the cert chain and everything) */
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_CTRL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG);
|
||||
break;
|
||||
}
|
||||
if (s->tlsext_opaque_prf_input != NULL)
|
||||
OPENSSL_free(s->tlsext_opaque_prf_input);
|
||||
s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg);
|
||||
if (s->tlsext_opaque_prf_input != NULL)
|
||||
{
|
||||
s->tlsext_opaque_prf_input_len = (size_t)larg;
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
s->tlsext_opaque_prf_input_len = 0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
default:
|
||||
break;
|
||||
|
@ -2562,7 +2600,15 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG:
|
||||
ctx->tlsext_opaque_prf_input_callback_arg = parg;
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
|
||||
/* A Thawte special :-) */
|
||||
case SSL_CTRL_EXTRA_CHAIN_CERT:
|
||||
if (ctx->extra_certs == NULL)
|
||||
|
@ -2612,6 +2658,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
|
|||
case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
|
||||
ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
|
||||
break;
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB:
|
||||
ctx->tlsext_opaque_prf_input_callback = (int (*)(SSL *,void *, size_t, void *))fp;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
default:
|
||||
return(0);
|
||||
|
|
16
ssl/ssl.h
16
ssl/ssl.h
|
@ -799,7 +799,12 @@ struct ssl_ctx_st
|
|||
unsigned char tlsext_tick_key_name[16];
|
||||
unsigned char tlsext_tick_hmac_key[16];
|
||||
unsigned char tlsext_tick_aes_key[16];
|
||||
|
||||
/* draft-rescorla-tls-opaque-prf-input-00.txt information */
|
||||
int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
|
||||
void *tlsext_opaque_prf_input_callback_arg;
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
char *psk_identity_hint;
|
||||
unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
|
||||
|
@ -1086,11 +1091,16 @@ struct ssl_st
|
|||
size_t tlsext_ellipticcurvelist_length;
|
||||
unsigned char *tlsext_ellipticcurvelist; /* our list */
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
/* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
|
||||
void *tlsext_opaque_prf_input;
|
||||
size_t tlsext_opaque_prf_input_len;
|
||||
|
||||
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
|
||||
#define session_ctx initial_ctx
|
||||
#else
|
||||
#define session_ctx ctx
|
||||
#endif
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1304,6 +1314,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
|
|||
#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
|
||||
#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
|
||||
#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
|
||||
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
|
||||
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
|
||||
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
|
||||
#endif
|
||||
|
||||
#define SSL_session_reused(ssl) \
|
||||
|
@ -2009,6 +2022,7 @@ void ERR_load_SSL_strings(void);
|
|||
#define SSL_R_NULL_SSL_METHOD_PASSED 196
|
||||
#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
|
||||
#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297
|
||||
#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327
|
||||
#define SSL_R_PACKET_LENGTH_TOO_LONG 198
|
||||
#define SSL_R_PARSE_TLSEXT 227
|
||||
#define SSL_R_PATH_TOO_LONG 270
|
||||
|
|
|
@ -443,6 +443,14 @@ typedef struct ssl3_state_st
|
|||
|
||||
int in_read_app_data;
|
||||
|
||||
/* Opaque PRF input as used for the current handshake.
|
||||
* These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
|
||||
* (otherwise, they are merely present to improve binary compatibility) */
|
||||
void *client_opaque_prf_input;
|
||||
size_t client_opaque_prf_input_len;
|
||||
void *server_opaque_prf_input;
|
||||
size_t server_opaque_prf_input_len;
|
||||
|
||||
struct {
|
||||
/* actually only needs to be 16+20 */
|
||||
unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
|
||||
|
|
|
@ -249,13 +249,13 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
|||
{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
|
||||
{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "SSL_VERIFY_CERT_CHAIN"},
|
||||
{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
|
||||
{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
|
||||
{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "TLS1_CERT_VERIFY_MAC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"},
|
||||
{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
|
||||
{ERR_FUNC(SSL_F_TLS1_PRF), "TLS1_PRF"},
|
||||
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
|
||||
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
|
||||
{0,NULL}
|
||||
|
@ -399,6 +399,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
|
|||
{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
|
||||
{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
|
||||
{ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
|
||||
{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
|
||||
{ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
|
||||
{ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"},
|
||||
{ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"},
|
||||
|
|
|
@ -542,6 +542,7 @@ void SSL_free(SSL *s)
|
|||
if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
|
||||
if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
|
||||
#endif
|
||||
|
||||
if (s->client_CA != NULL)
|
||||
|
|
|
@ -330,24 +330,30 @@
|
|||
#define SSL_SSLV3 0x00000002L
|
||||
#define SSL_TLSV1 SSL_SSLV3 /* for now */
|
||||
|
||||
/* Bits for algorithm2 (handshake digests) */
|
||||
|
||||
/* Bits for algorithm2 (handshake digests and other extra flags) */
|
||||
|
||||
#define SSL_HANDSHAKE_MAC_MD5 0x10
|
||||
#define SSL_HANDSHAKE_MAC_SHA 0x20
|
||||
#define SSL_HANDSHAKE_MAC_GOST94 0x40
|
||||
#define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)
|
||||
|
||||
|
||||
/* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX
|
||||
* make sure to update this constant too */
|
||||
#define SSL_MAX_DIGEST 4
|
||||
|
||||
|
||||
#define TLS1_PRF_DGST_SHIFT 8
|
||||
#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
|
||||
#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT)
|
||||
#define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
|
||||
#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
|
||||
|
||||
/* Stream MAC for GOST ciphersuites from cryptopro draft
|
||||
* (currently this also goes into algorithm2) */
|
||||
#define TLS1_STREAM_MAC 0x04
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Export and cipher strength information. For each cipher we have to decide
|
||||
* whether it is exportable or not. This information is likely to change
|
||||
|
|
|
@ -422,6 +422,25 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
struct cb_info_st { void *input; size_t len; int ret; };
|
||||
struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */
|
||||
struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */
|
||||
struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */
|
||||
struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */
|
||||
|
||||
int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
|
||||
{
|
||||
struct cb_info_st *arg = arg_;
|
||||
|
||||
if (arg == NULL)
|
||||
return 1;
|
||||
|
||||
if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len))
|
||||
return 0;
|
||||
return arg->ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -836,6 +855,13 @@ bad:
|
|||
SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
|
||||
#endif
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb);
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb);
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */
|
||||
SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */
|
||||
#endif
|
||||
|
||||
if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM))
|
||||
{
|
||||
ERR_print_errors(bio_err);
|
||||
|
|
163
ssl/t1_enc.c
163
ssl/t1_enc.c
|
@ -142,8 +142,14 @@
|
|||
#include <openssl/hmac.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/* seed1 through seed5 are virtually concatenated */
|
||||
static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
||||
int sec_len, unsigned char *seed, int seed_len,
|
||||
int sec_len,
|
||||
const void *seed1, int seed1_len,
|
||||
const void *seed2, int seed2_len,
|
||||
const void *seed3, int seed3_len,
|
||||
const void *seed4, int seed4_len,
|
||||
const void *seed5, int seed5_len,
|
||||
unsigned char *out, int olen)
|
||||
{
|
||||
int chunk,n;
|
||||
|
@ -159,7 +165,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
|||
HMAC_CTX_init(&ctx_tmp);
|
||||
HMAC_Init_ex(&ctx,sec,sec_len,md, NULL);
|
||||
HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL);
|
||||
HMAC_Update(&ctx,seed,seed_len);
|
||||
if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
|
||||
if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
|
||||
if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
|
||||
if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
|
||||
if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
|
||||
HMAC_Final(&ctx,A1,&A1_len);
|
||||
|
||||
n=0;
|
||||
|
@ -169,7 +179,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
|||
HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */
|
||||
HMAC_Update(&ctx,A1,A1_len);
|
||||
HMAC_Update(&ctx_tmp,A1,A1_len);
|
||||
HMAC_Update(&ctx,seed,seed_len);
|
||||
if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
|
||||
if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
|
||||
if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
|
||||
if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
|
||||
if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
|
||||
|
||||
if (olen > chunk)
|
||||
{
|
||||
|
@ -190,9 +204,15 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
|||
OPENSSL_cleanse(A1,sizeof(A1));
|
||||
}
|
||||
|
||||
/* seed1 through seed5 are virtually concatenated */
|
||||
static void tls1_PRF(long digest_mask,
|
||||
unsigned char *label, int label_len,
|
||||
const unsigned char *sec, int slen, unsigned char *out1,
|
||||
const void *seed1, int seed1_len,
|
||||
const void *seed2, int seed2_len,
|
||||
const void *seed3, int seed3_len,
|
||||
const void *seed4, int seed4_len,
|
||||
const void *seed5, int seed5_len,
|
||||
const unsigned char *sec, int slen,
|
||||
unsigned char *out1,
|
||||
unsigned char *out2, int olen)
|
||||
{
|
||||
int len,i,idx,count;
|
||||
|
@ -200,7 +220,7 @@ static void tls1_PRF(long digest_mask,
|
|||
long m;
|
||||
const EVP_MD *md;
|
||||
|
||||
/* Count number of digests and divide sec evenly */
|
||||
/* Count number of digests and partition sec evenly */
|
||||
count=0;
|
||||
for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
|
||||
if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
|
||||
|
@ -215,7 +235,9 @@ static void tls1_PRF(long digest_mask,
|
|||
SSL_R_UNSUPPORTED_DIGEST_TYPE);
|
||||
return;
|
||||
}
|
||||
tls1_P_hash(md ,S1,len+(slen&1),label,label_len,out2,olen);
|
||||
tls1_P_hash(md ,S1,len+(slen&1),
|
||||
seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
|
||||
out2,olen);
|
||||
S1+=len;
|
||||
for (i=0; i<olen; i++)
|
||||
{
|
||||
|
@ -228,20 +250,11 @@ static void tls1_PRF(long digest_mask,
|
|||
static void tls1_generate_key_block(SSL *s, unsigned char *km,
|
||||
unsigned char *tmp, int num)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned char buf[SSL3_RANDOM_SIZE*2+
|
||||
TLS_MD_MAX_CONST_SIZE];
|
||||
p=buf;
|
||||
|
||||
memcpy(p,TLS_MD_KEY_EXPANSION_CONST,
|
||||
TLS_MD_KEY_EXPANSION_CONST_SIZE);
|
||||
p+=TLS_MD_KEY_EXPANSION_CONST_SIZE;
|
||||
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
|
||||
TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
NULL,0,NULL,0,
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
km,tmp,num);
|
||||
#ifdef KSSL_DEBUG
|
||||
|
@ -261,8 +274,7 @@ int tls1_change_cipher_state(SSL *s, int which)
|
|||
{
|
||||
static const unsigned char empty[]="";
|
||||
unsigned char *p,*key_block,*mac_secret;
|
||||
unsigned char *exp_label,buf[TLS_MD_MAX_CONST_SIZE+
|
||||
SSL3_RANDOM_SIZE*2];
|
||||
unsigned char *exp_label;
|
||||
unsigned char tmp1[EVP_MAX_KEY_LENGTH];
|
||||
unsigned char tmp2[EVP_MAX_KEY_LENGTH];
|
||||
unsigned char iv1[EVP_MAX_IV_LENGTH*2];
|
||||
|
@ -443,29 +455,22 @@ printf("which = %04X\nmac key=",which);
|
|||
/* In here I set both the read and write key/iv to the
|
||||
* same value since only the correct one will be used :-).
|
||||
*/
|
||||
p=buf;
|
||||
memcpy(p,exp_label,exp_label_len);
|
||||
p+=exp_label_len;
|
||||
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),key,j,
|
||||
tmp1,tmp2,EVP_CIPHER_key_length(c));
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
|
||||
exp_label,exp_label_len,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
NULL,0,NULL,0,
|
||||
key,j,tmp1,tmp2,EVP_CIPHER_key_length(c));
|
||||
key=tmp1;
|
||||
|
||||
if (k > 0)
|
||||
{
|
||||
p=buf;
|
||||
memcpy(p,TLS_MD_IV_BLOCK_CONST,
|
||||
TLS_MD_IV_BLOCK_CONST_SIZE);
|
||||
p+=TLS_MD_IV_BLOCK_CONST_SIZE;
|
||||
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
|
||||
p+=SSL3_RANDOM_SIZE;
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,p-buf,empty,0,
|
||||
iv1,iv2,k*2);
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
|
||||
TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
NULL,0,NULL,0,
|
||||
empty,0,iv1,iv2,k*2);
|
||||
if (client_write)
|
||||
iv=iv1;
|
||||
else
|
||||
|
@ -767,35 +772,51 @@ int tls1_final_finish_mac(SSL *s,
|
|||
{
|
||||
unsigned int i;
|
||||
EVP_MD_CTX ctx;
|
||||
unsigned char buf[TLS_MD_MAX_CONST_SIZE+MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
|
||||
unsigned char buf[2*EVP_MAX_MD_SIZE];
|
||||
unsigned char *q,buf2[12];
|
||||
int idx;
|
||||
long mask;
|
||||
int err=0;
|
||||
const EVP_MD *md;
|
||||
|
||||
q=buf;
|
||||
memcpy(q,str,slen);
|
||||
q+=slen;
|
||||
|
||||
EVP_MD_CTX_init(&ctx);
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
ssl3_digest_cached_records(s);
|
||||
|
||||
for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) {
|
||||
if (mask & s->s3->tmp.new_cipher->algorithm2) {
|
||||
EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
|
||||
EVP_DigestFinal_ex(&ctx,q,&i);
|
||||
q+=i;
|
||||
for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
|
||||
{
|
||||
if (mask & s->s3->tmp.new_cipher->algorithm2)
|
||||
{
|
||||
int hashsize = EVP_MD_size(md);
|
||||
if ((size_t)hashsize > (sizeof buf - (size_t)(q-buf)))
|
||||
{
|
||||
/* internal error: 'buf' is too small for this cipersuite! */
|
||||
err = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
|
||||
EVP_DigestFinal_ex(&ctx,q,&i);
|
||||
if (i != hashsize) /* can't really happen */
|
||||
err = 1;
|
||||
q+=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(q-buf),
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
out,buf2,sizeof buf2);
|
||||
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
|
||||
str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
out,buf2,sizeof buf2);
|
||||
EVP_MD_CTX_cleanup(&ctx);
|
||||
|
||||
return sizeof buf2;
|
||||
if (err)
|
||||
return 0;
|
||||
else
|
||||
return sizeof buf2;
|
||||
}
|
||||
|
||||
int tls1_mac(SSL *ssl, unsigned char *md, int send)
|
||||
|
@ -876,23 +897,35 @@ printf("rec=");
|
|||
int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
|
||||
int len)
|
||||
{
|
||||
unsigned char buf[SSL3_RANDOM_SIZE*2+TLS_MD_MASTER_SECRET_CONST_SIZE];
|
||||
unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
|
||||
const void *co = NULL, *so = NULL;
|
||||
int col = 0, sol = NULL;
|
||||
|
||||
#ifdef KSSL_DEBUG
|
||||
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
|
||||
#endif /* KSSL_DEBUG */
|
||||
|
||||
/* Setup the stuff to munge */
|
||||
memcpy(buf,TLS_MD_MASTER_SECRET_CONST,
|
||||
TLS_MD_MASTER_SECRET_CONST_SIZE);
|
||||
memcpy(&(buf[TLS_MD_MASTER_SECRET_CONST_SIZE]),
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE);
|
||||
memcpy(&(buf[SSL3_RANDOM_SIZE+TLS_MD_MASTER_SECRET_CONST_SIZE]),
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE);
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
|
||||
s->s3->client_opaque_prf_input_len > 0 &&
|
||||
s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
|
||||
{
|
||||
co = s->s3->client_opaque_prf_input;
|
||||
col = s->s3->server_opaque_prf_input_len;
|
||||
so = s->s3->server_opaque_prf_input;
|
||||
sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
|
||||
}
|
||||
#endif
|
||||
|
||||
tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
|
||||
buf,TLS_MD_MASTER_SECRET_CONST_SIZE+SSL3_RANDOM_SIZE*2,p,len,
|
||||
TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
co, col,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
so, sol,
|
||||
p,len,
|
||||
s->session->master_key,buff,sizeof buff);
|
||||
|
||||
#ifdef KSSL_DEBUG
|
||||
printf ("tls1_generate_master_secret() complete\n");
|
||||
#endif /* KSSL_DEBUG */
|
||||
|
|
225
ssl/t1_lib.c
225
ssl/t1_lib.c
|
@ -284,8 +284,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
+ hostname length
|
||||
*/
|
||||
|
||||
if ((lenmax = limit - p - 9) < 0
|
||||
|| (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
|
||||
if ((lenmax = limit - ret - 9) < 0
|
||||
|| (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
|
||||
return NULL;
|
||||
|
||||
/* extension type and length */
|
||||
|
@ -300,15 +300,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
s2n(size_str,ret);
|
||||
memcpy(ret, s->tlsext_hostname, size_str);
|
||||
ret+=size_str;
|
||||
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
if (s->tlsext_ecpointformatlist != NULL)
|
||||
{
|
||||
/* Add TLS extension ECPointFormats to the ClientHello message */
|
||||
long lenmax;
|
||||
|
||||
if ((lenmax = limit - p - 5) < 0) return NULL;
|
||||
if ((lenmax = limit - ret - 5) < 0) return NULL;
|
||||
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
|
||||
if (s->tlsext_ecpointformatlist_length > 255)
|
||||
{
|
||||
|
@ -327,7 +327,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
/* Add TLS extension EllipticCurves to the ClientHello message */
|
||||
long lenmax;
|
||||
|
||||
if ((lenmax = limit - p - 6) < 0) return NULL;
|
||||
if ((lenmax = limit - ret - 6) < 0) return NULL;
|
||||
if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
|
||||
if (s->tlsext_ellipticcurvelist_length > 65532)
|
||||
{
|
||||
|
@ -359,8 +359,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
/* Check for enough room 2 for extension type, 2 for len
|
||||
* rest for ticket
|
||||
*/
|
||||
if (limit - p - 4 - ticklen < 0)
|
||||
return NULL;
|
||||
if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
|
||||
s2n(TLSEXT_TYPE_session_ticket,ret);
|
||||
s2n(ticklen,ret);
|
||||
if (ticklen)
|
||||
|
@ -370,6 +369,24 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->s3->client_opaque_prf_input != NULL)
|
||||
{
|
||||
size_t col = s->s3->client_opaque_prf_input_len;
|
||||
|
||||
if ((long)(limit - ret - 6 - col < 0))
|
||||
return NULL;
|
||||
if (col > 0xFFFD) /* can't happen */
|
||||
return NULL;
|
||||
|
||||
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
|
||||
s2n(col + 2, ret);
|
||||
s2n(col, ret);
|
||||
memcpy(ret, s->s3->client_opaque_prf_input, col);
|
||||
ret += col;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
|
@ -387,7 +404,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
|
||||
if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
|
||||
{
|
||||
if (limit - p - 4 < 0) return NULL;
|
||||
if ((long)(limit - ret - 4) < 0) return NULL;
|
||||
|
||||
s2n(TLSEXT_TYPE_server_name,ret);
|
||||
s2n(0,ret);
|
||||
|
@ -398,7 +415,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
/* Add TLS extension ECPointFormats to the ServerHello message */
|
||||
long lenmax;
|
||||
|
||||
if ((lenmax = limit - p - 5) < 0) return NULL;
|
||||
if ((lenmax = limit - ret - 5) < 0) return NULL;
|
||||
if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
|
||||
if (s->tlsext_ecpointformatlist_length > 255)
|
||||
{
|
||||
|
@ -419,11 +436,29 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||
if (s->tlsext_ticket_expected
|
||||
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
|
||||
{
|
||||
if (limit - p - 4 < 0) return NULL;
|
||||
if ((long)(limit - ret - 4) < 0) return NULL;
|
||||
s2n(TLSEXT_TYPE_session_ticket,ret);
|
||||
s2n(0,ret);
|
||||
}
|
||||
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
if (s->s3->server_opaque_prf_input != NULL)
|
||||
{
|
||||
size_t sol = s->s3->server_opaque_prf_input_len;
|
||||
|
||||
if ((long)(limit - ret - 6 - sol) < 0)
|
||||
return NULL;
|
||||
if (sol > 0xFFFD) /* can't happen */
|
||||
return NULL;
|
||||
|
||||
s2n(TLSEXT_TYPE_opaque_prf_input, ret);
|
||||
s2n(sol + 2, ret);
|
||||
s2n(sol, ret);
|
||||
memcpy(ret, s->s3->server_opaque_prf_input, sol);
|
||||
ret += sol;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
|
@ -610,6 +645,35 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
|||
#endif
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
else if (type == TLSEXT_TYPE_opaque_prf_input)
|
||||
{
|
||||
unsigned char *sdata = data;
|
||||
|
||||
if (size < 2)
|
||||
{
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
n2s(sdata, s->s3->client_opaque_prf_input_len);
|
||||
if (s->s3->client_opaque_prf_input_len != size - 2)
|
||||
{
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
|
||||
OPENSSL_free(s->s3->client_opaque_prf_input);
|
||||
|
||||
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
|
||||
|
||||
/* session ticket processed earlier */
|
||||
data+=size;
|
||||
}
|
||||
|
@ -694,6 +758,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
|||
}
|
||||
s->tlsext_ticket_expected = 1;
|
||||
}
|
||||
#ifdef TLSEXT_TYPE_opaque_prf_input
|
||||
else if (type == TLSEXT_TYPE_opaque_prf_input)
|
||||
{
|
||||
unsigned char *sdata = data;
|
||||
|
||||
if (size < 2)
|
||||
{
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
n2s(sdata, s->s3->server_opaque_prf_input_len);
|
||||
if (s->s3->server_opaque_prf_input_len != size - 2)
|
||||
{
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
|
||||
OPENSSL_free(s->s3->server_opaque_prf_input);
|
||||
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
|
||||
|
||||
data+=size;
|
||||
}
|
||||
|
||||
|
@ -780,6 +873,38 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
|
|||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -810,6 +935,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
|
|||
s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -832,6 +958,62 @@ int ssl_check_clienthello_tlsext(SSL *s)
|
|||
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
|
||||
{
|
||||
/* 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! */
|
||||
|
||||
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:
|
||||
|
@ -895,6 +1077,29 @@ int ssl_check_serverhello_tlsext(SSL *s)
|
|||
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
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
||||
|
|
21
ssl/tls1.h
21
ssl/tls1.h
|
@ -183,16 +183,23 @@ extern "C" {
|
|||
#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
|
||||
#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */
|
||||
|
||||
/* ExtensionType values from RFC 3546 */
|
||||
/* ExtensionType values from RFC3546 / RFC4366 */
|
||||
#define TLSEXT_TYPE_server_name 0
|
||||
#define TLSEXT_TYPE_max_fragment_length 1
|
||||
#define TLSEXT_TYPE_client_certificate_url 2
|
||||
#define TLSEXT_TYPE_trusted_ca_keys 3
|
||||
#define TLSEXT_TYPE_truncated_hmac 4
|
||||
#define TLSEXT_TYPE_status_request 5
|
||||
/* ExtensionType values from RFC4492 */
|
||||
#define TLSEXT_TYPE_elliptic_curves 10
|
||||
#define TLSEXT_TYPE_ec_point_formats 11
|
||||
#define TLSEXT_TYPE_session_ticket 35
|
||||
/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */
|
||||
#if 0 /* will have to be provided externally for now ,
|
||||
* i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183
|
||||
* using whatever extension number you'd like to try */
|
||||
# define TLSEXT_TYPE_opaque_prf_input ?? */
|
||||
#endif
|
||||
|
||||
/* NameType value from RFC 3546 */
|
||||
#define TLSEXT_NAMETYPE_host_name 0
|
||||
|
@ -235,6 +242,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
|
|||
SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
|
||||
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
|
||||
SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
|
||||
|
||||
#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
|
||||
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
|
||||
#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \
|
||||
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb)
|
||||
#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \
|
||||
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
|
||||
|
||||
#endif
|
||||
|
||||
/* PSK ciphersuites from 4279 */
|
||||
|
@ -416,10 +431,6 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
|
|||
#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA"
|
||||
#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA"
|
||||
|
||||
/* Flags for SSL_CIPHER.algorithm2 field */
|
||||
/* Stream MAC for GOST ciphersuites from cryptopro draft */
|
||||
#define TLS1_STREAM_MAC 0x04
|
||||
|
||||
|
||||
#define TLS_CT_RSA_SIGN 1
|
||||
#define TLS_CT_DSS_SIGN 2
|
||||
|
|
Loading…
Reference in a new issue