Add new ctrl to retrieve client certificate types, print out
details in s_client.

Also add ctrl to set client certificate types. If not used sensible values
will be included based on supported signature algorithms: for example if
we don't include any DSA signing algorithms the DSA certificate type is
omitted.

Fix restriction in old code where certificate types would be truncated
if it exceeded TLS_CT_NUMBER.
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 8d7bcfe..812af8c 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1936,11 +1936,22 @@
 
 	/* get the certificate types */
 	ctype_num= *(p++);
+	if (s->cert->ctypes)
+		{
+		OPENSSL_free(s->cert->ctypes);
+		s->cert->ctypes = NULL;
+		}
 	if (ctype_num > SSL3_CT_NUMBER)
+		{
+		/* If we exceed static buffer copy all to cert structure */
+		s->cert->ctypes = OPENSSL_malloc(ctype_num);
+		memcpy(s->cert->ctypes, p, ctype_num);
+		s->cert->ctype_num = (size_t)ctype_num;
 		ctype_num=SSL3_CT_NUMBER;
+		}
 	for (i=0; i<ctype_num; i++)
 		s->s3->tmp.ctype[i]= p[i];
-	p+=ctype_num;
+	p+=p[-1];
 	if (TLS1_get_version(s) >= TLS1_2_VERSION)
 		{
 		n2s(p, llen);
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 2c6e1ad..457a5c7 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3089,6 +3089,8 @@
 	}
 #endif
 
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len);
+
 long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
 	{
 	int ret=0;
@@ -3426,6 +3428,27 @@
 	case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
 		return tls1_set_sigalgs_list(s->cert, parg, 1);
 
+	case SSL_CTRL_GET_CLIENT_CERT_TYPES:
+		{
+		const unsigned char **pctype = parg;
+		if (s->server || !s->s3->tmp.cert_req)
+			return 0;
+		if (s->cert->ctypes)
+			{
+			if (pctype)
+				*pctype = s->cert->ctypes;
+			return (int)s->cert->ctype_num;
+			}
+		if (pctype)
+			*pctype = (unsigned char *)s->s3->tmp.ctype;
+		return s->s3->tmp.ctype_num;
+		}
+
+	case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+		if (!s->server)
+			return 0;
+		return ssl3_set_req_cert_type(s->cert, parg, larg);
+
 	default:
 		break;
 		}
@@ -3720,6 +3743,9 @@
 	case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
 		return tls1_set_sigalgs_list(ctx->cert, parg, 1);
 
+	case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+		return ssl3_set_req_cert_type(ctx->cert, parg, larg);
+
 	case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG:
 		ctx->tlsext_authz_server_audit_proof_cb_arg = parg;
 		break;
@@ -4014,8 +4040,61 @@
 int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
 	{
 	int ret=0;
+	const unsigned char *sig;
+	size_t siglen;
+	int have_rsa_sign = 0, have_dsa_sign = 0, have_ecdsa_sign = 0;
+	int nostrict = 1;
 	unsigned long alg_k;
 
+	/* If we have custom certificate types set, use them */
+	if (s->cert->ctypes)
+		{
+		memcpy(p, s->cert->ctypes, s->cert->ctype_num);
+		return (int)s->cert->ctype_num;
+		}
+	/* Else see if we have any signature algorithms configured */
+	if (s->cert->client_sigalgs)
+		{
+		sig = s->cert->client_sigalgs;
+		siglen = s->cert->client_sigalgslen;
+		}
+	else
+		{
+		sig = s->cert->conf_sigalgs;
+		siglen = s->cert->conf_sigalgslen;
+		}
+	/* If we have sigalgs work out if we can sign with RSA, DSA, ECDSA */
+	if (sig)
+		{
+		size_t i;
+		if (s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT)
+			nostrict = 0;
+		for (i = 0; i < siglen; i+=2, sig+=2)
+			{
+			switch(sig[1])
+				{
+			case TLSEXT_signature_rsa:
+				have_rsa_sign = 1;
+				break;
+
+			case TLSEXT_signature_dsa:
+				have_dsa_sign = 1;
+				break;
+
+			case TLSEXT_signature_ecdsa:
+				have_ecdsa_sign = 1;
+				break;
+				}
+			}
+		}
+	/* Otherwise allow anything */
+	else
+		{
+		have_rsa_sign = 1;
+		have_dsa_sign = 1;
+		have_ecdsa_sign = 1;
+		}
+
 	alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
 #ifndef OPENSSL_NO_GOST
@@ -4034,10 +4113,15 @@
 	if (alg_k & (SSL_kDHr|SSL_kEDH))
 		{
 #  ifndef OPENSSL_NO_RSA
-		p[ret++]=SSL3_CT_RSA_FIXED_DH;
+		/* Since this refers to a certificate signed with an RSA
+		 * algorithm, only check for rsa signing in strict mode.
+		 */
+		if (nostrict || have_rsa_sign)
+			p[ret++]=SSL3_CT_RSA_FIXED_DH;
 #  endif
 #  ifndef OPENSSL_NO_DSA
-		p[ret++]=SSL3_CT_DSS_FIXED_DH;
+		if (nostrict || have_dsa_sign)
+			p[ret++]=SSL3_CT_DSS_FIXED_DH;
 #  endif
 		}
 	if ((s->version == SSL3_VERSION) &&
@@ -4052,16 +4136,20 @@
 		}
 #endif /* !OPENSSL_NO_DH */
 #ifndef OPENSSL_NO_RSA
-	p[ret++]=SSL3_CT_RSA_SIGN;
+	if (have_rsa_sign)
+		p[ret++]=SSL3_CT_RSA_SIGN;
 #endif
 #ifndef OPENSSL_NO_DSA
-	p[ret++]=SSL3_CT_DSS_SIGN;
+	if (have_dsa_sign)
+		p[ret++]=SSL3_CT_DSS_SIGN;
 #endif
 #ifndef OPENSSL_NO_ECDH
 	if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->version >= TLS1_VERSION))
 		{
-		p[ret++]=TLS_CT_RSA_FIXED_ECDH;
-		p[ret++]=TLS_CT_ECDSA_FIXED_ECDH;
+		if (nostrict || have_rsa_sign)
+			p[ret++]=TLS_CT_RSA_FIXED_ECDH;
+		if (nostrict || have_ecdsa_sign)
+			p[ret++]=TLS_CT_ECDSA_FIXED_ECDH;
 		}
 #endif
 
@@ -4071,12 +4159,32 @@
 	 */
 	if (s->version >= TLS1_VERSION)
 		{
-		p[ret++]=TLS_CT_ECDSA_SIGN;
+		if (have_ecdsa_sign)
+			p[ret++]=TLS_CT_ECDSA_SIGN;
 		}
 #endif	
 	return(ret);
 	}
 
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len)
+	{
+	if (c->ctypes)
+		{
+		OPENSSL_free(c->ctypes);
+		c->ctypes = NULL;
+		}
+	if (!p || !len)
+		return 1;
+	if (len > 0xff)
+		return 0;
+	c->ctypes = OPENSSL_malloc(len);
+	if (!c->ctypes)
+		return 0;
+	memcpy(c->ctypes, p, len);
+	c->ctype_num = len;
+	return 1;
+	}
+
 int ssl3_shutdown(SSL *s)
 	{
 	int ret;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index a3da0cc..0e78fb7 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1664,6 +1664,8 @@
 #define SSL_CTRL_CLEAR_CERT_FLAGS		100
 #define SSL_CTRL_SET_CLIENT_SIGALGS		101
 #define SSL_CTRL_SET_CLIENT_SIGALGS_LIST	102
+#define SSL_CTRL_GET_CLIENT_CERT_TYPES		103
+#define SSL_CTRL_SET_CLIENT_CERT_TYPES		104
 
 #define DTLSv1_get_timeout(ssl, arg) \
 	SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
@@ -1758,6 +1760,14 @@
 #define SSL_set1_client_sigalgs_list(ctx, s) \
 	SSL_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS_LIST,0,(char *)s)
 
+#define SSL_get0_certificate_types(s, clist) \
+	SSL_ctrl(s, SSL_CTRL_GET_CLIENT_CERT_TYPES, 0, (char *)clist)
+
+#define SSL_CTX_set1_client_certificate_types(ctx, clist, clistlen) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist)
+#define SSL_set1_client_certificate_types(s, clist, clistlen) \
+	SSL_ctrl(s,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist)
+
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_ssl(void);
 BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 1edbf18..59a8544 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -388,6 +388,15 @@
 		ret->client_sigalgs = NULL;
 	/* Shared sigalgs also NULL */
 	ret->shared_sigalgs = NULL;
+	/* Copy any custom client certificate types */
+	if (cert->ctypes)
+		{
+		ret->ctypes = OPENSSL_malloc(cert->ctype_num);
+		if (!ret->ctypes)
+			goto err;
+		memcpy(ret->ctypes, cert->ctypes, cert->ctype_num);
+		ret->ctype_num = cert->ctype_num;
+		}
 
 	ret->cert_flags = cert->cert_flags;
 
@@ -489,6 +498,8 @@
 		OPENSSL_free(c->client_sigalgs);
 	if (c->shared_sigalgs)
 		OPENSSL_free(c->shared_sigalgs);
+	if (c->ctypes)
+		OPENSSL_free(c->ctypes);
 	OPENSSL_free(c);
 	}
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index fd23a9c..7512875 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -531,6 +531,13 @@
 	unsigned int cert_flags;
 	CERT_PKEY pkeys[SSL_PKEY_NUM];
 
+	/* Certificate types (received or sent) in certificate request
+	 * message. On receive this is only set if number of certificate
+	 * types exceeds SSL3_CT_NUMBER.
+	 */
+	unsigned char *ctypes;
+	size_t ctype_num;
+
 	/* signature algorithms peer reports: e.g. supported signature
 	 * algorithms extension for server or as part of a certificate
 	 * request for client.