X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_clnt.c;h=f46aaef6ce026a56dbc48b093ae05ebf49285fa0;hp=44b698cc5f021af147156a85386d309d7f144847;hb=f3d781bb43050abf89bdc0ace3a880d3af6cfcb7;hpb=d5e7f2f2c3262c0dbf21363259b0477082c7b98e diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 44b698cc5f..f46aaef6ce 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 @@ -156,6 +157,9 @@ #include #include #include +#ifdef OPENSSL_FIPS +#include +#endif #ifndef OPENSSL_NO_DH #include #endif @@ -207,7 +211,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 */ @@ -280,7 +284,16 @@ int ssl3_connect(SSL *s) if (ret <= 0) goto end; if (s->hit) + { s->state=SSL3_ST_CR_FINISHED_A; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_ticket_expected) + { + /* receive renewed session ticket */ + s->state=SSL3_ST_CR_SESSION_TICKET_A; + } +#endif + } else s->state=SSL3_ST_CR_CERT_A; s->init_num=0; @@ -358,6 +371,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 @@ -423,7 +447,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->s3->next_proto_neg_seen) + 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; @@ -451,6 +483,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, @@ -546,6 +587,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); @@ -847,6 +889,14 @@ int ssl3_get_server_hello(SSL *s) SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED); goto f_err; } + /* TLS v1.2 only ciphersuites require v1.2 or later */ + if ((c->algorithm_ssl & SSL_TLSV1_2) && + (TLS1_get_version(s) < TLS1_2_VERSION)) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } p+=ssl_put_cipher_by_char(s,NULL,NULL); sk=ssl_get_ciphers_by_id(s); @@ -866,8 +916,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); @@ -875,9 +928,11 @@ int ssl3_get_server_hello(SSL *s) } } s->s3->tmp.new_cipher=c; - if (!ssl3_digest_cached_records(s)) + /* Don't digest cached records if TLS v1.2: we may need them for + * client authentication. + */ + if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s)) goto f_err; - /* lets get the compression algorithm */ /* COMPRESSION */ #ifdef OPENSSL_NO_COMP @@ -950,7 +1005,7 @@ int ssl3_get_server_hello(SSL *s) /* wrong packet length */ al=SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH); - goto err; + goto f_err; } return(1); @@ -981,7 +1036,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); @@ -1154,6 +1211,7 @@ int ssl3_get_key_exchange(SSL *s) int al,i,j,param_len,ok; long n,alg_k,alg_a; EVP_PKEY *pkey=NULL; + const EVP_MD *md = NULL; #ifndef OPENSSL_NO_RSA RSA *rsa=NULL; #endif @@ -1277,6 +1335,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) { @@ -1506,6 +1644,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; } @@ -1523,6 +1662,38 @@ int ssl3_get_key_exchange(SSL *s) /* if it was signed, check the signature */ if (pkey != NULL) { + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + /* Check key type is consistent with signature */ + if (sigalg != (int)p[1]) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } + md = tls12_get_hash(p[0]); + if (md == NULL) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } +#ifdef SSL_DEBUG +fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + p += 2; + n -= 2; + } + else + md = EVP_sha1(); + n2s(p,i); n-=2; j=EVP_PKEY_size(pkey); @@ -1536,7 +1707,7 @@ int ssl3_get_key_exchange(SSL *s) } #ifndef OPENSSL_NO_RSA - if (pkey->type == EVP_PKEY_RSA) + if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION) { int num; @@ -1544,6 +1715,8 @@ int ssl3_get_key_exchange(SSL *s) q=md_buf; for (num=2; num > 0; num--) { + EVP_MD_CTX_set_flags(&md_ctx, + EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); EVP_DigestInit_ex(&md_ctx,(num == 2) ?s->ctx->md5:s->ctx->sha1, NULL); EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); @@ -1571,11 +1744,8 @@ int ssl3_get_key_exchange(SSL *s) } else #endif -#ifndef OPENSSL_NO_DSA - if (pkey->type == EVP_PKEY_DSA) { - /* lets do DSS */ - EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL); + EVP_VerifyInit_ex(&md_ctx, md, NULL); 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); @@ -1587,30 +1757,6 @@ int ssl3_get_key_exchange(SSL *s) goto f_err; } } - else -#endif -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) - { - /* let's do ECDSA */ - EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL); - 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) <= 0) - { - /* bad signature */ - al=SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE); - goto f_err; - } - } - else -#endif - { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); - goto err; - } } else { @@ -1657,7 +1803,7 @@ int ssl3_get_certificate_request(SSL *s) { int ok,ret=0; unsigned long n,nc,l; - unsigned int llen,ctype_num,i; + unsigned int llen, ctype_num,i; X509_NAME *xn=NULL; const unsigned char *p,*q; unsigned char *d; @@ -1677,6 +1823,14 @@ int ssl3_get_certificate_request(SSL *s) if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE) { s->s3->tmp.reuse_message=1; + /* If we get here we don't need any cached handshake records + * as we wont be doing client auth. + */ + if (s->s3->handshake_buffer) + { + if (!ssl3_digest_cached_records(s)) + goto err; + } return(1); } @@ -1713,6 +1867,26 @@ int ssl3_get_certificate_request(SSL *s) for (i=0; is3->tmp.ctype[i]= p[i]; p+=ctype_num; + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + n2s(p, llen); + /* Check we have enough room for signature algorithms and + * following length value. + */ + if ((unsigned long)(p - d + llen + 2) > n) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + if ((llen & 1) || !tls1_process_sigalgs(s, p, llen)) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_SIGNATURE_ALGORITHMS_ERROR); + goto err; + } + p += llen; + } /* get the CA RDNs */ n2s(p,llen); @@ -1725,7 +1899,7 @@ fclose(out); } #endif - if ((llen+ctype_num+2+1) != n) + if ((unsigned long)(p - d + llen) != n) { ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR); SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH); @@ -1831,7 +2005,7 @@ int ssl3_get_new_session_ticket(SSL *s) if (n < 6) { /* need at least ticket_lifetime_hint + ticket length */ - al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR; + al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH); goto f_err; } @@ -1842,7 +2016,7 @@ int ssl3_get_new_session_ticket(SSL *s) /* ticket_lifetime_hint + ticket_length + ticket */ if (ticklen + 6 != n) { - al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR; + al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH); goto f_err; } @@ -2237,6 +2411,7 @@ int ssl3_send_client_key_exchange(SSL *s) if (!DH_generate_key(dh_clnt)) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB); + DH_free(dh_clnt); goto err; } @@ -2248,6 +2423,7 @@ int ssl3_send_client_key_exchange(SSL *s) if (n <= 0) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB); + DH_free(dh_clnt); goto err; } @@ -2545,6 +2721,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) { @@ -2664,13 +2873,12 @@ int ssl3_send_client_verify(SSL *s) unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; EVP_PKEY *pkey; EVP_PKEY_CTX *pctx=NULL; -#ifndef OPENSSL_NO_RSA + EVP_MD_CTX mctx; unsigned u=0; -#endif unsigned long n; -#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) int j; -#endif + + EVP_MD_CTX_init(&mctx); if (s->state == SSL3_ST_CW_CERT_VRFY_A) { @@ -2682,7 +2890,8 @@ int ssl3_send_client_verify(SSL *s) EVP_PKEY_sign_init(pctx); if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0) { - s->method->ssl3_enc->cert_verify_mac(s, + if (TLS1_get_version(s) < TLS1_2_VERSION) + s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, &(data[MD5_DIGEST_LENGTH])); } @@ -2690,6 +2899,41 @@ int ssl3_send_client_verify(SSL *s) { ERR_clear_error(); } + /* For TLS v1.2 send signature algorithm and signature + * using agreed digest and cached handshake records. + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + long hdatalen = 0; + void *hdata; + const EVP_MD *md = s->cert->key->digest; + hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, + &hdata); + if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + p += 2; +#ifdef SSL_DEBUG + fprintf(stderr, "Using TLS 1.2 with client alg %s\n", + EVP_MD_name(md)); +#endif + if (!EVP_SignInit_ex(&mctx, md, NULL) + || !EVP_SignUpdate(&mctx, hdata, hdatalen) + || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) + { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_EVP_LIB); + goto err; + } + s2n(u,p); + n = u + 4; + if (!ssl3_digest_cached_records(s)) + goto err; + } + else #ifndef OPENSSL_NO_RSA if (pkey->type == EVP_PKEY_RSA) { @@ -2772,9 +3016,11 @@ int ssl3_send_client_verify(SSL *s) s->init_num=(int)n+4; s->init_off=0; } + EVP_MD_CTX_cleanup(&mctx); EVP_PKEY_CTX_free(pctx); return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); err: + EVP_MD_CTX_cleanup(&mctx); EVP_PKEY_CTX_free(pctx); return(-1); } @@ -2870,13 +3116,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; @@ -2884,6 +3123,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 @@ -2898,7 +3144,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) if (idx == SSL_PKEY_ECC) { if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509, - s->s3->tmp.new_cipher) == 0) + s) == 0) { /* check failed */ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT); goto f_err; @@ -3000,6 +3246,32 @@ err: */ #ifndef OPENSSL_NO_TLSEXT +# 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;