X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fd1_clnt.c;h=887e3244e772363ddc0eebce5f2f0bc43c15399c;hp=f4e9df9810a1810587e45d32711109f9f6355dca;hb=8f119a03578ddc9f82d83e01ccfe48890f9dda03;hpb=368888bcb6192b96638c3d6dd706103be52eac89 diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index f4e9df9810..887e3244e7 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -114,7 +114,11 @@ */ #include +#include #include "ssl_locl.h" +#ifndef OPENSSL_NO_KRB5 +#include "kssl_lcl.h" +#endif #include #include #include @@ -130,7 +134,7 @@ static int dtls1_get_hello_verify(SSL *s); static const SSL_METHOD *dtls1_get_client_method(int ver) { - if (ver == DTLS1_VERSION) + if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER) return(DTLSv1_client_method()); else return(NULL); @@ -145,7 +149,6 @@ int dtls1_connect(SSL *s) { BUF_MEM *buf=NULL; unsigned long Time=(unsigned long)time(NULL); - long num1; void (*cb)(const SSL *ssl,int type,int val)=NULL; int ret= -1; int new_state,state,skip=0;; @@ -169,7 +172,7 @@ int dtls1_connect(SSL *s) switch(s->state) { case SSL_ST_RENEGOTIATE: - s->new_session=1; + s->renegotiate=1; s->state=SSL_ST_CONNECT; s->ctx->stats.sess_connect_renegotiate++; /* break */ @@ -181,7 +184,8 @@ int dtls1_connect(SSL *s) s->server=0; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); - if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00)) + if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) && + (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00)) { SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR); ret = -1; @@ -219,6 +223,8 @@ int dtls1_connect(SSL *s) s->init_num=0; /* mark client_random uninitialized */ memset(s->s3->client_random,0,sizeof(s->s3->client_random)); + s->d1->send_cookie = 0; + s->hit = 0; break; case SSL3_ST_CW_CLNT_HELLO_A: @@ -229,6 +235,7 @@ int dtls1_connect(SSL *s) /* every DTLS ClientHello resets Finished MAC */ ssl3_init_finished_mac(s); + dtls1_start_timer(s); ret=dtls1_client_hello(s); if (ret <= 0) goto end; @@ -254,6 +261,7 @@ int dtls1_connect(SSL *s) if (ret <= 0) goto end; else { + dtls1_stop_timer(s); if (s->hit) s->state=SSL3_ST_CR_FINISHED_A; else @@ -268,6 +276,7 @@ int dtls1_connect(SSL *s) ret = dtls1_get_hello_verify(s); if ( ret <= 0) goto end; + dtls1_stop_timer(s); if ( s->d1->send_cookie) /* start again, with a cookie */ s->state=SSL3_ST_CW_CLNT_HELLO_A; else @@ -277,15 +286,44 @@ int dtls1_connect(SSL *s) case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: - /* Check if it is anon DH */ - if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)) +#ifndef OPENSSL_NO_TLSEXT + ret=ssl3_check_finished(s); + if (ret <= 0) goto end; + if (ret == 2) + { + s->hit = 1; + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_CR_SESSION_TICKET_A; + else + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + } +#endif + /* Check if it is anon DH or PSK */ + if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && + !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state=SSL3_ST_CR_CERT_STATUS_A; + else + s->state=SSL3_ST_CR_KEY_EXCH_A; + } + else + { + skip = 1; + s->state=SSL3_ST_CR_KEY_EXCH_A; + } +#else } else skip=1; + s->state=SSL3_ST_CR_KEY_EXCH_A; +#endif s->init_num=0; break; @@ -329,6 +367,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: case SSL3_ST_CW_CERT_D: + dtls1_start_timer(s); ret=dtls1_send_client_certificate(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_KEY_EXCH_A; @@ -337,6 +376,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: + dtls1_start_timer(s); ret=dtls1_send_client_key_exchange(s); if (ret <= 0) goto end; /* EAY EAY EAY need to check for DH fix cert @@ -358,6 +398,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: + dtls1_start_timer(s); ret=dtls1_send_client_verify(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_CHANGE_A; @@ -367,6 +408,8 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: + if (!s->hit) + dtls1_start_timer(s); ret=dtls1_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; @@ -401,6 +444,8 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: + if (!s->hit) + dtls1_start_timer(s); ret=dtls1_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, s->method->ssl3_enc->client_finished_label, @@ -422,19 +467,43 @@ int dtls1_connect(SSL *s) } else { +#ifndef OPENSSL_NO_TLSEXT + /* Allow NewSessionTicket if ticket expected */ + if (s->tlsext_ticket_expected) + s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A; + else +#endif + s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; } s->init_num=0; - /* mark client_random uninitialized */ - memset (s->s3->client_random,0,sizeof(s->s3->client_random)); break; +#ifndef OPENSSL_NO_TLSEXT + case SSL3_ST_CR_SESSION_TICKET_A: + case SSL3_ST_CR_SESSION_TICKET_B: + ret=ssl3_get_new_session_ticket(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + + case SSL3_ST_CR_CERT_STATUS_A: + case SSL3_ST_CR_CERT_STATUS_B: + ret=ssl3_get_cert_status(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_KEY_EXCH_A; + s->init_num=0; + break; +#endif + case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: - + s->d1->change_cipher_spec_ok = 1; ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); if (ret <= 0) goto end; + dtls1_stop_timer(s); if (s->hit) s->state=SSL3_ST_CW_CHANGE_A; @@ -444,16 +513,13 @@ int dtls1_connect(SSL *s) break; case SSL3_ST_CW_FLUSH: - /* number of bytes to be flushed */ - num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); - if (num1 > 0) + s->rwstate=SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { - s->rwstate=SSL_WRITING; - num1=BIO_flush(s->wbio); - if (num1 <= 0) { ret= -1; goto end; } - s->rwstate=SSL_NOTHING; + ret= -1; + goto end; } - + s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; @@ -476,6 +542,7 @@ int dtls1_connect(SSL *s) /* else do it later in ssl3_write */ s->init_num=0; + s->renegotiate=0; s->new_session=0; ssl_update_cache(s,SSL_SESS_CACHE_CLIENT); @@ -490,6 +557,7 @@ int dtls1_connect(SSL *s) /* done with handshaking */ s->d1->handshake_read_seq = 0; + s->d1->next_handshake_write_seq = 0; goto end; /* break; */ @@ -539,8 +607,14 @@ int dtls1_client_hello(SSL *s) buf=(unsigned char *)s->init_buf->data; if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { + SSL_SESSION *sess = s->session; if ((s->session == NULL) || (s->session->ssl_version != s->version) || +#ifdef OPENSSL_NO_TLSEXT + !sess->session_id_length || +#else + (!sess->session_id_length && !sess->tlsext_tick) || +#endif (s->session->not_resumable)) { if (!ssl_get_new_session(s,0)) @@ -620,7 +694,15 @@ int dtls1_client_hello(SSL *s) *(p++)=comp->id; } *(p++)=0; /* Add the NULL method */ - + +#ifndef OPENSSL_NO_TLSEXT + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } +#endif + l=(p-d); d=buf; @@ -704,6 +786,14 @@ int dtls1_send_client_key_exchange(SSL *s) #ifndef OPENSSL_NO_KRB5 KSSL_ERR kssl_err; #endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_ECDH + EC_KEY *clnt_ecdh = NULL; + const EC_POINT *srvr_ecpoint = NULL; + EVP_PKEY *srvr_pub_pkey = NULL; + unsigned char *encodedPoint = NULL; + int encoded_pt_len = 0; + BN_CTX * bn_ctx = NULL; +#endif if (s->state == SSL3_ST_CW_KEY_EXCH_A) { @@ -782,7 +872,7 @@ int dtls1_send_client_key_exchange(SSL *s) krb5_data *enc_ticket; krb5_data authenticator, *authp = NULL; EVP_CIPHER_CTX ciph_ctx; - EVP_CIPHER *enc = NULL; + const EVP_CIPHER *enc = NULL; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH @@ -883,7 +973,7 @@ int dtls1_send_client_key_exchange(SSL *s) sizeof tmp_buf); EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl); outl += padl; - if (outl > sizeof epms) + if (outl > (int)sizeof epms) { SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); goto err; @@ -960,6 +1050,274 @@ int dtls1_send_client_key_exchange(SSL *s) /* perhaps clean things up a bit EAY EAY EAY EAY*/ } +#endif +#ifndef OPENSSL_NO_ECDH + else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) + { + const EC_GROUP *srvr_group = NULL; + EC_KEY *tkey; + int ecdh_clnt_cert = 0; + int field_size = 0; + + /* Did we send out the client's + * ECDH share for use in premaster + * computation as part of client certificate? + * If so, set ecdh_clnt_cert to 1. + */ + if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->cert != NULL)) + { + /* XXX: For now, we do not support client + * authentication using ECDH certificates. + * To add such support, one needs to add + * code that checks for appropriate + * conditions and sets ecdh_clnt_cert to 1. + * For example, the cert have an ECC + * key on the same curve as the server's + * and the key should be authorized for + * key agreement. + * + * One also needs to add code in ssl3_connect + * to skip sending the certificate verify + * message. + * + * if ((s->cert->key->privatekey != NULL) && + * (s->cert->key->privatekey->type == + * EVP_PKEY_EC) && ...) + * ecdh_clnt_cert = 1; + */ + } + + if (s->session->sess_cert->peer_ecdh_tmp != NULL) + { + tkey = s->session->sess_cert->peer_ecdh_tmp; + } + else + { + /* Get the Server Public Key from Cert */ + srvr_pub_pkey = X509_get_pubkey(s->session-> \ + sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + if ((srvr_pub_pkey == NULL) || + (srvr_pub_pkey->type != EVP_PKEY_EC) || + (srvr_pub_pkey->pkey.ec == NULL)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + tkey = srvr_pub_pkey->pkey.ec; + } + + srvr_group = EC_KEY_get0_group(tkey); + srvr_ecpoint = EC_KEY_get0_public_key(tkey); + + if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((clnt_ecdh=EC_KEY_new()) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB); + goto err; + } + if (ecdh_clnt_cert) + { + /* Reuse key info from our certificate + * We only need our private key to perform + * the ECDH computation. + */ + const BIGNUM *priv_key; + tkey = s->cert->key->privatekey->pkey.ec; + priv_key = EC_KEY_get0_private_key(tkey); + if (priv_key == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_EC_LIB); + goto err; + } + } + else + { + /* Generate a new ECDH key pair */ + if (!(EC_KEY_generate_key(clnt_ecdh))) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + } + + /* use the 'p' output buffer for the ECDH key, but + * make sure to clear it out afterwards + */ + + field_size = EC_GROUP_get_degree(srvr_group); + if (field_size <= 0) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL); + if (n <= 0) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + + /* generate master key from the result */ + s->session->master_key_length = s->method->ssl3_enc \ + -> generate_master_secret(s, + s->session->master_key, + p, n); + + memset(p, 0, n); /* clean up */ + + if (ecdh_clnt_cert) + { + /* Send empty client key exch message */ + n = 0; + } + else + { + /* First check the size of encoding and + * allocate memory accordingly. + */ + encoded_pt_len = + EC_POINT_point2oct(srvr_group, + EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, + NULL, 0, NULL); + + encodedPoint = (unsigned char *) + OPENSSL_malloc(encoded_pt_len * + sizeof(unsigned char)); + bn_ctx = BN_CTX_new(); + if ((encodedPoint == NULL) || + (bn_ctx == NULL)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Encode the public key */ + n = EC_POINT_point2oct(srvr_group, + EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, + encodedPoint, encoded_pt_len, bn_ctx); + + *p = n; /* length of encoded point */ + /* Encoded point will be copied here */ + p += 1; + /* copy the point */ + memcpy((unsigned char *)p, encodedPoint, n); + /* increment n to account for length field */ + n += 1; + } + + /* Free allocated memory */ + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + EC_KEY_free(clnt_ecdh); + EVP_PKEY_free(srvr_pub_pkey); + } +#endif /* !OPENSSL_NO_ECDH */ + +#ifndef OPENSSL_NO_PSK + else if (alg_k & SSL_kPSK) + { + char identity[PSK_MAX_IDENTITY_LEN]; + unsigned char *t = NULL; + unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4]; + unsigned int pre_ms_len = 0, psk_len = 0; + int psk_err = 1; + + n = 0; + if (s->psk_client_callback == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_NO_CLIENT_CB); + goto err; + } + + psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, + identity, PSK_MAX_IDENTITY_LEN, + psk_or_pre_ms, sizeof(psk_or_pre_ms)); + if (psk_len > PSK_MAX_PSK_LEN) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto psk_err; + } + else if (psk_len == 0) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + goto psk_err; + } + + /* create PSK pre_master_secret */ + pre_ms_len = 2+psk_len+2+psk_len; + t = psk_or_pre_ms; + memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len); + s2n(psk_len, t); + memset(t, 0, psk_len); + t+=psk_len; + s2n(psk_len, t); + + if (s->session->psk_identity_hint != NULL) + OPENSSL_free(s->session->psk_identity_hint); + s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); + if (s->ctx->psk_identity_hint != NULL && + s->session->psk_identity_hint == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + if (s->session->psk_identity != NULL) + OPENSSL_free(s->session->psk_identity); + s->session->psk_identity = BUF_strdup(identity); + if (s->session->psk_identity == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, + psk_or_pre_ms, pre_ms_len); + n = strlen(identity); + s2n(n, p); + memcpy(p, identity, n); + n+=2; + psk_err = 0; + psk_err: + OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN); + OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); + if (psk_err != 0) + { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + } #endif else { @@ -989,6 +1347,13 @@ int dtls1_send_client_key_exchange(SSL *s) /* SSL3_ST_CW_KEY_EXCH_B */ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); err: +#ifndef OPENSSL_NO_ECDH + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + EC_KEY_free(clnt_ecdh); + EVP_PKEY_free(srvr_pub_pkey); +#endif return(-1); } @@ -1001,7 +1366,7 @@ int dtls1_send_client_verify(SSL *s) unsigned u=0; #endif unsigned long n; -#ifndef OPENSSL_NO_DSA +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) int j; #endif @@ -1048,6 +1413,23 @@ int dtls1_send_client_verify(SSL *s) n=j+2; } else +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_EC) + { + if (!ECDSA_sign(pkey->save_type, + &(data[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH,&(p[2]), + (unsigned int *)&j,pkey->pkey.ec)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY, + ERR_R_ECDSA_LIB); + goto err; + } + s2n(j,p); + n=j+2; + } + else #endif { SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);