diff options
| author | Simon L. B. Nielsen <simon@FreeBSD.org> | 2008-09-21 14:56:30 +0000 | 
|---|---|---|
| committer | Simon L. B. Nielsen <simon@FreeBSD.org> | 2008-09-21 14:56:30 +0000 | 
| commit | bb1499d2aac1d25a95b8573ff425751f06f159e1 (patch) | |
| tree | a136b5b2317abe8eb83b021afe5e088230fd67e2 /ssl/s3_srvr.c | |
| parent | ee266f1253f9cc49430572463d26f72910dfb49e (diff) | |
Diffstat (limited to 'ssl/s3_srvr.c')
| -rw-r--r-- | ssl/s3_srvr.c | 255 | 
1 files changed, 238 insertions, 17 deletions
| diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 9414cf09fb64..398ce469d682 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -132,6 +132,7 @@  #include <openssl/rand.h>  #include <openssl/objects.h>  #include <openssl/evp.h> +#include <openssl/hmac.h>  #include <openssl/x509.h>  #ifndef OPENSSL_NO_DH  #include <openssl/dh.h> @@ -143,7 +144,6 @@  #include <openssl/md5.h>  static SSL_METHOD *ssl3_get_server_method(int ver); -  #ifndef OPENSSL_NO_ECDH  static int nid2curve_id(int nid);  #endif @@ -290,9 +290,18 @@ int ssl3_accept(SSL *s)  		case SSL3_ST_SW_SRVR_HELLO_B:  			ret=ssl3_send_server_hello(s);  			if (ret <= 0) goto end; - +#ifndef OPENSSL_NO_TLSEXT  			if (s->hit) -				s->state=SSL3_ST_SW_CHANGE_A; +				{ +				if (s->tlsext_ticket_expected) +					s->state=SSL3_ST_SW_SESSION_TICKET_A; +				else +					s->state=SSL3_ST_SW_CHANGE_A; +				} +#else +			if (s->hit) +					s->state=SSL3_ST_SW_CHANGE_A; +#endif  			else  				s->state=SSL3_ST_SW_CERT_A;  			s->init_num=0; @@ -306,10 +315,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; @@ -494,11 +517,34 @@ int ssl3_accept(SSL *s)  			if (ret <= 0) goto end;  			if (s->hit)  				s->state=SSL_ST_OK; +#ifndef OPENSSL_NO_TLSEXT +			else if (s->tlsext_ticket_expected) +				s->state=SSL3_ST_SW_SESSION_TICKET_A; +#endif  			else  				s->state=SSL3_ST_SW_CHANGE_A;  			s->init_num=0;  			break; +#ifndef OPENSSL_NO_TLSEXT +		case SSL3_ST_SW_SESSION_TICKET_A: +		case SSL3_ST_SW_SESSION_TICKET_B: +			ret=ssl3_send_newsession_ticket(s); +			if (ret <= 0) goto end; +			s->state=SSL3_ST_SW_CHANGE_A; +			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:  		case SSL3_ST_SW_CHANGE_B: @@ -699,7 +745,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)  @@ -727,14 +774,14 @@ int ssl3_get_client_hello(SSL *s)  	 * might be written that become totally unsecure when compiled with  	 * an earlier library version)  	 */ -	if (j == 0 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) +	if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))  		{  		if (!ssl_get_new_session(s,1))  			goto err;  		}  	else  		{ -		i=ssl_get_prev_session(s,p,j); +		i=ssl_get_prev_session(s, p, j, d + n);  		if (i == 1)  			{ /* previous session */  			s->hit=1; @@ -750,7 +797,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++); @@ -897,6 +944,22 @@ int ssl3_get_client_hello(SSL *s)  		goto f_err;  		} +#ifndef OPENSSL_NO_TLSEXT +	/* TLS extensions*/ +	if (s->version > SSL3_VERSION) +		{ +		if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al)) +			{ +			/* 'al' set by ssl_parse_clienthello_tlsext */ +			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT); +			goto f_err; +			} +		} +		if (ssl_check_clienthello_tlsext(s) <= 0) { +			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); +			goto err; +		} +#endif  	/* Worst case, we will use the NULL compression, but if we have other  	 * options, we will now look for them.  We have i-1 compression  	 * algorithms from the client, starting at q. */ @@ -1061,8 +1124,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; @@ -1088,20 +1159,26 @@ int ssl3_send_server_hello(SSL *s)  		else  			*(p++)=s->s3->tmp.new_compression->id;  #endif - +#ifndef OPENSSL_NO_TLSEXT +		if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) +			{ +			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); +			return -1; +			} +#endif  		/* do the header */  		l=(p-d);  		d=buf;  		*(d++)=SSL3_MT_SERVER_HELLO;  		l2n3(l,d); -		s->state=SSL3_ST_CW_CLNT_HELLO_B; +		s->state=SSL3_ST_SW_SRVR_HELLO_B;  		/* number of bytes to write */  		s->init_num=p-buf;  		s->init_off=0;  		} -	/* SSL3_ST_CW_CLNT_HELLO_B */ +	/* SSL3_ST_SW_SRVR_HELLO_B */  	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));  	} @@ -1125,7 +1202,7 @@ int ssl3_send_server_done(SSL *s)  		s->init_off=0;  		} -	/* SSL3_ST_CW_CLNT_HELLO_B */ +	/* SSL3_ST_SW_SRVR_DONE_B */  	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));  	} @@ -1463,6 +1540,8 @@ int ssl3_send_server_key_exchange(SSL *s)  				j=0;  				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); @@ -1711,8 +1790,9 @@ int ssl3_get_client_key_exchange(SSL *s)  			rsa=pkey->pkey.rsa;  			} -		/* TLS */ -		if (s->version > SSL3_VERSION) +		/* TLS and [incidentally] DTLS, including pre-0.9.8f */ +		if (s->version > SSL3_VERSION && +		    s->client_version != DTLS1_BAD_VER)  			{  			n2s(p,i);  			if (n != i+2) @@ -1997,7 +2077,7 @@ int ssl3_get_client_key_exchange(SSL *s)  				SSL_R_DATA_LENGTH_TOO_LONG);  			goto err;  			} -		if (!((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff)))) +		if (!((pms[0] == (s->client_version>>8)) && (pms[1] == (s->client_version & 0xff))))  		    {  		    /* The premaster secret must contain the same version number as the  		     * ClientHello to detect version rollback attacks (strangely, the @@ -2007,8 +2087,7 @@ int ssl3_get_client_key_exchange(SSL *s)  		     * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients.   		     * (Perhaps we should have a separate BUG value for the Kerberos cipher)  		     */ -		    if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) && -			   (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff)))) +		    if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG))  		        {  			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,  			       SSL_AD_DECODE_ERROR); @@ -2616,3 +2695,145 @@ static int nid2curve_id(int nid)  	}  }  #endif +#ifndef OPENSSL_NO_TLSEXT +int ssl3_send_newsession_ticket(SSL *s) +	{ +	if (s->state == SSL3_ST_SW_SESSION_TICKET_A) +		{ +		unsigned char *p, *senc, *macstart; +		int len, slen; +		unsigned int hlen; +		EVP_CIPHER_CTX ctx; +		HMAC_CTX hctx; +		unsigned char iv[EVP_MAX_IV_LENGTH]; +		unsigned char key_name[16]; + +		/* get session encoding length */ +		slen = i2d_SSL_SESSION(s->session, NULL); +		/* Some length values are 16 bits, so forget it if session is + 		 * too long + 		 */ +		if (slen > 0xFF00) +			return -1; +		/* Grow buffer if need be: the length calculation is as + 		 * follows 1 (size of message name) + 3 (message length + 		 * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) + + 		 * 16 (key name) + max_iv_len (iv length) + + 		 * session_length + max_enc_block_size (max encrypted session + 		 * length) + max_md_size (HMAC). + 		 */ +		if (!BUF_MEM_grow(s->init_buf, +			26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + +			EVP_MAX_MD_SIZE + slen)) +			return -1; +		senc = OPENSSL_malloc(slen); +		if (!senc) +			return -1; +		p = senc; +		i2d_SSL_SESSION(s->session, &p); + +		p=(unsigned char *)s->init_buf->data; +		/* do the header */ +		*(p++)=SSL3_MT_NEWSESSION_TICKET; +		/* Skip message length for now */ +		p += 3; +		EVP_CIPHER_CTX_init(&ctx); +		HMAC_CTX_init(&hctx); +		/* Initialize HMAC and cipher contexts. If callback present +		 * it does all the work otherwise use generated values +		 * from parent ctx. +		 */ +		if (s->ctx->tlsext_ticket_key_cb) +			{ +			if (s->ctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, +							 &hctx, 1) < 0) +				{ +				OPENSSL_free(senc); +				return -1; +				} +			} +		else +			{ +			RAND_pseudo_bytes(iv, 16); +			EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, +					s->ctx->tlsext_tick_aes_key, iv); +			HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, +					tlsext_tick_md(), NULL); +			memcpy(key_name, s->ctx->tlsext_tick_key_name, 16); +			} +		l2n(s->session->tlsext_tick_lifetime_hint, p); +		/* Skip ticket length for now */ +		p += 2; +		/* Output key name */ +		macstart = p; +		memcpy(p, key_name, 16); +		p += 16; +		/* output IV */ +		memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); +		p += EVP_CIPHER_CTX_iv_length(&ctx); +		/* Encrypt session data */ +		EVP_EncryptUpdate(&ctx, p, &len, senc, slen); +		p += len; +		EVP_EncryptFinal(&ctx, p, &len); +		p += len; +		EVP_CIPHER_CTX_cleanup(&ctx); + +		HMAC_Update(&hctx, macstart, p - macstart); +		HMAC_Final(&hctx, p, &hlen); +		HMAC_CTX_cleanup(&hctx); + +		p += hlen; +		/* Now write out lengths: p points to end of data written */ +		/* Total length */ +		len = p - (unsigned char *)s->init_buf->data; +		p=(unsigned char *)s->init_buf->data + 1; +		l2n3(len - 4, p); /* Message length */ +		p += 4; +		s2n(len - 10, p);  /* Ticket length */ + +		/* number of bytes to write */ +		s->init_num= len; +		s->state=SSL3_ST_SW_SESSION_TICKET_B; +		s->init_off=0; +		OPENSSL_free(senc); +		} + +	/* 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 | 
