static int get_server_hello(SSL *s)
	{
	unsigned char *buf;
	unsigned char *p;
	int i,j;
	unsigned long len;
	STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow;

	buf=(unsigned char *)s->init_buf->data;
	p=buf;
	if (s->state == SSL2_ST_GET_SERVER_HELLO_A)
		{
		i=ssl2_read(s,(char *)&(buf[s->init_num]),11-s->init_num);
		if (i < (11-s->init_num)) 
			return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
		s->init_num = 11;

		if (*(p++) != SSL2_MT_SERVER_HELLO)
			{
			if (p[-1] != SSL2_MT_ERROR)
				{
				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
				SSLerr(SSL_F_GET_SERVER_HELLO,
					SSL_R_READ_WRONG_PACKET_TYPE);
				}
			else
				SSLerr(SSL_F_GET_SERVER_HELLO,
					SSL_R_PEER_ERROR);
			return(-1);
			}
#if 0
		s->hit=(*(p++))?1:0;
		/* Some [PPC?] compilers fail to increment p in above
		   statement, e.g. one provided with Rhapsody 5.5, but
		   most recent example XL C 11.1 for AIX, even without
		   optimization flag... */
#else
		s->hit=(*p)?1:0; p++;
#endif
		s->s2->tmp.cert_type= *(p++);
		n2s(p,i);
		if (i < s->version) s->version=i;
		n2s(p,i); s->s2->tmp.cert_length=i;
		n2s(p,i); s->s2->tmp.csl=i;
		n2s(p,i); s->s2->tmp.conn_id_length=i;
		s->state=SSL2_ST_GET_SERVER_HELLO_B;
		}

	/* SSL2_ST_GET_SERVER_HELLO_B */
	len = 11 + (unsigned long)s->s2->tmp.cert_length + (unsigned long)s->s2->tmp.csl + (unsigned long)s->s2->tmp.conn_id_length;
	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
		{
		SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_MESSAGE_TOO_LONG);
		return -1;
		}
	j = (int)len - s->init_num;
	i = ssl2_read(s,(char *)&(buf[s->init_num]),j);
	if (i != j) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
	if (s->msg_callback)
		s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg); /* SERVER-HELLO */

	/* things are looking good */

	p = buf + 11;
	if (s->hit)
		{
		if (s->s2->tmp.cert_length != 0) 
			{
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_LENGTH_NOT_ZERO);
			return(-1);
			}
		if (s->s2->tmp.cert_type != 0)
			{
			if (!(s->options &
				SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG))
				{
				SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_TYPE_NOT_ZERO);
				return(-1);
				}
			}
		if (s->s2->tmp.csl != 0)
			{
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CIPHER_LIST_NOT_ZERO);
			return(-1);
			}
		}
	else
		{
#ifdef undef
		/* very bad */
		memset(s->session->session_id,0,
			SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES);
		s->session->session_id_length=0;
		*/
#endif

		/* we need to do this in case we were trying to reuse a 
		 * client session but others are already reusing it.
		 * If this was a new 'blank' session ID, the session-id
		 * length will still be 0 */
		if (s->session->session_id_length > 0)
			{
			if (!ssl_get_new_session(s,0))
				{
				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
				return(-1);
				}
			}

		if (ssl2_set_certificate(s,s->s2->tmp.cert_type,
			s->s2->tmp.cert_length,p) <= 0)
			{
			ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
			return(-1);
			}
		p+=s->s2->tmp.cert_length;

		if (s->s2->tmp.csl == 0)
			{
			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_LIST);
			return(-1);
			}

		/* We have just received a list of ciphers back from the
		 * server.  We need to get the ones that match, then select
		 * the one we want the most :-). */

		/* load the ciphers */
		sk=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.csl,
					    &s->session->ciphers);
		p+=s->s2->tmp.csl;
		if (sk == NULL)
			{
			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
			SSLerr(SSL_F_GET_SERVER_HELLO,ERR_R_MALLOC_FAILURE);
			return(-1);
			}

		(void)sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp);

		/* get the array of ciphers we will accept */
		cl=SSL_get_ciphers(s);
		(void)sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp);

		/*
		 * If server preference flag set, choose the first
		 * (highest priority) cipher the server sends, otherwise
		 * client preference has priority.
		 */
		if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
		    {
		    prio = sk;
		    allow = cl;
		    }
		else
		    {
		    prio = cl;
		    allow = sk;
		    }
		/* In theory we could have ciphers sent back that we
		 * don't want to use but that does not matter since we
		 * will check against the list we originally sent and
		 * for performance reasons we should not bother to match
		 * the two lists up just to check. */
		for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
			{
			if (sk_SSL_CIPHER_find(allow,
					     sk_SSL_CIPHER_value(prio,i)) >= 0)
				break;
			}

		if (i >= sk_SSL_CIPHER_num(prio))
			{
			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH);
			return(-1);
			}
		s->session->cipher=sk_SSL_CIPHER_value(prio,i);


		if (s->session->peer != NULL) /* can't happen*/
			{
			ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
			SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
			return(-1);
			}

		s->session->peer = s->session->sess_cert->peer_key->x509;
		/* peer_key->x509 has been set by ssl2_set_certificate. */
		CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509);
		}

	if (s->session->sess_cert == NULL 
      || s->session->peer != s->session->sess_cert->peer_key->x509)
		/* can't happen */
		{
		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
		SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
		return(-1);
		}
		
	s->s2->conn_id_length=s->s2->tmp.conn_id_length;
	if (s->s2->conn_id_length > sizeof s->s2->conn_id)
		{
		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
		SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG);
		return -1;
		}
	memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length);
	return(1);
	}
static int get_server_hello(SSL *s)
	{
	unsigned char *buf;
	unsigned char *p;
	int i,j;
	unsigned long len;
	STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow;

	buf=(unsigned char *)s->init_buf->data;
	p=buf;
	if (s->state == SSL2_ST_GET_SERVER_HELLO_A)
		{
		i=ssl2_read(s,(char *)&(buf[s->init_num]),11-s->init_num);
		if (i < (11-s->init_num)) 
			return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
		s->init_num = 11;

		if (*(p++) != SSL2_MT_SERVER_HELLO)
			{
			if (p[-1] != SSL2_MT_ERROR)
				{
				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
				SSLerr(SSL_F_GET_SERVER_HELLO,
					SSL_R_READ_WRONG_PACKET_TYPE);
				}
			else
				SSLerr(SSL_F_GET_SERVER_HELLO,
					SSL_R_PEER_ERROR);
			return(-1);
			}
#if 0
		s->hit=(*(p++))?1:0;
		 
#else
		s->hit=(*p)?1:0; p++;
#endif
		s->s2->tmp.cert_type= *(p++);
		n2s(p,i);
		if (i < s->version) s->version=i;
		n2s(p,i); s->s2->tmp.cert_length=i;
		n2s(p,i); s->s2->tmp.csl=i;
		n2s(p,i); s->s2->tmp.conn_id_length=i;
		s->state=SSL2_ST_GET_SERVER_HELLO_B;
		}

	 
	len = 11 + (unsigned long)s->s2->tmp.cert_length + (unsigned long)s->s2->tmp.csl + (unsigned long)s->s2->tmp.conn_id_length;
	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
		{
		SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_MESSAGE_TOO_LONG);
		return -1;
		}
	j = (int)len - s->init_num;
	i = ssl2_read(s,(char *)&(buf[s->init_num]),j);
	if (i != j) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
	if (s->msg_callback)
		s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg);  

	 

	p = buf + 11;
	if (s->hit)
		{
		if (s->s2->tmp.cert_length != 0) 
			{
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_LENGTH_NOT_ZERO);
			return(-1);
			}
		if (s->s2->tmp.cert_type != 0)
			{
			if (!(s->options &
				SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG))
				{
				SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_TYPE_NOT_ZERO);
				return(-1);
				}
			}
		if (s->s2->tmp.csl != 0)
			{
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CIPHER_LIST_NOT_ZERO);
			return(-1);
			}
		}
	else
		{
#ifdef undef
		 
		memset(s->session->session_id,0,
			SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES);
		s->session->session_id_length=0;
		*/
#endif

		 
		if (s->session->session_id_length > 0)
			{
			if (!ssl_get_new_session(s,0))
				{
				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
				return(-1);
				}
			}

		if (ssl2_set_certificate(s,s->s2->tmp.cert_type,
			s->s2->tmp.cert_length,p) <= 0)
			{
			ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
			return(-1);
			}
		p+=s->s2->tmp.cert_length;

		if (s->s2->tmp.csl == 0)
			{
			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_LIST);
			return(-1);
			}

		 

		 
		sk=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.csl,
					    &s->session->ciphers);
		p+=s->s2->tmp.csl;
		if (sk == NULL)
			{
			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
			SSLerr(SSL_F_GET_SERVER_HELLO,ERR_R_MALLOC_FAILURE);
			return(-1);
			}

		(void)sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp);

		 
		cl=SSL_get_ciphers(s);
		(void)sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp);

		 
		if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
		    {
		    prio = sk;
		    allow = cl;
		    }
		else
		    {
		    prio = cl;
		    allow = sk;
		    }
		 
		for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
			{
			if (sk_SSL_CIPHER_find(allow,
					     sk_SSL_CIPHER_value(prio,i)) >= 0)
				break;
			}

		if (i >= sk_SSL_CIPHER_num(prio))
			{
			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH);
			return(-1);
			}
		s->session->cipher=sk_SSL_CIPHER_value(prio,i);


		if (s->session->peer != NULL)  
			{
			ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
			SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
			return(-1);
			}

		s->session->peer = s->session->sess_cert->peer_key->x509;
		 
		CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509);
		}

	if (s->session->sess_cert == NULL 
      || s->session->peer != s->session->sess_cert->peer_key->x509)
		 
		{
		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
		SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
		return(-1);
		}
		
	s->s2->conn_id_length=s->s2->tmp.conn_id_length;
	if (s->s2->conn_id_length > sizeof s->s2->conn_id)
		{
		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
		SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG);
		return -1;
		}
	memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length);
	return(1);
	}