Add new ctrl to retrieve client certificate types, print out
[openssl.git] / ssl / s3_lib.c
index 9653de6eea462c0bbc6cb3376b1d70c6fab428e2..457a5c7b5c5a3ffdd1b7100d96adb674fe5562a4 100644 (file)
@@ -2988,6 +2988,10 @@ void ssl3_free(SSL *s)
        if (s->s3->handshake_dgst) ssl3_free_digest_list(s);
 #ifndef OPENSSL_NO_SRP
        SSL_SRP_CTX_free(s);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+       if (s->s3->tlsext_authz_client_types != NULL)
+               OPENSSL_free(s->s3->tlsext_authz_client_types);
 #endif
        OPENSSL_cleanse(s->s3,sizeof *s->s3);
        OPENSSL_free(s->s3);
@@ -3032,6 +3036,13 @@ void ssl3_clear(SSL *s)
                s->s3->tmp.ecdh = NULL;
                }
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+       if (s->s3->tlsext_authz_client_types != NULL)
+               {
+               OPENSSL_free(s->s3->tlsext_authz_client_types);
+               s->s3->tlsext_authz_client_types = NULL;
+               }
+#endif
 
        rp = s->s3->rbuf.buf;
        wp = s->s3->wbuf.buf;
@@ -3078,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;
@@ -3403,6 +3416,39 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                s->cert->ecdh_tmp_auto = larg;
                break;
 
+       case SSL_CTRL_SET_SIGALGS:
+               return tls1_set_sigalgs(s->cert, parg, larg, 0);
+
+       case SSL_CTRL_SET_SIGALGS_LIST:
+               return tls1_set_sigalgs_list(s->cert, parg, 0);
+
+       case SSL_CTRL_SET_CLIENT_SIGALGS:
+               return tls1_set_sigalgs(s->cert, parg, larg, 1);
+
+       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;
                }
@@ -3685,6 +3731,21 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                ctx->cert->ecdh_tmp_auto = larg;
                break;
 
+       case SSL_CTRL_SET_SIGALGS:
+               return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
+
+       case SSL_CTRL_SET_SIGALGS_LIST:
+               return tls1_set_sigalgs_list(ctx->cert, parg, 0);
+
+       case SSL_CTRL_SET_CLIENT_SIGALGS:
+               return tls1_set_sigalgs(ctx->cert, parg, larg, 1);
+
+       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;
@@ -3898,6 +3959,8 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *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);
@@ -3956,10 +4019,6 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
 
 #ifndef OPENSSL_NO_TLSEXT
 #ifndef OPENSSL_NO_EC
-               /* if we are considering an ECC cipher suite that uses our
-                * certificate check it */
-               if (alg_a & (SSL_aECDSA|SSL_aECDH))
-                       ok = ok && tls1_check_ec_server_key(s);
                /* if we are considering an ECC cipher suite that uses
                 * an ephemeral EC key check it */
                if (alg_k & SSL_kEECDH)
@@ -3981,8 +4040,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
@@ -4001,10 +4113,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) &&
@@ -4019,16 +4136,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
 
@@ -4038,12 +4159,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;