Use tls_choose_sigalg for client auth.
[openssl.git] / ssl / t1_lib.c
index 31c3b04fc13497974bec5e2d3155c5de7b83bb54..fc9ae687f605152794bcde22e678e106cec9b20a 100644 (file)
@@ -917,7 +917,7 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
         if (SSL_IS_TLS13(s)) {
             /* For TLS 1.3 check curve matches signature algorithm */
 
-            if (curve != lu->curve) {
+            if (lu->curve != NID_undef && curve != lu->curve) {
                 SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
                 return 0;
             }
@@ -1349,58 +1349,6 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick,
     return ret;
 }
 
-int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk,
-                         const EVP_MD *md, int *ispss)
-{
-    int md_id, sig_id;
-    size_t i;
-    const SIGALG_LOOKUP *curr;
-
-    if (md == NULL)
-        return 0;
-    md_id = EVP_MD_type(md);
-    sig_id = EVP_PKEY_id(pk);
-    if (md_id == NID_undef)
-        return 0;
-    /* For TLS 1.3 only allow RSA-PSS */
-    if (SSL_IS_TLS13(s) && sig_id == EVP_PKEY_RSA)
-        sig_id = EVP_PKEY_RSA_PSS;
-
-    if (s->s3->tmp.peer_sigalgs == NULL) {
-        /* Should never happen: we abort if no sigalgs extension and TLS 1.3 */
-        if (SSL_IS_TLS13(s))
-            return 0;
-        /* For TLS 1.2 and no sigalgs lookup using complete table */
-        for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
-             i++, curr++) {
-            if (curr->hash == md_id && curr->sig == sig_id) {
-                if (!WPACKET_put_bytes_u16(pkt, curr->sigalg))
-                    return 0;
-                *ispss = curr->sig == EVP_PKEY_RSA_PSS;
-                return 1;
-            }
-        }
-        return 0;
-    }
-
-    for (i = 0; i < s->cert->shared_sigalgslen; i++) {
-        curr = s->cert->shared_sigalgs[i];
-
-        /*
-         * Look for matching key and hash. If key type is RSA also match PSS
-         * signature type.
-         */
-        if (curr->hash == md_id && (curr->sig == sig_id
-            || (sig_id == EVP_PKEY_RSA && curr->sig == EVP_PKEY_RSA_PSS))){
-            if (!WPACKET_put_bytes_u16(pkt, curr->sigalg))
-                return 0;
-            *ispss = curr->sig == EVP_PKEY_RSA_PSS;
-            return 1;
-        }
-    }
-    return 0;
-}
-
 static int tls12_get_pkey_idx(int sig_nid)
 {
     switch (sig_nid) {
@@ -2316,13 +2264,23 @@ int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy)
 
 /*
  * Choose an appropriate signature algorithm based on available certificates
- * Set current certificate and digest to match chosen algorithm.
+ * Sets chosen certificate and signature algorithm.
+ *
+ * For servers if we fail to find a required certificate it is a fatal error
+ * and an appropriate error code is set and the TLS alert set in *al.
+ *
+ * For clients al is set to NULL. If a certificate is not suitable it is not
+ * a fatal error: we will either try another certificate or not present one
+ * to the server. In this case no error is set.
  */
 int tls_choose_sigalg(SSL *s, int *al)
 {
-    int idx;
+    int idx = -1;
     const SIGALG_LOOKUP *lu = NULL;
 
+    s->s3->tmp.cert = NULL;
+    s->s3->tmp.sigalg = NULL;
+
     if (SSL_IS_TLS13(s)) {
         size_t i;
 #ifndef OPENSSL_NO_EC
@@ -2348,7 +2306,7 @@ int tls_choose_sigalg(SSL *s, int *al)
 
                     curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
                 }
-                if (curve != lu->curve)
+                if (lu->curve != NID_undef && curve != lu->curve)
                     continue;
 #else
                 continue;
@@ -2357,37 +2315,47 @@ int tls_choose_sigalg(SSL *s, int *al)
             break;
         }
         if (i == s->cert->shared_sigalgslen) {
+            if (al == NULL)
+                return 1;
             *al = SSL_AD_HANDSHAKE_FAILURE;
             SSLerr(SSL_F_TLS_CHOOSE_SIGALG,
                    SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
             return 0;
         }
     } else {
-        /* Find index corresponding to ciphersuite */
-        idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
-        /* If no certificate for ciphersuite return */
-        if (idx == -1) {
-            s->s3->tmp.cert = NULL;
-            s->s3->tmp.sigalg = NULL;
-            return 1;
-        }
-        if (idx == SSL_PKEY_GOST_EC) {
-            /* Work out which GOST certificate is avaiable */
-            if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
-                idx = SSL_PKEY_GOST12_512;
-            } else if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) {
-                idx = SSL_PKEY_GOST12_256;
-            } else if (ssl_has_cert(s, SSL_PKEY_GOST01)) {
-                idx = SSL_PKEY_GOST01;
-            } else {
+        if (s->server) {
+            /* Find index corresponding to ciphersuite */
+            idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+            /* If no certificate for ciphersuite return */
+            if (idx == -1)
+                return 1;
+            if (idx == SSL_PKEY_GOST_EC) {
+                /* Work out which GOST certificate is avaiable */
+                if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
+                    idx = SSL_PKEY_GOST12_512;
+                } else if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) {
+                    idx = SSL_PKEY_GOST12_256;
+                } else if (ssl_has_cert(s, SSL_PKEY_GOST01)) {
+                    idx = SSL_PKEY_GOST01;
+                } else {
+                    if (al == NULL)
+                        return 1;
+                    *al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+            } else if (!ssl_has_cert(s, idx)) {
+                if (al == NULL)
+                    return 1;
                 *al = SSL_AD_INTERNAL_ERROR;
                 SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
                 return 0;
             }
-        } else if (!ssl_has_cert(s, idx)) {
-            *al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
-            return 0;
+        } else {
+            /* Find index for client certificate */
+            idx = s->cert->key - s->cert->pkeys;
+            if (!ssl_has_cert(s, idx))
+                return 1;
         }
 
         if (SSL_USE_SIGALGS(s)) {
@@ -2406,6 +2374,8 @@ int tls_choose_sigalg(SSL *s, int *al)
                         break;
                 }
                 if (i == s->cert->shared_sigalgslen) {
+                    if (al == NULL)
+                        return 1;
                     *al = SSL_AD_INTERNAL_ERROR;
                     SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
                     return 0;
@@ -2418,6 +2388,8 @@ int tls_choose_sigalg(SSL *s, int *al)
                 size_t sent_sigslen, i;
 
                 if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) {
+                    if (al == NULL)
+                        return 1;
                     *al = SSL_AD_INTERNAL_ERROR;
                     SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
                     return 0;
@@ -2430,6 +2402,8 @@ int tls_choose_sigalg(SSL *s, int *al)
                         break;
                 }
                 if (i == sent_sigslen) {
+                    if (al == NULL)
+                        return 1;
                     SSLerr(SSL_F_TLS_CHOOSE_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
                     *al = SSL_AD_HANDSHAKE_FAILURE;
                     return 0;
@@ -2437,13 +2411,23 @@ int tls_choose_sigalg(SSL *s, int *al)
             }
         } else {
             if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) {
+                if (al == NULL)
+                    return 1;
                 *al = SSL_AD_INTERNAL_ERROR;
                 SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
                 return 0;
             }
         }
     }
+    if (idx == -1) {
+        if (al != NULL) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+        }
+        return 0;
+    }
     s->s3->tmp.cert = &s->cert->pkeys[idx];
+    s->cert->key = s->s3->tmp.cert;
     s->s3->tmp.sigalg = lu;
     return 1;
 }