Abort handshake if signature algorithm used not supported by peer.
[openssl.git] / ssl / s3_clnt.c
index 8d7bcfef39e287ffc08aea9966e96ecdee7a83a8..e9c1518810b53346e231b14bae53b2f8e59697a7 100644 (file)
@@ -837,6 +837,7 @@ int ssl3_get_server_hello(SSL *s)
        {
        STACK_OF(SSL_CIPHER) *sk;
        const SSL_CIPHER *c;
+       CERT *ct = s->cert;
        unsigned char *p,*d;
        int i,al=SSL_AD_INTERNAL_ERROR,ok;
        unsigned int j;
@@ -959,9 +960,12 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
                goto f_err;
                }
-       /* TLS v1.2 only ciphersuites require v1.2 or later */
-       if ((c->algorithm_ssl & SSL_TLSV1_2) && 
-               (TLS1_get_version(s) < TLS1_2_VERSION))
+       /* 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)
                {
                al=SSL_AD_ILLEGAL_PARAMETER;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
@@ -1643,9 +1647,17 @@ int ssl3_get_key_exchange(SSL *s)
                 * and the ECParameters in this case is just three bytes.
                 */
                param_len=3;
-               if ((param_len > n) ||
-                   (*p != NAMED_CURVE_TYPE) || 
-                   ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0)) 
+               /* Check curve is one of our prefrences, if not server has
+                * sent an invalid curve.
+                */
+               if (!tls1_check_curve(s, p, param_len))
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_CURVE);
+                       goto f_err;
+                       }
+
+               if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0) 
                        {
                        al=SSL_AD_INTERNAL_ERROR;
                        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
@@ -1738,25 +1750,12 @@ int ssl3_get_key_exchange(SSL *s)
                {
                if (TLS1_get_version(s) >= TLS1_2_VERSION)
                        {
-                       int sigalg = tls12_get_sigid(pkey);
-                       /* Should never happen */
-                       if (sigalg == -1)
-                               {
-                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                       int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+                       if (rv == -1)
                                goto err;
-                               }
-                       /* Check key type is consistent with signature */
-                       if (sigalg != (int)p[1])
+                       else if (rv == 0)
                                {
-                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
-                               al=SSL_AD_DECODE_ERROR;
-                               goto f_err;
-                               }
-                       md = tls12_get_hash(p[0]);
-                       if (md == NULL)
-                               {
-                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
-                               al=SSL_AD_DECODE_ERROR;
+                               al = SSL_AD_DECODE_ERROR;
                                goto f_err;
                                }
 #ifdef SSL_DEBUG
@@ -1936,11 +1935,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);
@@ -3138,13 +3148,17 @@ err:
        }
 
 /* Check a certificate can be used for client authentication. Currently
- * just check cert exists and if static DH client certificates can be used.
+ * check cert exists, if we have a suitable digest for TLS 1.2  and if
+ * static DH client certificates can be used.
  */
 static int ssl3_check_client_certificate(SSL *s)
        {
        unsigned long alg_k;
        if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
                return 0;
+       /* If no suitable signature algorithm can't use certificate */
+       if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest)
+               return 0;
        alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
        /* See if we can use client certificate for fixed DH */
        if (alg_k & (SSL_kDHr|SSL_kDHd))