perform sanity checks on server certificate type as soon as it is received instead...
[openssl.git] / ssl / s3_clnt.c
index b6345b5fa82b596022d889fa75728711d19714b1..b5c939f9a112a00e6db0f2d19e6ea366da0ae038 100644 (file)
@@ -1225,6 +1225,15 @@ int ssl3_get_server_certificate(SSL *s)
 
        if (need_cert)
                {
+               int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+               if (exp_idx >= 0 && i != exp_idx)
+                       {
+                       x=NULL;
+                       al=SSL_AD_ILLEGAL_PARAMETER;
+                       SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+                               SSL_R_WRONG_CERTIFICATE_TYPE);
+                       goto f_err;
+                       }
                sc->peer_cert_type=i;
                CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
                /* Why would the following ever happen?
@@ -1647,9 +1656,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);
@@ -1742,25 +1759,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])
-                               {
-                               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)
+                       else if (rv == 0)
                                {
-                               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
@@ -1838,10 +1842,13 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
                }
        else
                {
+               /* aNULL or kPSK do not need public keys */
                if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
-                       /* aNULL or kPSK do not need public keys */
                        {
-                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                       /* Might be wrong key type, check it */
+                       if (ssl3_check_cert_and_algorithm(s))
+                               /* Otherwise this shouldn't happen */
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
                        goto err;
                        }
                /* still data left over */
@@ -1968,6 +1975,12 @@ int ssl3_get_certificate_request(SSL *s)
                        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
                        goto err;
                        }
+               /* Clear certificate digests and validity flags */
+               for (i = 0; i < SSL_PKEY_NUM; i++)
+                       {
+                       s->cert->pkeys[i].digest = NULL;
+                       s->cert->pkeys[i].valid_flags = 0;
+                       }
                if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
                        {
                        ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
@@ -3153,13 +3166,24 @@ 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 if
+ * static DH client certificates can be used and optionally checks
+ * suitability for Suite B.
  */
 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;
+       /* If strict mode check suitability of chain before using it.
+        * This also adjusts suite B digest if necessary.
+        */
+       if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+               !tls1_check_chain(s, NULL, NULL, NULL, -2))
+               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))
@@ -3322,6 +3346,16 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                        return 1;
                        }
                }
+       else if (alg_a & SSL_aECDSA)
+               {
+               SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDSA_SIGNING_CERT);
+               goto f_err;
+               }
+       else if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+               {
+               SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDH_CERT);
+               goto f_err;
+               }
 #endif
        pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
        i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);