X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_srvr.c;h=2ff4bc7ebdeb3dd494960e20753cbefa5fd37e52;hp=0d90198a8fd6a7d53f15a082065a1c8beeb470a9;hb=dc634aff252943c5f61fa1a245a4206259cf941f;hpb=6434abbfc6ac0d5cb882844ed10fef5821039cf6 diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 0d90198a8f..2ff4bc7ebd 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -332,10 +332,24 @@ int ssl3_accept(SSL *s) { ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state=SSL3_ST_SW_CERT_STATUS_A; + else + s->state=SSL3_ST_SW_KEY_EXCH_A; + } + else + { + skip = 1; + s->state=SSL3_ST_SW_KEY_EXCH_A; + } +#else } else skip=1; + s->state=SSL3_ST_SW_KEY_EXCH_A; +#endif s->init_num=0; break; @@ -497,18 +511,24 @@ int ssl3_accept(SSL *s) } else { + int offset=0; + int dgst_num; s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; /* We need to get hashes here so if there is * a client cert, it can be verified + * FIXME - digest processing for CertificateVerify + * should be generalized. But it is next step */ - s->method->ssl3_enc->cert_verify_mac(s, - &(s->s3->finish_dgst1), - &(s->s3->tmp.cert_verify_md[0])); - s->method->ssl3_enc->cert_verify_mac(s, - &(s->s3->finish_dgst2), - &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH])); + if (s->s3->handshake_buffer) + ssl3_digest_cached_records(s); + for (dgst_num=0; dgst_nums3->handshake_dgst[dgst_num]) + { + s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset])); + offset+=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); + } } break; @@ -548,6 +568,14 @@ int ssl3_accept(SSL *s) s->init_num=0; break; + case SSL3_ST_SW_CERT_STATUS_A: + case SSL3_ST_SW_CERT_STATUS_B: + ret=ssl3_send_cert_status(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_SW_KEY_EXCH_A; + s->init_num=0; + break; + #endif case SSL3_ST_SW_CHANGE_A: @@ -750,7 +778,8 @@ int ssl3_get_client_hello(SSL *s) s->client_version=(((int)p[0])<<8)|(int)p[1]; p+=2; - if (s->client_version < s->version) + if ((s->version == DTLS1_VERSION && s->client_version > s->version) || + (s->version != DTLS1_VERSION && s->client_version < s->version)) { SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); if ((s->client_version>>8) == SSL3_VERSION_MAJOR) @@ -801,7 +830,7 @@ int ssl3_get_client_hello(SSL *s) p+=j; - if (SSL_version(s) == DTLS1_VERSION) + if (s->version == DTLS1_VERSION) { /* cookie stuff */ cookie_len = *(p++); @@ -1026,6 +1055,7 @@ int ssl3_get_client_hello(SSL *s) goto f_err; } s->s3->tmp.new_cipher=c; + ssl3_digest_cached_records(s); } else { @@ -1056,6 +1086,9 @@ int ssl3_get_client_hello(SSL *s) else #endif s->s3->tmp.new_cipher=s->session->cipher; + /* Clear cached handshake records */ + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; } /* we now have the following setup. @@ -1112,8 +1145,16 @@ int ssl3_send_server_hello(SSL *s) * session-id if we want it to be single use. * Currently I will not implement the '0' length session-id * 12-Jan-98 - I'll now support the '0' length stuff. + * + * We also have an additional case where stateless session + * resumption is successful: we always send back the old + * session id. In this case s->hit is non zero: this can + * only happen if stateless session resumption is succesful + * if session caching is disabled so existing functionality + * is unaffected. */ - if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) + if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->hit) s->session->session_id_length=0; sl=s->session->session_id_length; @@ -1151,7 +1192,6 @@ int ssl3_send_server_hello(SSL *s) return -1; } #endif - /* do the header */ l=(p-d); d=buf; @@ -1793,7 +1833,7 @@ int ssl3_get_client_key_exchange(SSL *s) rsa=pkey->pkey.rsa; } - /* TLS */ + /* TLS and [incidentally] DTLS{0xFEFF} */ if (s->version > SSL3_VERSION) { n2s(p,i); @@ -2368,6 +2408,35 @@ int ssl3_get_client_key_exchange(SSL *s) } else #endif + if (alg_k & SSL_kGOST) + { + EVP_PKEY_CTX *pkey_ctx; + unsigned char premaster_secret[32]; + size_t outlen; + + /* Get our certificate privatec key*/ + pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL); + EVP_PKEY_decrypt_init(pkey_ctx); + /* Decrypt session key */ + if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 ) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto err; + } + if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,p+3,p[2]) <0) + + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto err; + } + /* Generate master secret */ + EVP_PKEY_CTX_free(pkey_ctx); + s->session->master_key_length= + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key,premaster_secret,32); + + } + else { al=SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, @@ -2457,15 +2526,25 @@ int ssl3_get_cert_verify(SSL *s) /* we now have a signature that we need to verify */ p=(unsigned char *)s->init_msg; - n2s(p,i); - n-=2; - if (i > n) + /* Check for broken implementations of GOST ciphersuites */ + /* If key is GOST and n is exactly 64, it is bare + * signature without length field */ + if (n==64 && (pkey->type==NID_id_GostR3410_94 || + pkey->type == NID_id_GostR3410_2001) ) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH); - al=SSL_AD_DECODE_ERROR; - goto f_err; - } - + i=64; + } + else + { + n2s(p,i); + n-=2; + if (i > n) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } + } j=EVP_PKEY_size(pkey); if ((i > j) || (n > j) || (n <= 0)) { @@ -2528,6 +2607,28 @@ int ssl3_get_cert_verify(SSL *s) } else #endif + if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001) + { unsigned char signature[64]; + int idx; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey,NULL); + EVP_PKEY_verify_init(pctx); + if (i!=64) { + fprintf(stderr,"GOST signature length is %d",i); + } + for (idx=0;idx<64;idx++) { + signature[63-idx]=p[idx]; + } + j=EVP_PKEY_verify(pctx,signature,64,s->s3->tmp.cert_verify_md,32); + EVP_PKEY_CTX_free(pctx); + if (j<=0) + { + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_ECDSA_SIGNATURE); + goto f_err; + } + } + else { SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR); al=SSL_AD_UNSUPPORTED_CERTIFICATE; @@ -2730,7 +2831,7 @@ int ssl3_send_server_certificate(SSL *s) /* SSL3_ST_SW_CERT_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } -#ifndef OPENSSLP_NO_TLSEXT +#ifndef OPENSSL_NO_TLSEXT int ssl3_send_newsession_ticket(SSL *s) { if (s->state == SSL3_ST_SW_SESSION_TICKET_A) @@ -2792,7 +2893,7 @@ int ssl3_send_newsession_ticket(SSL *s) HMAC_CTX_init(&hctx); HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, - EVP_sha1(), NULL); + tlsext_tick_md(), NULL); HMAC_Update(&hctx, macstart, p - macstart); HMAC_Final(&hctx, p, &hlen); HMAC_CTX_cleanup(&hctx); @@ -2816,4 +2917,39 @@ int ssl3_send_newsession_ticket(SSL *s) /* SSL3_ST_SW_SESSION_TICKET_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } + +int ssl3_send_cert_status(SSL *s) + { + if (s->state == SSL3_ST_SW_CERT_STATUS_A) + { + unsigned char *p; + /* Grow buffer if need be: the length calculation is as + * follows 1 (message type) + 3 (message length) + + * 1 (ocsp response type) + 3 (ocsp response length) + * + (ocsp response) + */ + if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) + return -1; + + p=(unsigned char *)s->init_buf->data; + + /* do the header */ + *(p++)=SSL3_MT_CERTIFICATE_STATUS; + /* message length */ + l2n3(s->tlsext_ocsp_resplen + 4, p); + /* status type */ + *(p++)= s->tlsext_status_type; + /* length of OCSP response */ + l2n3(s->tlsext_ocsp_resplen, p); + /* actual response */ + memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen); + /* number of bytes to write */ + s->init_num = 8 + s->tlsext_ocsp_resplen; + s->state=SSL3_ST_SW_CERT_STATUS_B; + s->init_off = 0; + } + + /* SSL3_ST_SW_CERT_STATUS_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } #endif