s3_srvr.c

来自「一个用于点对点传输加密的工具包源码」· C语言 代码 · 共 1,755 行 · 第 1/3 页

C
1,755
字号
/* ssl/s3_srvr.c *//* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. *  * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to.  The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code.  The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). *  * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *    "This product includes cryptographic software written by *     Eric Young (eay@cryptsoft.com)" *    The word 'cryptographic' can be left out if the rouines from the library *    being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from  *    the apps directory (application code) you must include an acknowledgement: *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" *  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *  * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed.  i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */#define REUSE_CIPHER_BUG#define NETSCAPE_HANG_BUG#include <stdio.h>#include <openssl/buffer.h>#include <openssl/rand.h>#include <openssl/objects.h>#include <openssl/md5.h>#include <openssl/sha.h>#include <openssl/evp.h>#include <openssl/x509.h>#include "ssl_locl.h"static SSL_METHOD *ssl3_get_server_method(int ver);static int ssl3_get_client_hello(SSL *s);static int ssl3_check_client_hello(SSL *s);static int ssl3_send_server_hello(SSL *s);static int ssl3_send_server_key_exchange(SSL *s);static int ssl3_send_certificate_request(SSL *s);static int ssl3_send_server_done(SSL *s);static int ssl3_get_client_key_exchange(SSL *s);static int ssl3_get_client_certificate(SSL *s);static int ssl3_get_cert_verify(SSL *s);static int ssl3_send_hello_request(SSL *s);static SSL_METHOD *ssl3_get_server_method(int ver)	{	if (ver == SSL3_VERSION)		return(SSLv3_server_method());	else		return(NULL);	}SSL_METHOD *SSLv3_server_method(void)	{	static int init=1;	static SSL_METHOD SSLv3_server_data;	if (init)		{		memcpy((char *)&SSLv3_server_data,(char *)sslv3_base_method(),			sizeof(SSL_METHOD));		SSLv3_server_data.ssl_accept=ssl3_accept;		SSLv3_server_data.get_ssl_method=ssl3_get_server_method;		init=0;		}	return(&SSLv3_server_data);	}int ssl3_accept(SSL *s)	{	BUF_MEM *buf;	unsigned long l,Time=time(NULL);	void (*cb)()=NULL;	long num1;	int ret= -1;	int new_state,state,skip=0;	RAND_add(&Time,sizeof(Time),0);	ERR_clear_error();	clear_sys_error();	if (s->info_callback != NULL)		cb=s->info_callback;	else if (s->ctx->info_callback != NULL)		cb=s->ctx->info_callback;	/* init things to blank */	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);	s->in_handshake++;	if (s->cert == NULL)		{		SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);		return(-1);		}	for (;;)		{		state=s->state;		switch (s->state)			{		case SSL_ST_RENEGOTIATE:			s->new_session=1;			/* s->state=SSL_ST_ACCEPT; */		case SSL_ST_BEFORE:		case SSL_ST_ACCEPT:		case SSL_ST_BEFORE|SSL_ST_ACCEPT:		case SSL_ST_OK|SSL_ST_ACCEPT:			s->server=1;			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);			if ((s->version>>8) != 3)				{				SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_INTERNAL_ERROR);				return -1;				}			s->type=SSL_ST_ACCEPT;			if (s->init_buf == NULL)				{				if ((buf=BUF_MEM_new()) == NULL)					{					ret= -1;					goto end;					}				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))					{					ret= -1;					goto end;					}				s->init_buf=buf;				}			if (!ssl3_setup_buffers(s))				{				ret= -1;				goto end;				}			/* Ok, we now need to push on a buffering BIO so that			 * the output is sent in a way that TCP likes :-)			 */			if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }			s->init_num=0;			if (s->state != SSL_ST_RENEGOTIATE)				{				ssl3_init_finished_mac(s);				s->state=SSL3_ST_SR_CLNT_HELLO_A;				s->ctx->stats.sess_accept++;				}			else				{				s->ctx->stats.sess_accept_renegotiate++;				s->state=SSL3_ST_SW_HELLO_REQ_A;				}			break;		case SSL3_ST_SW_HELLO_REQ_A:		case SSL3_ST_SW_HELLO_REQ_B:			s->shutdown=0;			ret=ssl3_send_hello_request(s);			if (ret <= 0) goto end;			s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;			s->state=SSL3_ST_SW_FLUSH;			s->init_num=0;			ssl3_init_finished_mac(s);			break;		case SSL3_ST_SW_HELLO_REQ_C:			s->state=SSL_ST_OK;			ret=1;			goto end;			/* break; */		case SSL3_ST_SR_CLNT_HELLO_A:		case SSL3_ST_SR_CLNT_HELLO_B:		case SSL3_ST_SR_CLNT_HELLO_C:			s->shutdown=0;			ret=ssl3_get_client_hello(s);			if (ret <= 0) goto end;			s->state=SSL3_ST_SW_SRVR_HELLO_A;			s->init_num=0;			break;		case SSL3_ST_SW_SRVR_HELLO_A:		case SSL3_ST_SW_SRVR_HELLO_B:			ret=ssl3_send_server_hello(s);			if (ret <= 0) goto end;			if (s->hit)				s->state=SSL3_ST_SW_CHANGE_A;			else				s->state=SSL3_ST_SW_CERT_A;			s->init_num=0;			break;		case SSL3_ST_SW_CERT_A:		case SSL3_ST_SW_CERT_B:			/* Check if it is anon DH */			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))				{				ret=ssl3_send_server_certificate(s);				if (ret <= 0) goto end;				}			else				skip=1;			s->state=SSL3_ST_SW_KEY_EXCH_A;			s->init_num=0;			break;		case SSL3_ST_SW_KEY_EXCH_A:		case SSL3_ST_SW_KEY_EXCH_B:			l=s->s3->tmp.new_cipher->algorithms;			/* clear this, it may get reset by			 * send_server_key_exchange */			if (s->options & SSL_OP_EPHEMERAL_RSA)				s->s3->tmp.use_rsa_tmp=1;			else				s->s3->tmp.use_rsa_tmp=0;			/* only send if a DH key exchange, fortezza or			 * RSA but we have a sign only certificate */			if (s->s3->tmp.use_rsa_tmp			    || (l & (SSL_DH|SSL_kFZA))			    || ((l & SSL_kRSA)				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL				    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)					&& EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)					)				    )				)			    )				{				ret=ssl3_send_server_key_exchange(s);				if (ret <= 0) goto end;				}			else				skip=1;			s->state=SSL3_ST_SW_CERT_REQ_A;			s->init_num=0;			break;		case SSL3_ST_SW_CERT_REQ_A:		case SSL3_ST_SW_CERT_REQ_B:			if (/* don't request cert unless asked for it: */				!(s->verify_mode & SSL_VERIFY_PEER) ||				/* if SSL_VERIFY_CLIENT_ONCE is set,				 * don't request cert during re-negotiation: */				((s->session->peer != NULL) &&				 (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||				/* never request cert in anonymous ciphersuites				 * (see section "Certificate request" in SSL 3 drafts				 * and in RFC 2246): */				((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&				 /* ... except when the application insists on verification				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */				 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)))				{				/* no cert request */				skip=1;				s->s3->tmp.cert_request=0;				s->state=SSL3_ST_SW_SRVR_DONE_A;				}			else				{				s->s3->tmp.cert_request=1;				ret=ssl3_send_certificate_request(s);				if (ret <= 0) goto end;#ifndef NETSCAPE_HANG_BUG				s->state=SSL3_ST_SW_SRVR_DONE_A;#else				s->state=SSL3_ST_SW_FLUSH;				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;#endif				s->init_num=0;				}			break;		case SSL3_ST_SW_SRVR_DONE_A:		case SSL3_ST_SW_SRVR_DONE_B:			ret=ssl3_send_server_done(s);			if (ret <= 0) goto end;			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;			s->state=SSL3_ST_SW_FLUSH;			s->init_num=0;			break;				case SSL3_ST_SW_FLUSH:			/* number of bytes to be flushed */			num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);			if (num1 > 0)				{				s->rwstate=SSL_WRITING;				num1=BIO_flush(s->wbio);				if (num1 <= 0) { ret= -1; goto end; }				s->rwstate=SSL_NOTHING;				}			s->state=s->s3->tmp.next_state;			break;		case SSL3_ST_SR_CERT_A:		case SSL3_ST_SR_CERT_B:			/* Check for second client hello (MS SGC) */			ret = ssl3_check_client_hello(s);			if (ret <= 0)				goto end;			if (ret == 2)				s->state = SSL3_ST_SR_CLNT_HELLO_C;			else {				/* could be sent for a DH cert, even if we				 * have not asked for it :-) */				ret=ssl3_get_client_certificate(s);				if (ret <= 0) goto end;				s->init_num=0;				s->state=SSL3_ST_SR_KEY_EXCH_A;			}			break;		case SSL3_ST_SR_KEY_EXCH_A:		case SSL3_ST_SR_KEY_EXCH_B:			ret=ssl3_get_client_key_exchange(s);			if (ret <= 0) goto end;			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 */ 			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]));			break;		case SSL3_ST_SR_CERT_VRFY_A:		case SSL3_ST_SR_CERT_VRFY_B:			/* we should decide if we expected this one */			ret=ssl3_get_cert_verify(s);			if (ret <= 0) goto end;			s->state=SSL3_ST_SR_FINISHED_A;			s->init_num=0;			break;		case SSL3_ST_SR_FINISHED_A:		case SSL3_ST_SR_FINISHED_B:			ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,				SSL3_ST_SR_FINISHED_B);			if (ret <= 0) goto end;			if (s->hit)				s->state=SSL_ST_OK;			else				s->state=SSL3_ST_SW_CHANGE_A;			s->init_num=0;			break;		case SSL3_ST_SW_CHANGE_A:		case SSL3_ST_SW_CHANGE_B:			s->session->cipher=s->s3->tmp.new_cipher;			if (!s->method->ssl3_enc->setup_key_block(s))				{ ret= -1; goto end; }			ret=ssl3_send_change_cipher_spec(s,				SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);			if (ret <= 0) goto end;			s->state=SSL3_ST_SW_FINISHED_A;			s->init_num=0;			if (!s->method->ssl3_enc->change_cipher_state(s,				SSL3_CHANGE_CIPHER_SERVER_WRITE))				{				ret= -1;				goto end;				}			break;		case SSL3_ST_SW_FINISHED_A:		case SSL3_ST_SW_FINISHED_B:			ret=ssl3_send_finished(s,				SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,				s->method->ssl3_enc->server_finished_label,				s->method->ssl3_enc->server_finished_label_len);			if (ret <= 0) goto end;			s->state=SSL3_ST_SW_FLUSH;			if (s->hit)				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;			else				s->s3->tmp.next_state=SSL_ST_OK;			s->init_num=0;			break;		case SSL_ST_OK:			/* clean a few things up */			ssl3_cleanup_key_block(s);			BUF_MEM_free(s->init_buf);			s->init_buf=NULL;			/* remove buffering on output */			ssl_free_wbio_buffer(s);			s->new_session=0;			s->init_num=0;			ssl_update_cache(s,SSL_SESS_CACHE_SERVER);			s->ctx->stats.sess_accept_good++;			/* s->server=1; */			s->handshake_func=ssl3_accept;			ret=1;			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);			goto end;			/* break; */		default:			SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);			ret= -1;			goto end;			/* break; */			}				if (!s->s3->tmp.reuse_message && !skip)			{			if (s->debug)				{				if ((ret=BIO_flush(s->wbio)) <= 0)					goto end;				}			if ((cb != NULL) && (s->state != state))				{				new_state=s->state;				s->state=state;				cb(s,SSL_CB_ACCEPT_LOOP,1);				s->state=new_state;				}			}		skip=0;		}end:	/* BIO_flush(s->wbio); */	if (cb != NULL)		cb(s,SSL_CB_ACCEPT_EXIT,ret);	s->in_handshake--;	return(ret);	}static int ssl3_send_hello_request(SSL *s)	{	unsigned char *p;	if (s->state == SSL3_ST_SW_HELLO_REQ_A)		{		p=(unsigned char *)s->init_buf->data;		*(p++)=SSL3_MT_HELLO_REQUEST;		*(p++)=0;		*(p++)=0;		*(p++)=0;		s->state=SSL3_ST_SW_HELLO_REQ_B;		/* number of bytes to write */		s->init_num=4;		s->init_off=0;		}	/* SSL3_ST_SW_HELLO_REQ_B */	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));	}static int ssl3_check_client_hello(SSL *s)	{	int ok;	long n;	n=ssl3_get_message(s,		SSL3_ST_SR_CERT_A,		SSL3_ST_SR_CERT_B,		-1,		SSL3_RT_MAX_PLAIN_LENGTH,		&ok);	if (!ok) return((int)n);	s->s3->tmp.reuse_message = 1;	if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)		{		/* Throw away what we have done so far in the current handshake,		 * which will now be aborted. (A full SSL_clear would be too much.)		 * I hope that tmp.dh is the only thing that may need to be cleared		 * when a handshake is not completed ... */#ifndef NO_DH		if (s->s3->tmp.dh != NULL)			{			DH_free(s->s3->tmp.dh);			s->s3->tmp.dh = NULL;			}#endif		return 2;		}	return 1;}static int ssl3_get_client_hello(SSL *s)	{	int i,j,ok,al,ret= -1;	long n;	unsigned long id;	unsigned char *p,*d,*q;	SSL_CIPHER *c;	SSL_COMP *comp=NULL;	STACK_OF(SSL_CIPHER) *ciphers=NULL;	/* We do this so that we will respond with our native type.	 * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,	 * This down switching should be handled by a different method.	 * If we are SSLv3, we will respond with SSLv3, even if prompted with	 * TLSv1.	 */	if (s->state == SSL3_ST_SR_CLNT_HELLO_A)		{		s->first_packet=1;		s->state=SSL3_ST_SR_CLNT_HELLO_B;		}	n=ssl3_get_message(s,		SSL3_ST_SR_CLNT_HELLO_B,		SSL3_ST_SR_CLNT_HELLO_C,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?