diff options
author | Matt Caswell <matt@openssl.org> | 2015-09-08 09:38:08 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2015-10-30 08:38:18 +0000 |
commit | e27f234a4147a7bd621d2a439c2cc2cc9a6a8382 (patch) | |
tree | b18fe84ebeec97d3fecef591388a4506fdaa06d7 /ssl/s3_srvr.c | |
parent | 4e3458a565da5bccf30fe598e87ad7da1ee9daa7 (diff) |
Split TLS server functions
Split the TLS server ssl3_get_* and ssl3_send_* functions into two ready
for the migration to the new state machine code.
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl/s3_srvr.c')
-rw-r--r-- | ssl/s3_srvr.c | 1976 |
1 files changed, 1077 insertions, 899 deletions
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 376ab7150d..98e831c58e 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -169,7 +169,6 @@ static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, STACK_OF(SSL_CIPHER) **skp, int sslv2format, int *al); - #ifndef OPENSSL_NO_SRP static int ssl_check_srp_ext_ClientHello(SSL *s, int *al) { @@ -350,37 +349,29 @@ int ssl3_accept(SSL *s) ret = ssl3_get_client_hello(s); if (ret <= 0) goto end; + + s->state = SSL3_ST_SW_SRVR_HELLO_A; + s->init_num = 0; + break; + #ifndef OPENSSL_NO_SRP - s->state = SSL3_ST_SR_CLNT_HELLO_D; case SSL3_ST_SR_CLNT_HELLO_D: { - int al; - if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) { - /* - * callback indicates firther work to be done - */ - s->rwstate = SSL_X509_LOOKUP; + enum WORK_STATE wst_ret; + + wst_ret = tls_post_process_client_hello(s, WORK_MORE_B); + if (wst_ret == WORK_MORE_B) goto end; - } - if (ret != SSL_ERROR_NONE) { - ssl3_send_alert(s, SSL3_AL_FATAL, al); - /* - * This is not really an error but the only means to for - * a client to detect whether srp is supported. - */ - if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) - SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_CLIENTHELLO_TLSEXT); + if (wst_ret == WORK_ERROR) { ret = -1; - s->state = SSL_ST_ERR; goto end; } } -#endif - s->renegotiate = 2; s->state = SSL3_ST_SW_SRVR_HELLO_A; s->init_num = 0; break; +#endif case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: @@ -569,7 +560,7 @@ int ssl3_accept(SSL *s) ret = ssl3_get_client_key_exchange(s); if (ret <= 0) goto end; - if (ret == 2) { + if (s->no_cert_verify) { /* * For the ECDH ciphersuites when the client sends its ECDH * pub key in a certificate, the CertificateVerify message is @@ -825,8 +816,7 @@ int ssl3_send_hello_request(SSL *s) { if (s->state == SSL3_ST_SW_HELLO_REQ_A) { - if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) { - SSLerr(SSL_F_SSL3_SEND_HELLO_REQUEST, ERR_R_INTERNAL_ERROR); + if (tls_construct_hello_request(s) == 0) { return -1; } s->state = SSL3_ST_SW_HELLO_REQ_B; @@ -836,21 +826,22 @@ int ssl3_send_hello_request(SSL *s) return ssl_do_write(s); } +int tls_construct_hello_request(SSL *s) +{ + if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, ERR_R_INTERNAL_ERROR); + statem_set_error(s); + return 0; + } + + return 1; +} + int ssl3_get_client_hello(SSL *s) { - int i, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1; - unsigned int j, complen = 0; + int ok; long n; - unsigned long id; - SSL_CIPHER *c; -#ifndef OPENSSL_NO_COMP - SSL_COMP *comp = NULL; -#endif - STACK_OF(SSL_CIPHER) *ciphers = NULL; - int protverr = 1; - /* |cookie| will only be initialized for DTLS. */ - PACKET pkt, session_id, cipher_suites, compression, extensions, cookie; - int is_v2_record; + enum WORK_STATE wst_ret; if (s->state == SSL3_ST_SR_CLNT_HELLO_C && !s->first_packet) goto retry_cert; @@ -874,8 +865,38 @@ int ssl3_get_client_hello(SSL *s) if (!ok) return ((int)n); s->first_packet = 0; + + if (tls_process_client_hello(s, n) == 0) + return -1; + + retry_cert: + wst_ret = tls_post_process_client_hello(s, WORK_MORE_A); + if (wst_ret == WORK_MORE_A || wst_ret == WORK_ERROR) + return -1; + if (wst_ret == WORK_MORE_B) { + s->state = SSL3_ST_SR_CLNT_HELLO_D; + return -1; + } + return n; +} + +enum MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, long n) +{ + int i, al = SSL_AD_INTERNAL_ERROR; + unsigned int j, complen = 0; + unsigned long id; + SSL_CIPHER *c; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp = NULL; +#endif + STACK_OF(SSL_CIPHER) *ciphers = NULL; + int protverr = 1; + /* |cookie| will only be initialized for DTLS. */ + PACKET pkt, session_id, cipher_suites, compression, extensions, cookie; + int is_v2_record; + if (!PACKET_buf_init(&pkt, s->init_msg, n)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); al = SSL_AD_INTERNAL_ERROR; goto f_err; } @@ -909,25 +930,25 @@ int ssl3_get_client_hello(SSL *s) * layer in order to have determined that this is a SSLv2 record * in the first place */ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } if (!PACKET_get_net_2(&pkt, &version)) { /* No protocol version supplied! */ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); goto err; } if (version == 0x0002) { /* This is real SSLv2. We don't support it. */ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); goto err; } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) { /* SSLv3/TLS */ s->client_version = version; } else { /* No idea what protocol this is */ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); goto err; } } else { @@ -937,7 +958,7 @@ int ssl3_get_client_hello(SSL *s) */ if(!PACKET_get_net_2(&pkt, (unsigned int *)&s->client_version)) { al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); goto f_err; } } @@ -998,7 +1019,7 @@ int ssl3_get_client_hello(SSL *s) } if (protverr) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); if ((!s->enc_write_ctx && !s->write_hash)) { /* * similar to ssl3_get_record, send alert using remote version @@ -1023,7 +1044,8 @@ int ssl3_get_client_hello(SSL *s) if (!PACKET_get_net_2(&pkt, &cipher_len) || !PACKET_get_net_2(&pkt, &session_id_len) || !PACKET_get_net_2(&pkt, &challenge_len)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_RECORD_LENGTH_MISMATCH); al = SSL_AD_DECODE_ERROR; goto f_err; } @@ -1135,7 +1157,7 @@ int ssl3_get_client_hello(SSL *s) } if (SSL_IS_DTLS(s)) { - /* Empty cookie was already handled above by returning early. */ + /* Empty cookie was already handled above by returning early. */ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { if (s->ctx->app_verify_cookie_cb != NULL) { if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie), @@ -1153,8 +1175,7 @@ int ssl3_get_client_hello(SSL *s) SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); goto f_err; } - /* Set to -2 so if successful we return 2 */ - ret = -2; + s->d1->cookie_verified = 1; } if (s->method->version == DTLS_ANY_VERSION) { /* Select version to use */ @@ -1278,7 +1299,7 @@ int ssl3_get_client_hello(SSL *s) (s)); if (pref_cipher == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER); goto f_err; } @@ -1304,7 +1325,7 @@ int ssl3_get_client_hello(SSL *s) /* Perform sanity checks on resumed compression algorithm */ /* Can't disable compression */ if (!ssl_allow_compression(s)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION); goto f_err; } @@ -1317,7 +1338,7 @@ int ssl3_get_client_hello(SSL *s) } } if (s->s3->tmp.new_compression == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INVALID_COMPRESSION_ALGORITHM); goto f_err; } @@ -1328,7 +1349,7 @@ int ssl3_get_client_hello(SSL *s) } if (k >= complen) { al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING); goto f_err; } @@ -1363,7 +1384,7 @@ int ssl3_get_client_hello(SSL *s) * using compression. */ if (s->session->compress_meth != 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION); goto f_err; } #endif @@ -1382,89 +1403,140 @@ int ssl3_get_client_hello(SSL *s) s->session->ciphers = ciphers; if (ciphers == NULL) { al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto f_err; } ciphers = NULL; if (!tls1_set_server_sigalgs(s)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); goto err; } - /* Let cert callback update server certificates if required */ - retry_cert: - if (s->cert->cert_cb) { - int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg); - if (rv == 0) { - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CERT_CB_ERROR); - goto f_err; + } + + sk_SSL_CIPHER_free(ciphers); + return MSG_PROCESS_CONTINUE_PROCESSING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + statem_set_error(s); + + sk_SSL_CIPHER_free(ciphers); + return MSG_PROCESS_ERROR; + +} + +enum WORK_STATE tls_post_process_client_hello(SSL *s, enum WORK_STATE wst) +{ + int al; + SSL_CIPHER *cipher; + + if (wst == WORK_MORE_A) { + if (!s->hit) { + /* Let cert callback update server certificates if required */ + if (s->cert->cert_cb) { + int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg); + if (rv == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CERT_CB_ERROR); + goto f_err; + } + if (rv < 0) { + s->rwstate = SSL_X509_LOOKUP; + return WORK_MORE_A; + } + s->rwstate = SSL_NOTHING; } - if (rv < 0) { - s->rwstate = SSL_X509_LOOKUP; - return -1; + cipher = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); + + if (cipher == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER); + goto f_err; } - s->rwstate = SSL_NOTHING; + s->s3->tmp.new_cipher = cipher; + /* check whether we should disable session resumption */ + if (s->not_resumable_session_cb != NULL) + s->session->not_resumable = s->not_resumable_session_cb(s, + ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0)); + if (s->session->not_resumable) + /* do not send a session ticket */ + s->tlsext_ticket_expected = 0; + } else { + /* Session-id reuse */ + s->s3->tmp.new_cipher = s->session->cipher; } - c = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); - if (c == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER); - goto f_err; + if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) { + if (!ssl3_digest_cached_records(s, 0)) + goto f_err; } - s->s3->tmp.new_cipher = c; - /* check whether we should disable session resumption */ - if (s->not_resumable_session_cb != NULL) - s->session->not_resumable = s->not_resumable_session_cb(s, - ((c->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) - != 0)); - if (s->session->not_resumable) - /* do not send a session ticket */ - s->tlsext_ticket_expected = 0; - } else { - /* Session-id reuse */ - s->s3->tmp.new_cipher = s->session->cipher; - } - if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) { - if (!ssl3_digest_cached_records(s, 0)) - goto f_err; - } + /*- + * we now have the following setup. + * client_random + * cipher_list - our prefered list of ciphers + * ciphers - the clients prefered list of ciphers + * compression - basically ignored right now + * ssl version is set - sslv3 + * s->session - The ssl session has been setup. + * s->hit - session reuse flag + * s->s3->tmp.new_cipher- the new cipher to use. + */ - /*- - * we now have the following setup. - * client_random - * cipher_list - our prefered list of ciphers - * ciphers - the clients prefered list of ciphers - * compression - basically ignored right now - * ssl version is set - sslv3 - * s->session - The ssl session has been setup. - * s->hit - session reuse flag - * s->s3->tmp.new_cipher- the new cipher to use. - */ + /* Handles TLS extensions that we couldn't check earlier */ + if (s->version >= SSL3_VERSION) { + if (ssl_check_clienthello_tlsext_late(s) <= 0) { + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto f_err; + } + } - /* Handles TLS extensions that we couldn't check earlier */ - if (s->version >= SSL3_VERSION) { - if (ssl_check_clienthello_tlsext_late(s) <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); - goto err; + wst = WORK_MORE_B; + } +#ifndef OPENSSL_NO_SRP + if (wst == WORK_MORE_B) { + int ret; + if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) { + /* + * callback indicates further work to be done + */ + s->rwstate = SSL_X509_LOOKUP; + return WORK_MORE_B; + } + if (ret != SSL_ERROR_NONE) { + /* + * This is not really an error but the only means to for + * a client to detect whether srp is supported. + */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_CLIENTHELLO_TLSEXT); + goto f_err; } } +#endif + s->renegotiate = 2; - if (ret < 0) - ret = -ret; - if (0) { + return WORK_FINISHED_STOP; f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - s->state = SSL_ST_ERR; + ssl3_send_alert(s, SSL3_AL_FATAL, al); + statem_set_error(s); + return WORK_ERROR; +} + +int ssl3_send_server_hello(SSL *s) +{ + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) { + if (tls_construct_server_hello(s) != 1) + return -1; + s->state = SSL3_ST_SW_SRVR_HELLO_B; } - sk_SSL_CIPHER_free(ciphers); - return ret < 0 ? -1 : ret; + /* SSL3_ST_SW_SRVR_HELLO_B */ + return ssl_do_write(s); } -int ssl3_send_server_hello(SSL *s) +int tls_construct_server_hello(SSL *s) { unsigned char *buf; unsigned char *p, *d; @@ -1472,102 +1544,97 @@ int ssl3_send_server_hello(SSL *s) int al = 0; unsigned long l; - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) { - buf = (unsigned char *)s->init_buf->data; + buf = (unsigned char *)s->init_buf->data; - /* Do the message type and length last */ - d = p = ssl_handshake_start(s); + /* Do the message type and length last */ + d = p = ssl_handshake_start(s); - *(p++) = s->version >> 8; - *(p++) = s->version & 0xff; + *(p++) = s->version >> 8; + *(p++) = s->version & 0xff; - /* - * Random stuff. Filling of the server_random takes place in - * ssl3_get_client_hello() - */ - memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); - p += SSL3_RANDOM_SIZE; + /* + * Random stuff. Filling of the server_random takes place in + * tls_process_client_hello() + */ + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; - /*- - * There are several cases for the session ID to send - * back in the server hello: - * - For session reuse from the session cache, - * we send back the old session ID. - * - If stateless session reuse (using a session ticket) - * is successful, we send back the client's "session ID" - * (which doesn't actually identify the session). - * - If it is a new session, we send back the new - * session ID. - * - However, if we want the new session to be single-use, - * we send back a 0-length session ID. - * s->hit is non-zero in either case of session reuse, - * so the following won't overwrite an ID that we're supposed - * to send back. - */ - if (s->session->not_resumable || - (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) - && !s->hit)) - s->session->session_id_length = 0; - - sl = s->session->session_id_length; - if (sl > (int)sizeof(s->session->session_id)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR); - s->state = SSL_ST_ERR; - return -1; - } - *(p++) = sl; - memcpy(p, s->session->session_id, sl); - p += sl; + /*- + * There are several cases for the session ID to send + * back in the server hello: + * - For session reuse from the session cache, + * we send back the old session ID. + * - If stateless session reuse (using a session ticket) + * is successful, we send back the client's "session ID" + * (which doesn't actually identify the session). + * - If it is a new session, we send back the new + * session ID. + * - However, if we want the new session to be single-use, + * we send back a 0-length session ID. + * s->hit is non-zero in either case of session reuse, + * so the following won't overwrite an ID that we're supposed + * to send back. + */ + if (s->session->not_resumable || + (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->hit)) + s->session->session_id_length = 0; + + sl = s->session->session_id_length; + if (sl > (int)sizeof(s->session->session_id)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + statem_set_error(s); + return 0; + } + *(p++) = sl; + memcpy(p, s->session->session_id, sl); + p += sl; - /* put the cipher */ - i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p); - p += i; + /* put the cipher */ + i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p); + p += i; - /* put the compression method */ + /* put the compression method */ #ifdef OPENSSL_NO_COMP - *(p++) = 0; + *(p++) = 0; #else - if (s->s3->tmp.new_compression == NULL) - *(p++) = 0; - else - *(p++) = s->s3->tmp.new_compression->id; + if (s->s3->tmp.new_compression == NULL) + *(p++) = 0; + else + *(p++) = s->s3->tmp.new_compression->id; #endif - if (ssl_prepare_serverhello_tlsext(s) <= 0) { - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); - s->state = SSL_ST_ERR; - return -1; - } - if ((p = - ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, - &al)) == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, al); - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR); - s->state = SSL_ST_ERR; - return -1; - } + if (ssl_prepare_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); + statem_set_error(s); + return 0; + } + if ((p = + ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, + &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + statem_set_error(s); + return 0; + } - /* do the header */ - l = (p - d); - if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR); - return -1; - } - s->state = SSL3_ST_SW_SRVR_HELLO_B; + /* do the header */ + l = (p - d); + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + statem_set_error(s); + return 0; } - /* SSL3_ST_SW_SRVR_HELLO_B */ - return ssl_do_write(s); + return 1; } int ssl3_send_server_done(SSL *s) { if (s->state == SSL3_ST_SW_SRVR_DONE_A) { - if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_DONE, ERR_R_INTERNAL_ERROR); + if (tls_construct_server_done(s) == 0) return -1; - } s->state = SSL3_ST_SW_SRVR_DONE_B; } @@ -1575,8 +1642,36 @@ int ssl3_send_server_done(SSL *s) return ssl_do_write(s); } +int tls_construct_server_done(SSL *s) +{ + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_DONE, ERR_R_INTERNAL_ERROR); + statem_set_error(s); + return 0; + } + + if (!s->s3->tmp.cert_request) { + if (!ssl3_digest_cached_records(s, 0)) { + statem_set_error(s); + } + } + + return 1; +} + int ssl3_send_server_key_exchange(SSL *s) { + if (s->state == SSL3_ST_SW_KEY_EXCH_A) { + if (tls_construct_server_key_exchange(s) == 0) + return -1; + } + + s->state = SSL3_ST_SW_KEY_EXCH_B; + return ssl_do_write(s); +} + +int tls_construct_server_key_exchange(SSL *s) +{ #ifndef OPENSSL_NO_RSA unsigned char *q; int j, num; @@ -1607,431 +1702,429 @@ int ssl3_send_server_key_exchange(SSL *s) EVP_MD_CTX md_ctx; EVP_MD_CTX_init(&md_ctx); - if (s->state == SSL3_ST_SW_KEY_EXCH_A) { - type = s->s3->tmp.new_cipher->algorithm_mkey; - cert = s->cert; - buf = s->init_buf; + type = s->s3->tmp.new_cipher->algorithm_mkey; + cert = s->cert; + + buf = s->init_buf; - r[0] = r[1] = r[2] = r[3] = NULL; - n = 0; + r[0] = r[1] = r[2] = r[3] = NULL; + n = 0; #ifndef OPENSSL_NO_PSK - if (type & SSL_PSK) { - /* - * reserve size for record length and PSK identity hint - */ - n += 2; - if (s->cert->psk_identity_hint) - n += strlen(s->cert->psk_identity_hint); - } - /* Plain PSK or RSAPSK nothing to do */ - if (type & (SSL_kPSK | SSL_kRSAPSK)) { - } else + if (type & SSL_PSK) { + /* + * reserve size for record length and PSK identity hint + */ + n += 2; + if (s->cert->psk_identity_hint) + n += strlen(s->cert->psk_identity_hint); + } + /* Plain PSK or RSAPSK nothing to do */ + if (type & (SSL_kPSK | SSL_kRSAPSK)) { + } else #endif /* !OPENSSL_NO_PSK */ #ifndef OPENSSL_NO_RSA - if (type & SSL_kRSA) { - rsa = cert->rsa_tmp; - if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) { - rsa = s->cert->rsa_tmp_cb(s, - SSL_C_IS_EXPORT(s->s3-> - tmp.new_cipher), - SSL_C_EXPORT_PKEYLENGTH(s->s3-> - tmp.new_cipher)); - if (rsa == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_ERROR_GENERATING_TMP_RSA_KEY); - goto f_err; - } - RSA_up_ref(rsa); - cert->rsa_tmp = rsa; - } + if (type & SSL_kRSA) { + rsa = cert->rsa_tmp; + if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) { + rsa = s->cert->rsa_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3-> + tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s->s3-> + tmp.new_cipher)); if (rsa == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_MISSING_TMP_RSA_KEY); + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_ERROR_GENERATING_TMP_RSA_KEY); goto f_err; } - r[0] = rsa->n; - r[1] = rsa->e; - s->s3->tmp.use_rsa_tmp = 1; - } else + RSA_up_ref(rsa); + cert->rsa_tmp = rsa; + } + if (rsa == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_RSA_KEY); + goto f_err; + } + r[0] = rsa->n; + r[1] = rsa->e; + s->s3->tmp.use_rsa_tmp = 1; + } else #endif #ifndef OPENSSL_NO_DH - if (type & (SSL_kDHE | SSL_kDHEPSK)) { - if (s->cert->dh_tmp_auto) { - dhp = ssl_get_auto_dh(s); - if (dhp == NULL) { - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto f_err; - } - } else - dhp = cert->dh_tmp; - if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL)) - dhp = s->cert->dh_tmp_cb(s, - SSL_C_IS_EXPORT(s->s3-> - tmp.new_cipher), - SSL_C_EXPORT_PKEYLENGTH(s->s3-> - tmp.new_cipher)); + if (type & (SSL_kDHE | SSL_kDHEPSK)) { + if (s->cert->dh_tmp_auto) { + dhp = ssl_get_auto_dh(s); if (dhp == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_MISSING_TMP_DH_KEY); - goto f_err; - } - if (!ssl_security(s, SSL_SECOP_TMP_DH, - DH_security_bits(dhp), 0, dhp)) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_DH_KEY_TOO_SMALL); - goto f_err; - } - if (s->s3->tmp.dh != NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); - goto err; + goto f_err; } + } else + dhp = cert->dh_tmp; + if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL)) + dhp = s->cert->dh_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3-> + tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s->s3-> + tmp.new_cipher)); + if (dhp == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + if (!ssl_security(s, SSL_SECOP_TMP_DH, + DH_security_bits(dhp), 0, dhp)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_DH_KEY_TOO_SMALL); + goto f_err; + } + if (s->s3->tmp.dh != NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } - if (s->cert->dh_tmp_auto) - dh = dhp; - else if ((dh = DHparams_dup(dhp)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + if (s->cert->dh_tmp_auto) + dh = dhp; + else if ((dh = DHparams_dup(dhp)) == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + s->s3->tmp.dh = dh; + if ((dhp->pub_key == NULL || + dhp->priv_key == NULL || + (s->options & SSL_OP_SINGLE_DH_USE))) { + if (!DH_generate_key(dh)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); goto err; } - - s->s3->tmp.dh = dh; - if ((dhp->pub_key == NULL || - dhp->priv_key == NULL || - (s->options & SSL_OP_SINGLE_DH_USE))) { - if (!DH_generate_key(dh)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - } else { - dh->pub_key = BN_dup(dhp->pub_key); - dh->priv_key = BN_dup(dhp->priv_key); - if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } + } else { + dh->pub_key = BN_dup(dhp->pub_key); + dh->priv_key = BN_dup(dhp->priv_key); + if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; } - r[0] = dh->p; - r[1] = dh->g; - r[2] = dh->pub_key; - } else + } + r[0] = dh->p; + r[1] = dh->g; + r[2] = dh->pub_key; + } else #endif #ifndef OPENSSL_NO_EC - if (type & (SSL_kECDHE | SSL_kECDHEPSK)) { - const EC_GROUP *group; - - ecdhp = cert->ecdh_tmp; - if (s->cert->ecdh_tmp_auto) { - /* Get NID of appropriate shared curve */ - int nid = tls1_shared_curve(s, -2); - if (nid != NID_undef) - ecdhp = EC_KEY_new_by_curve_name(nid); - } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) { - ecdhp = s->cert->ecdh_tmp_cb(s, - SSL_C_IS_EXPORT(s->s3-> - tmp.new_cipher), - SSL_C_EXPORT_PKEYLENGTH(s-> - s3->tmp.new_cipher)); - } - if (ecdhp == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_MISSING_TMP_ECDH_KEY); - goto f_err; - } + if (type & (SSL_kECDHE | SSL_kECDHEPSK)) { + const EC_GROUP *group; - if (s->s3->tmp.ecdh != NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } + ecdhp = cert->ecdh_tmp; + if (s->cert->ecdh_tmp_auto) { + /* Get NID of appropriate shared curve */ + int nid = tls1_shared_curve(s, -2); + if (nid != NID_undef) + |