SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
	     STACK_OF(SSL_CIPHER) *srvr)
	{
	SSL_CIPHER *c,*ret=NULL;
	STACK_OF(SSL_CIPHER) *prio, *allow;
	int i,ii,ok;
	CERT *cert;
	unsigned long alg_k,alg_a,mask_k,mask_a,emask_k,emask_a;

	/* Let's see which ciphers we can support */
	cert=s->cert;

#if 0
	/* Do not set the compare functions, because this may lead to a
	 * reordering by "id". We want to keep the original ordering.
	 * We may pay a price in performance during sk_SSL_CIPHER_find(),
	 * but would have to pay with the price of sk_SSL_CIPHER_dup().
	 */
	sk_SSL_CIPHER_set_cmp_func(srvr, ssl_cipher_ptr_id_cmp);
	sk_SSL_CIPHER_set_cmp_func(clnt, ssl_cipher_ptr_id_cmp);
#endif

#ifdef CIPHER_DEBUG
	printf("Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr), (void *)srvr);
	for(i=0 ; i < sk_SSL_CIPHER_num(srvr) ; ++i)
		{
		c=sk_SSL_CIPHER_value(srvr,i);
		printf("%p:%s\n",(void *)c,c->name);
		}
	printf("Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt), (void *)clnt);
	for(i=0 ; i < sk_SSL_CIPHER_num(clnt) ; ++i)
	    {
	    c=sk_SSL_CIPHER_value(clnt,i);
	    printf("%p:%s\n",(void *)c,c->name);
	    }
#endif

	if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s))
		{
		prio = srvr;
		allow = clnt;
		}
	else
		{
		prio = clnt;
		allow = srvr;
		}

	tls1_set_cert_validity(s);

	for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
		{
		c=sk_SSL_CIPHER_value(prio,i);

		/* Skip TLS v1.2 only ciphersuites if not supported */
		if ((c->algorithm_ssl & SSL_TLSV1_2) && 
			!SSL_USE_TLS1_2_CIPHERS(s))
			continue;

		ssl_set_cert_masks(cert,c);
		mask_k = cert->mask_k;
		mask_a = cert->mask_a;
		emask_k = cert->export_mask_k;
		emask_a = cert->export_mask_a;
#ifndef OPENSSL_NO_SRP
		mask_k=cert->mask_k | s->srp_ctx.srp_Mask;
		emask_k=cert->export_mask_k | s->srp_ctx.srp_Mask;
#endif
			
#ifdef KSSL_DEBUG
/*		printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/
#endif    /* KSSL_DEBUG */

		alg_k=c->algorithm_mkey;
		alg_a=c->algorithm_auth;

#ifndef OPENSSL_NO_KRB5
		if (alg_k & SSL_kKRB5)
			{
			if ( !kssl_keytab_is_available(s->kssl_ctx) )
			    continue;
			}
#endif /* OPENSSL_NO_KRB5 */
#ifndef OPENSSL_NO_PSK
		/* with PSK there must be server callback set */
		if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL)
			continue;
#endif /* OPENSSL_NO_PSK */

		if (SSL_C_IS_EXPORT(c))
			{
			ok = (alg_k & emask_k) && (alg_a & emask_a);
#ifdef CIPHER_DEBUG
			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s (export)\n",ok,alg_k,alg_a,emask_k,emask_a,
			       (void *)c,c->name);
#endif
			}
		else
			{
			ok = (alg_k & mask_k) && (alg_a & mask_a);
#ifdef CIPHER_DEBUG
			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n",ok,alg_k,alg_a,mask_k,mask_a,(void *)c,
			       c->name);
#endif
			}

#ifndef OPENSSL_NO_TLSEXT
#ifndef OPENSSL_NO_EC
		/* if we are considering an ECC cipher suite that uses
		 * an ephemeral EC key check it */
		if (alg_k & SSL_kECDHE)
			ok = ok && tls1_check_ec_tmp_key(s, c->id);
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_NO_TLSEXT */

		if (!ok) continue;
		ii=sk_SSL_CIPHER_find(allow,c);
		if (ii >= 0)
			{
			/* Check security callback permits this cipher */
			if (!ssl_security(s, SSL_SECOP_CIPHER_SHARED,
						c->strength_bits, 0, c))
				continue;
#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT)
			if ((alg_k & SSL_kECDHE) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari)
				{
				if (!ret) ret=sk_SSL_CIPHER_value(allow,ii);
				continue;
				}
#endif
			ret=sk_SSL_CIPHER_value(allow,ii);
			break;
			}
		}
	return(ret);
	}