X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_clnt.c;h=f96ec4f9848fb34590f439c5a52cc01f3316f3ec;hp=5cea73ca1abcbedaf7c06d5482d1e7dd66af734c;hb=23bc7961d2486254082be1ba0eb4bedb8bfbcfb3;hpb=12bf56c017a34bd0d5fc6d817564ae49d0a9e861 diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 5cea73ca1a..f96ec4f984 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -149,6 +149,7 @@ */ #include +#include #include "ssl_locl.h" #include "kssl_lcl.h" #include @@ -166,9 +167,6 @@ static const SSL_METHOD *ssl3_get_client_method(int ver); static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b); -#ifndef OPENSSL_NO_TLSEXT -static int ssl3_check_finished(SSL *s); -#endif static const SSL_METHOD *ssl3_get_client_method(int ver) { @@ -187,10 +185,9 @@ int ssl3_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;; + int new_state,state,skip=0; RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); @@ -211,7 +208,7 @@ int ssl3_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 */ @@ -281,6 +278,20 @@ int ssl3_connect(SSL *s) case SSL3_ST_CR_SRVR_HELLO_A: case SSL3_ST_CR_SRVR_HELLO_B: ret=ssl3_get_server_hello(s); +#ifndef OPENSSL_NO_SRP + if ((ret == 0) && (s->s3->warn_alert == SSL_AD_MISSING_SRP_USERNAME)) + { + if (!SRP_have_to_put_srp_username(s)) + { + SSLerr(SSL_F_SSL3_CONNECT,SSL_R_MISSING_SRP_USERNAME); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_USER_CANCELLED); + goto end; + } + s->state=SSL3_ST_CW_CLNT_HELLO_A; + if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; } + break; + } +#endif if (ret <= 0) goto end; if (s->hit) @@ -362,6 +373,17 @@ int ssl3_connect(SSL *s) case SSL3_ST_CR_SRVR_DONE_B: ret=ssl3_get_server_done(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_SRP + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) + { + if ((ret = SRP_Calc_A_param(s))<=0) + { + SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR); + goto end; + } + } +#endif if (s->s3->tmp.cert_req) s->state=SSL3_ST_CW_CERT_A; else @@ -404,6 +426,11 @@ int ssl3_connect(SSL *s) s->state=SSL3_ST_CW_CHANGE_A; s->s3->change_cipher_spec=0; } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) + { + s->state=SSL3_ST_CW_CHANGE_A; + s->s3->change_cipher_spec=0; + } s->init_num=0; break; @@ -422,7 +449,15 @@ int ssl3_connect(SSL *s) ret=ssl3_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; + +#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) s->state=SSL3_ST_CW_FINISHED_A; +#else + if (s->next_proto_negotiated) + s->state=SSL3_ST_CW_NEXT_PROTO_A; + else + s->state=SSL3_ST_CW_FINISHED_A; +#endif s->init_num=0; s->session->cipher=s->s3->tmp.new_cipher; @@ -450,6 +485,15 @@ int ssl3_connect(SSL *s) break; +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + case SSL3_ST_CW_NEXT_PROTO_A: + case SSL3_ST_CW_NEXT_PROTO_B: + ret=ssl3_send_next_proto(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CW_FINISHED_A; + break; +#endif + case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: ret=ssl3_send_finished(s, @@ -518,16 +562,13 @@ int ssl3_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; @@ -548,6 +589,7 @@ int ssl3_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); @@ -613,9 +655,15 @@ int ssl3_client_hello(SSL *s) buf=(unsigned char *)s->init_buf->data; if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { - if ((s->session == NULL) || - (s->session->ssl_version != s->version) || - (s->session->not_resumable)) + SSL_SESSION *sess = s->session; + if ((sess == NULL) || + (sess->ssl_version != s->version) || +#ifdef OPENSSL_NO_TLSEXT + !sess->session_id_length || +#else + (!sess->session_id_length && !sess->tlsext_tick) || +#endif + (sess->not_resumable)) { if (!ssl_get_new_session(s,0)) goto err; @@ -737,7 +785,7 @@ int ssl3_get_server_hello(SSL *s) if (!ok) return((int)n); - if ( SSL_version(s) == DTLS1_VERSION) + if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) { if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { @@ -862,8 +910,11 @@ int ssl3_get_server_hello(SSL *s) s->session->cipher_id = s->session->cipher->id; if (s->hit && (s->session->cipher_id != c->id)) { +/* Workaround is now obsolete */ +#if 0 if (!(s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG)) +#endif { al=SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); @@ -871,7 +922,8 @@ int ssl3_get_server_hello(SSL *s) } } s->s3->tmp.new_cipher=c; - ssl3_digest_cached_records(s); + if (!ssl3_digest_cached_records(s)) + goto f_err; /* lets get the compression algorithm */ /* COMPRESSION */ @@ -882,10 +934,31 @@ int ssl3_get_server_hello(SSL *s) SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); goto f_err; } + /* If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) + { + al=SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } #else j= *(p++); - if ((j == 0) || (s->options & SSL_OP_NO_COMPRESSION)) + if (s->hit && j != s->session->compress_meth) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED); + goto f_err; + } + if (j == 0) comp=NULL; + else if (s->options & SSL_OP_NO_COMPRESSION) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED); + goto f_err; + } else comp=ssl3_comp_find(s->ctx->comp_methods,j); @@ -903,7 +976,7 @@ int ssl3_get_server_hello(SSL *s) #ifndef OPENSSL_NO_TLSEXT /* TLS extensions*/ - if (s->version > SSL3_VERSION) + if (s->version >= SSL3_VERSION) { if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al)) { @@ -955,7 +1028,9 @@ int ssl3_get_server_certificate(SSL *s) if (!ok) return((int)n); - if (s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) + if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) || + ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) && + (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE))) { s->s3->tmp.reuse_message=1; return(1); @@ -1017,7 +1092,7 @@ int ssl3_get_server_certificate(SSL *s) } i=ssl_verify_cert_chain(s,sk); - if ((s->verify_mode != SSL_VERIFY_NONE) && (!i) + if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0) #ifndef OPENSSL_NO_KRB5 && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)) @@ -1251,6 +1326,86 @@ int ssl3_get_key_exchange(SSL *s) } else #endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) + { + n2s(p,i); + param_len=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.N=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.g=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + i = (unsigned int)(p[0]); + p++; + param_len+=i+1; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.s=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.B=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + n-=param_len; + +/* We must check if there is a certificate */ +#ifndef OPENSSL_NO_RSA + if (alg_a & SSL_aRSA) + pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +#else + if (0) + ; +#endif +#ifndef OPENSSL_NO_DSA + else if (alg_a & SSL_aDSS) + pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); +#endif + } + else +#endif /* !OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_RSA if (alg_k & SSL_kRSA) { @@ -1480,6 +1635,7 @@ int ssl3_get_key_exchange(SSL *s) s->session->sess_cert->peer_ecdh_tmp=ecdh; ecdh=NULL; BN_CTX_free(bn_ctx); + bn_ctx = NULL; EC_POINT_free(srvr_ecpoint); srvr_ecpoint = NULL; } @@ -1553,7 +1709,7 @@ int ssl3_get_key_exchange(SSL *s) EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,param,param_len); - if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey)) + if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0) { /* bad signature */ al=SSL_AD_DECRYPT_ERROR; @@ -1571,7 +1727,7 @@ int ssl3_get_key_exchange(SSL *s) EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,param,param_len); - if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey)) + if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0) { /* bad signature */ al=SSL_AD_DECRYPT_ERROR; @@ -1809,6 +1965,7 @@ int ssl3_get_new_session_ticket(SSL *s) SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH); goto f_err; } + p=d=(unsigned char *)s->init_msg; n2l(p, s->session->tlsext_tick_lifetime_hint); n2s(p, ticklen); @@ -1832,7 +1989,28 @@ int ssl3_get_new_session_ticket(SSL *s) } memcpy(s->session->tlsext_tick, p, ticklen); s->session->tlsext_ticklen = ticklen; - + /* There are two ways to detect a resumed ticket sesion. + * One is to set an appropriate session ID and then the server + * must return a match in ServerHello. This allows the normal + * client session ID matching to work and we know much + * earlier that the ticket has been accepted. + * + * The other way is to set zero length session ID when the + * ticket is presented and rely on the handshake to determine + * session resumption. + * + * We choose the former approach because this fits in with + * assumptions elsewhere in OpenSSL. The session ID is set + * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the + * ticket. + */ + EVP_Digest(p, ticklen, + s->session->session_id, &s->session->session_id_length, +#ifndef OPENSSL_NO_SHA256 + EVP_sha256(), NULL); +#else + EVP_sha1(), NULL); +#endif ret=1; return(ret); f_err: @@ -2033,7 +2211,7 @@ int ssl3_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 @@ -2136,7 +2314,7 @@ int ssl3_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_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); goto err; @@ -2415,7 +2593,7 @@ int ssl3_send_client_key_exchange(SSL *s) size_t msglen; unsigned int md_len; int keytype; - unsigned char premaster_secret[32],shared_ukm[32]; + unsigned char premaster_secret[32],shared_ukm[32], tmp[256]; EVP_MD_CTX *ukm_hash; EVP_PKEY *pub_key; @@ -2441,16 +2619,13 @@ int ssl3_send_client_key_exchange(SSL *s) /* Generate session key */ RAND_bytes(premaster_secret,32); /* If we have client certificate, use its secret as peer key */ - if (s->cert->key->privatekey) { - if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <0) { + if (s->s3->tmp.cert_req && s->cert->key->privatekey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) { /* If there was an error - just ignore it. Ephemeral key * would be used */ ERR_clear_error(); - } else { - /* Set flag "client cert key is used for key - * exchange"*/ - } + } } /* Compute shared IV and store it in algorithm-specific * context data */ @@ -2469,15 +2644,30 @@ int ssl3_send_client_key_exchange(SSL *s) /* Make GOST keytransport blob message */ /*Encapsulate it into sequence */ *(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; - *(p++)=0x81; - msglen=256; - if (EVP_PKEY_encrypt(pkey_ctx,(unsigned char *)p+1,&msglen,premaster_secret,32)<0) { + msglen=255; + if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); goto err; - } - *(p++)= msglen & 0xff; - n=msglen+3; + } + if (msglen >= 0x80) + { + *(p++)=0x81; + *(p++)= msglen & 0xff; + n=msglen+3; + } + else + { + *(p++)= msglen & 0xff; + n=msglen+2; + } + memcpy(p, tmp, msglen); + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + { + /* Set flag "skip certificate verify" */ + s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY; + } EVP_PKEY_CTX_free(pkey_ctx); s->session->master_key_length= s->method->ssl3_enc->generate_master_secret(s, @@ -2485,6 +2675,39 @@ int ssl3_send_client_key_exchange(SSL *s) EVP_PKEY_free(pub_key); } +#ifndef OPENSSL_NO_SRP + else if (alg_k & SSL_kSRP) + { + if (s->srp_ctx.A != NULL) + { + /* send off the data */ + n=BN_num_bytes(s->srp_ctx.A); + s2n(n,p); + BN_bn2bin(s->srp_ctx.A,p); + n+=2; + } + else + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = SRP_generate_client_master_secret(s,s->session->master_key))<0) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif #ifndef OPENSSL_NO_PSK else if (alg_k & SSL_kPSK) { @@ -2608,9 +2831,7 @@ int ssl3_send_client_verify(SSL *s) unsigned u=0; #endif unsigned long n; -#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) int j; -#endif if (s->state == SSL3_ST_CW_CERT_VRFY_A) { @@ -2689,7 +2910,7 @@ int ssl3_send_client_verify(SSL *s) s->method->ssl3_enc->cert_verify_mac(s, NID_id_GostR3411_94, data); - if (!EVP_PKEY_sign(pctx,signbuf,&sigsize,data,32)) { + if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) { SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); goto err; @@ -2810,13 +3031,6 @@ int ssl3_check_cert_and_algorithm(SSL *s) DH *dh; #endif - sc=s->session->sess_cert; - if (sc == NULL) - { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR); - goto err; - } - alg_k=s->s3->tmp.new_cipher->algorithm_mkey; alg_a=s->s3->tmp.new_cipher->algorithm_auth; @@ -2824,6 +3038,13 @@ int ssl3_check_cert_and_algorithm(SSL *s) if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK)) return(1); + sc=s->session->sess_cert; + if (sc == NULL) + { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR); + goto err; + } + #ifndef OPENSSL_NO_RSA rsa=s->session->sess_cert->peer_rsa_tmp; #endif @@ -2940,7 +3161,33 @@ err: */ #ifndef OPENSSL_NO_TLSEXT -static int ssl3_check_finished(SSL *s) +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_send_next_proto(SSL *s) + { + unsigned int len, padding_len; + unsigned char *d; + + if (s->state == SSL3_ST_CW_NEXT_PROTO_A) + { + len = s->next_proto_negotiated_len; + padding_len = 32 - ((len + 2) % 32); + d = (unsigned char *)s->init_buf->data; + d[4] = len; + memcpy(d + 5, s->next_proto_negotiated, len); + d[5 + len] = padding_len; + memset(d + 6 + len, 0, padding_len); + *(d++)=SSL3_MT_NEXT_PROTO; + l2n3(2 + len + padding_len, d); + s->state = SSL3_ST_CW_NEXT_PROTO_B; + s->init_num = 4 + 2 + len + padding_len; + s->init_off = 0; + } + + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + } +# endif + +int ssl3_check_finished(SSL *s) { int ok; long n;