summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--apps/s_apps.h2
-rw-r--r--apps/s_cb.c78
-rw-r--r--apps/s_client.c2
-rw-r--r--apps/s_server.c4
-rw-r--r--ssl/s3_clnt.c13
-rw-r--r--ssl/s3_lib.c122
-rw-r--r--ssl/ssl.h10
-rw-r--r--ssl/ssl_cert.c11
-rw-r--r--ssl/ssl_locl.h7
10 files changed, 238 insertions, 17 deletions
diff --git a/CHANGES b/CHANGES
index 92b6cbfaa3..a597f56ef7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,12 @@
OID NID.
[Steve Henson]
+ *) New ctrls to retrieve and set certificate types in a certificate
+ request message. Print out received values in s_client. If certificate
+ types is not set with custom values set sensible values based on
+ supported signature algorithms.
+ [Steve Henson]
+
*) Support for distinct client and server supported signature algorithms.
[Steve Henson]
diff --git a/apps/s_apps.h b/apps/s_apps.h
index 3491b1ab69..c04e2d3611 100644
--- a/apps/s_apps.h
+++ b/apps/s_apps.h
@@ -160,7 +160,7 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
int set_cert_key_and_authz(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
unsigned char *authz, size_t authz_length);
# endif
-int ssl_print_sigalgs(BIO *out, SSL *s, int client);
+int ssl_print_sigalgs(BIO *out, SSL *s);
int ssl_print_curves(BIO *out, SSL *s);
#endif
int init_client(int *sock, char *server, int port, int type);
diff --git a/apps/s_cb.c b/apps/s_cb.c
index bd487d35db..6e26d43de4 100644
--- a/apps/s_cb.c
+++ b/apps/s_cb.c
@@ -285,9 +285,75 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
return 1;
}
-static int do_print_sigalgs(BIO *out, SSL *s, int client, int shared)
+static void ssl_print_client_cert_types(BIO *bio, SSL *s)
{
- int i, nsig;
+ const unsigned char *p;
+ int i;
+ int cert_type_num = SSL_get0_certificate_types(s, &p);
+ if (!cert_type_num)
+ return;
+ BIO_puts(bio, "Client Certificate Types: ");
+ for (i = 0; i < cert_type_num; i++)
+ {
+ unsigned char cert_type = p[i];
+ char *cname;
+ switch(cert_type)
+ {
+ case TLS_CT_RSA_SIGN:
+ cname = "RSA sign";
+ break;
+
+ case TLS_CT_DSS_SIGN:
+ cname = "DSA sign";
+ break;
+
+ case TLS_CT_RSA_FIXED_DH:
+ cname = "RSA fixed DH";
+ break;
+
+ case TLS_CT_DSS_FIXED_DH:
+ cname = "DSS fixed DH";
+ break;
+
+ case TLS_CT_ECDSA_SIGN:
+ cname = "ECDSA sign";
+ break;
+
+ case TLS_CT_RSA_FIXED_ECDH:
+ cname = "RSA fixed ECDH";
+ break;
+
+ case TLS_CT_ECDSA_FIXED_ECDH:
+ cname = "ECDSA fixed ECDH";
+ break;
+
+ case TLS_CT_GOST94_SIGN:
+ cname = "GOST94 Sign";
+ break;
+
+ case TLS_CT_GOST01_SIGN:
+ cname = "GOST01 Sign";
+ break;
+
+ default:
+ cname = NULL;
+ }
+
+ if (i)
+ BIO_puts(bio, ", ");
+
+ if (cname)
+ BIO_puts(bio, cname);
+ else
+ BIO_printf(bio, "UNKNOWN (%d),", cert_type);
+ }
+ BIO_puts(bio, "\n");
+ }
+
+static int do_print_sigalgs(BIO *out, SSL *s, int shared)
+ {
+ int i, nsig, client;
+ client = SSL_is_server(s) ? 0 : 1;
if (shared)
nsig = SSL_get_shared_sigalgs(s, -1, NULL, NULL, NULL,
NULL, NULL);
@@ -334,10 +400,12 @@ static int do_print_sigalgs(BIO *out, SSL *s, int client, int shared)
return 1;
}
-int ssl_print_sigalgs(BIO *out, SSL *s, int client)
+int ssl_print_sigalgs(BIO *out, SSL *s)
{
- do_print_sigalgs(out, s, client, 0);
- do_print_sigalgs(out, s, client, 1);
+ if (!SSL_is_server(s))
+ ssl_print_client_cert_types(out, s);
+ do_print_sigalgs(out, s, 0);
+ do_print_sigalgs(out, s, 1);
return 1;
}
diff --git a/apps/s_client.c b/apps/s_client.c
index f8469f87c7..999bd2043c 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -2077,7 +2077,7 @@ static void print_stuff(BIO *bio, SSL *s, int full)
BIO_write(bio,"\n",1);
}
- ssl_print_sigalgs(bio, s, 1);
+ ssl_print_sigalgs(bio, s);
BIO_printf(bio,"---\nSSL handshake has read %ld bytes and written %ld bytes\n",
BIO_number_read(SSL_get_rbio(s)),
diff --git a/apps/s_server.c b/apps/s_server.c
index 4b07cb0f07..92ca0a7f85 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -2575,7 +2575,7 @@ static int init_ssl_connection(SSL *con)
if (SSL_get_shared_ciphers(con,buf,sizeof buf) != NULL)
BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
str=SSL_CIPHER_get_name(SSL_get_current_cipher(con));
- ssl_print_sigalgs(bio_s_out, con, 0);
+ ssl_print_sigalgs(bio_s_out, con);
ssl_print_curves(bio_s_out, con);
BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)");
@@ -2890,7 +2890,7 @@ static int www_body(char *hostname, int s, unsigned char *context)
}
BIO_puts(io,"\n");
}
- ssl_print_sigalgs(io, con, 0);
+ ssl_print_sigalgs(io, con);
ssl_print_curves(io, con);
BIO_printf(io,(SSL_cache_hit(con)
?"---\nReused, "
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 8984183c1e..07f3102265 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1937,11 +1937,22 @@ int ssl3_get_certificate_request(SSL *s)
/* 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 516b697321..12fc9bd6bb 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3089,6 +3089,8 @@ static char * MS_CALLBACK srp_password_from_info_cb(SSL *s, void *arg)
}
#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 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
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;
}
@@ -3715,6 +3738,9 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
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;
@@ -4004,8 +4030,61 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
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
@@ -4024,10 +4103,15 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
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) &&
@@ -4042,16 +4126,20 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
}
#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
@@ -4061,12 +4149,32 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
*/
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 e57e160bbd..a327daa6e7 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1655,6 +1655,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#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)
@@ -1749,6 +1751,14 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#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 1edbf18f3b..59a8544431 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -388,6 +388,15 @@ CERT *ssl_cert_dup(CERT *cert)
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 @@ void ssl_cert_free(CERT *c)
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 801e96c429..4b88efe57c 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -533,6 +533,13 @@ typedef struct cert_st
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.