Allow return of supported ciphers.

New function ssl_cipher_disabled.

Check for disabled client ciphers using ssl_cipher_disabled.

New function to return only supported ciphers.

New option to ciphers utility to print only supported ciphers.
diff --git a/apps/ciphers.c b/apps/ciphers.c
index c9abf1a..52da702 100644
--- a/apps/ciphers.c
+++ b/apps/ciphers.c
@@ -85,6 +85,7 @@
 	{
 	int ret=1,i;
 	int verbose=0,Verbose=0;
+	int use_supported = 0;
 #ifndef OPENSSL_NO_SSL_TRACE
 	int stdname = 0;
 #endif
@@ -129,6 +130,8 @@
 			verbose=1;
 		else if (strcmp(*argv,"-V") == 0)
 			verbose=Verbose=1;
+		else if (strcmp(*argv,"-s") == 0)
+			use_supported = 1;
 #ifndef OPENSSL_NO_SSL_TRACE
 		else if (strcmp(*argv,"-stdname") == 0)
 			stdname=verbose=1;
@@ -179,12 +182,17 @@
 	ssl=SSL_new(ctx);
 	if (ssl == NULL) goto err;
 
+	if (use_supported)
+		sk=SSL_get1_supported_ciphers(ssl);
+	else
+		sk=SSL_get_ciphers(ssl);
 
 	if (!verbose)
 		{
-		for (i=0; ; i++)
+		for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
 			{
-			p=SSL_get_cipher_list(ssl,i);
+			SSL_CIPHER *c = sk_SSL_CIPHER_value(sk,i);
+			p = SSL_CIPHER_get_name(c);
 			if (p == NULL) break;
 			if (i != 0) BIO_printf(STDout,":");
 			BIO_printf(STDout,"%s",p);
@@ -193,7 +201,6 @@
 		}
 	else /* verbose */
 		{
-		sk=SSL_get_ciphers(ssl);
 
 		for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
 			{
@@ -237,6 +244,8 @@
 		ERR_print_errors(bio_err);
 		}
 end:
+	if (use_supported && sk)
+		sk_SSL_CIPHER_free(sk);
 	if (ctx != NULL) SSL_CTX_free(ctx);
 	if (ssl != NULL) SSL_free(ssl);
 	if (STDout != NULL) BIO_free_all(STDout);
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 9755a0f..70c6533 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1079,9 +1079,7 @@
 	/* If it is a disabled cipher we didn't send it in client hello,
 	 * so return an error.
 	 */
-	if (c->algorithm_ssl & ct->mask_ssl ||
-		c->algorithm_mkey & ct->mask_k ||
-		c->algorithm_auth & ct->mask_a)
+	if (ssl_cipher_disabled(s, c))
 		{
 		al=SSL_AD_ILLEGAL_PARAMETER;
 		SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index c6b1ac3..9c200b7 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2378,6 +2378,7 @@
 const SSL_METHOD *DTLS_client_method(void);	/* DTLS 1.0 and 1.2 */
 
 STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
+STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s);
 
 int SSL_do_handshake(SSL *s);
 int SSL_renegotiate(SSL *s);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index cc9b965..1b8c0f4 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1342,6 +1342,33 @@
 	return(NULL);
 	}
 
+STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
+	{
+	STACK_OF(SSL_CIPHER) *sk = NULL, *ciphers;
+	int i;
+	ciphers = SSL_get_ciphers(s);
+	if (!ciphers)
+		return NULL;
+	ssl_set_client_disabled(s);
+	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++)
+		{
+		const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
+		if (!ssl_cipher_disabled(s, c))
+			{
+			if (!sk)
+				sk = sk_SSL_CIPHER_new_null();
+			if (!sk)
+				return NULL;
+			if (!sk_SSL_CIPHER_push(sk, c))
+				{
+				sk_SSL_CIPHER_free(sk);
+				return NULL;
+				}
+			}
+		}
+	return sk;
+	}
+
 /** return a STACK of the ciphers available for the SSL and in order of
  * algorithm id */
 STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
@@ -1459,7 +1486,6 @@
 	{
 	int i,j=0;
 	SSL_CIPHER *c;
-	CERT *ct = s->cert;
 	unsigned char *q;
 	int no_scsv = s->renegotiate;
 	/* Set disabled masks for this session */
@@ -1472,9 +1498,7 @@
 		{
 		c=sk_SSL_CIPHER_value(sk,i);
 		/* Skip disabled ciphers */
-		if (c->algorithm_ssl & ct->mask_ssl ||
-			c->algorithm_mkey & ct->mask_k ||
-			c->algorithm_auth & ct->mask_a)
+		if (ssl_cipher_disabled(s, c))
 			continue;
 #ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
 		if (c->id == SSL3_CK_SCSV)
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index cd397f4..07ea0d2 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1331,6 +1331,7 @@
 int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
 				const unsigned char *sig, EVP_PKEY *pkey);
 void ssl_set_client_disabled(SSL *s);
+int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c);
 
 int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen);
 int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index c9e4898..37cc6f6 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1093,6 +1093,14 @@
 	c->valid = 1;
 	}
 
+int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c)
+	{
+	CERT *ct = s->cert;
+	if (c->algorithm_ssl & ct->mask_ssl || c->algorithm_mkey & ct->mask_k || c->algorithm_auth & ct->mask_a)
+		return 1;
+	return 0;
+	}
+
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al)
 	{
 	int extdatalen=0;