summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2012-07-24 18:11:27 +0000
committerDr. Stephen Henson <steve@openssl.org>2012-07-24 18:11:27 +0000
commitec4a50b3c3f2f50caccfd52e939857a5d6f02fd1 (patch)
treecb856889245aa324e613bece9db3d79f1dab91c1
parentd18b716d259d6d3b68ff7f49d154b9158b98df65 (diff)
Abort handshake if signature algorithm used not supported by peer.
-rw-r--r--CHANGES6
-rw-r--r--ssl/s3_clnt.c27
-rw-r--r--ssl/s3_srvr.c21
-rw-r--r--ssl/ssl.h1
-rw-r--r--ssl/ssl_err.c1
-rw-r--r--ssl/ssl_locl.h2
-rw-r--r--ssl/t1_lib.c39
7 files changed, 63 insertions, 34 deletions
diff --git a/CHANGES b/CHANGES
index fafaf6ddb3..46b23de1da 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
+ *) 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]
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 11ffabb460..e9c1518810 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1750,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])
- {
- 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
@@ -3161,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))
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 28f3bdd6e9..2f23f2121b 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -3051,26 +3051,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
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 09085a23b5..b8b1ba1207 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2452,6 +2452,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
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 665d74fe04..14e8488411 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -288,6 +288,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"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 8b0ea0ee71..d8d1b7918c 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1252,6 +1252,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);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 06db730adc..8b3c213ec6 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -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