Abort handshake if signature algorithm used not supported by peer.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 26 Dec 2012 15:27:24 +0000 (15:27 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 26 Dec 2012 15:27:24 +0000 (15:27 +0000)
(backport from HEAD)

CHANGES
ssl/s3_clnt.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_err.c
ssl/ssl_locl.h
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index df99053807229d7272796dc40ca083d2f1cb6972..891adc35805d093e2c49a3b3080086b37cbbf873 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,12 @@
      OID NID.
      [Steve Henson]
 
+  *) If an attempt is made to use a signature algorithm not in the peer
+     preference list abort the handshake. If client has no suitable
+     signature algorithms in response to a certificate request do not
+     use the certificate.
+     [Steve Henson]
+
   *) If server EC tmp key is not in client preference list abort handshake.
      [Steve Henson]
 
index a5f3d02b4c5c4d7cbd4d0d355b44c59e85d91a09..bf695955d182deeba871cc7de780ae30cfedf911 100644 (file)
@@ -1751,25 +1751,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
@@ -3162,13 +3149,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))
index dc20fab790020d12a60d69fbf56085bbe353f9f2..8a15af6dd10593e177dfb32b46c0fd6778b9da81 100644 (file)
@@ -3054,26 +3054,15 @@ int ssl3_get_cert_verify(SSL *s)
                {       
                if (TLS1_get_version(s) >= TLS1_2_VERSION)
                        {
-                       int sigalg = tls12_get_sigid(pkey);
-                       /* Should never happen */
-                       if (sigalg == -1)
+                       int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+                       if (rv == -1)
                                {
-                               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
-                               al=SSL_AD_INTERNAL_ERROR;
+                               al = SSL_AD_INTERNAL_ERROR;
                                goto f_err;
                                }
-                       /* Check key type is consistent with signature */
-                       if (sigalg != (int)p[1])
+                       else if (rv == 0)
                                {
-                               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,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_CERT_VERIFY,SSL_R_UNKNOWN_DIGEST);
-                               al=SSL_AD_DECODE_ERROR;
+                               al = SSL_AD_DECODE_ERROR;
                                goto f_err;
                                }
 #ifdef SSL_DEBUG
index d399fbc971d424a2da5a5c2a1dbf73d16315cd36..3e9b7ef8ad695f6d0d1e2b5cff104c1352636451 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2433,6 +2433,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE                206
 #define SSL_F_SSL_VERIFY_CERT_CHAIN                     207
 #define SSL_F_SSL_WRITE                                         208
+#define SSL_F_TLS12_CHECK_PEER_SIGALG                   333
 #define SSL_F_TLS1_CERT_VERIFY_MAC                      286
 #define SSL_F_TLS1_CHANGE_CIPHER_STATE                  209
 #define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT             274
index d3429403df3982b734d68637d2c068b617b9e8e0..96511be130014d193d70c84dbf0d8e6b67ac4f9c 100644 (file)
@@ -289,6 +289,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE),   "SSL_use_RSAPrivateKey_file"},
 {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN),        "ssl_verify_cert_chain"},
 {ERR_FUNC(SSL_F_SSL_WRITE),    "SSL_write"},
+{ERR_FUNC(SSL_F_TLS12_CHECK_PEER_SIGALG),      "tls12_check_peer_sigalg"},
 {ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
 {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE),     "tls1_change_cipher_state"},
 {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT),        "TLS1_CHECK_SERVERHELLO_TLSEXT"},
index 2e021450823e864324444f7ba360a48b68e7ade4..e0f338dfec6429ceb7216f7028815e307371d217 100644 (file)
@@ -1255,6 +1255,8 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
 long ssl_get_algorithm2(SSL *s);
 int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize);
 size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs);
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+                               const unsigned char *sig, EVP_PKEY *pkey);
 void ssl_set_client_disabled(SSL *s);
 
 int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen);
index 101cfa12a6515a2e1a465f958d7f49e9d4319162..05df5fe491cccd0eb93b785f6d4d5ced13b32cbf 100644 (file)
@@ -680,6 +680,45 @@ size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
                        return sizeof(tls12_sigalgs);
                }
        }
+/* Check signature algorithm is consistent with sent supported signature
+ * algorithms and if so return relevant digest.
+ */
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+                               const unsigned char *sig, EVP_PKEY *pkey)
+       {
+       const unsigned char *sent_sigs;
+       size_t sent_sigslen, i;
+       int sigalg = tls12_get_sigid(pkey);
+       /* Should never happen */
+       if (sigalg == -1)
+               return -1;
+       /* Check key type is consistent with signature */
+       if (sigalg != (int)sig[1])
+               {
+               SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
+               return 0;
+               }
+       /* Check signature matches a type we sent */
+       sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
+       for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2)
+               {
+               if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1])
+                       break;
+               }
+       /* Allow fallback to SHA1 if not strict mode */
+       if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT))
+               {
+               SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
+               return 0;
+               }
+       *pmd = tls12_get_hash(sig[0]);
+       if (*pmd == NULL)
+               {
+               SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_UNKNOWN_DIGEST);
+               return 0;
+               }
+       return 1;
+       }
 /* Get a mask of disabled algorithms: an algorithm is disabled
  * if it isn't supported or doesn't appear in supported signature
  * algorithms. Unlike ssl_cipher_get_disabled this applies to a specific