summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2013-12-15 13:32:24 +0000
committerDr. Stephen Henson <steve@openssl.org>2014-03-28 14:56:30 +0000
commitb362ccab5c1d52086f19d29a32f4acc11073b86b (patch)
treea6a2de4f90c8ce9272164ad448ac78cf95371909
parent66f96fe2d519147097c118d4bf60704c69ed0635 (diff)
Security framework.
Security callback: selects which parameters are permitted including sensible defaults based on bits of security. The "parameters" which can be selected include: ciphersuites, curves, key sizes, certificate signature algorithms, supported signature algorithms, DH parameters, SSL/TLS version, session tickets and compression. In some cases prohibiting the use of a parameters will mean they are not advertised to the peer: for example cipher suites and ECC curves. In other cases it will abort the handshake: e.g DH parameters or the peer key size. Documentation to follow...
-rw-r--r--ssl/s23_clnt.c14
-rw-r--r--ssl/s23_srvr.c6
-rw-r--r--ssl/s2_clnt.c6
-rw-r--r--ssl/s2_srvr.c6
-rw-r--r--ssl/s3_both.c11
-rw-r--r--ssl/s3_clnt.c28
-rw-r--r--ssl/s3_lib.c80
-rw-r--r--ssl/s3_srvr.c44
-rw-r--r--ssl/ssl.h82
-rw-r--r--ssl/ssl_cert.c175
-rw-r--r--ssl/ssl_err.c10
-rw-r--r--ssl/ssl_lib.c65
-rw-r--r--ssl/ssl_locl.h32
-rw-r--r--ssl/ssl_rsa.c15
-rw-r--r--ssl/t1_lib.c440
-rw-r--r--ssl/tls1.h5
16 files changed, 822 insertions, 197 deletions
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 60a028430d..dad7e3af3b 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -259,10 +259,13 @@ static int ssl23_no_ssl2_ciphers(SSL *s)
SSL_CIPHER *cipher;
STACK_OF(SSL_CIPHER) *ciphers;
int i;
+ ssl_set_client_disabled(s);
ciphers = SSL_get_ciphers(s);
for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++)
{
cipher = sk_SSL_CIPHER_value(ciphers, i);
+ if (ssl_cipher_disabled(s, cipher, SSL_SECOP_CIPHER_SUPPORTED))
+ continue;
if (cipher->algorithm_ssl == SSL_SSLV2)
return 0;
}
@@ -309,6 +312,8 @@ static int ssl23_client_hello(SSL *s)
ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1;
+ if (ssl2_compat && !ssl_security(s, SSL_SECOP_SSL2_COMPAT, 0, 0, NULL))
+ ssl2_compat = 0;
if (ssl2_compat && ssl23_no_ssl2_ciphers(s))
ssl2_compat = 0;
@@ -533,8 +538,7 @@ static int ssl23_client_hello(SSL *s)
#ifdef OPENSSL_NO_COMP
*(p++)=1;
#else
- if ((s->options & SSL_OP_NO_COMPRESSION)
- || !s->ctx->comp_methods)
+ if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
j=0;
else
j=sk_SSL_COMP_num(s->ctx->comp_methods);
@@ -750,6 +754,12 @@ static int ssl23_get_server_hello(SSL *s)
goto err;
}
+ if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL))
+ {
+ SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_VERSION_TOO_LOW);
+ goto err;
+ }
+
if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING)
{
/* fatal alert */
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index 9d47c22cb8..cb2b138f08 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -441,6 +441,12 @@ int ssl23_get_client_hello(SSL *s)
}
#endif
+ if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL))
+ {
+ SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,SSL_R_VERSION_TOO_LOW);
+ goto err;
+ }
+
if (s->state == SSL23_ST_SR_CLNT_HELLO_B)
{
/* we have SSLv3/TLSv1 in an SSLv2 header
diff --git a/ssl/s2_clnt.c b/ssl/s2_clnt.c
index 299389addc..3621cf9fac 100644
--- a/ssl/s2_clnt.c
+++ b/ssl/s2_clnt.c
@@ -1056,6 +1056,12 @@ int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data)
ERR_clear_error(); /* but we keep s->verify_result */
s->session->verify_result = s->verify_result;
+ if (i > 1)
+ {
+ SSLerr(SSL_F_SSL2_SET_CERTIFICATE, i);
+ goto err;
+ }
+
/* server's cert for this session */
sc=ssl_sess_cert_new();
if (sc == NULL)
diff --git a/ssl/s2_srvr.c b/ssl/s2_srvr.c
index a16c33a65f..71f677bbec 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -1053,6 +1053,12 @@ static int request_certificate(SSL *s)
i=ssl_verify_cert_chain(s,sk);
+ if (i > 1)
+ {
+ SSLerr(SSL_F_REQUEST_CERTIFICATE, i);
+ goto msg_end;
+ }
+
if (i > 0) /* we like the packet, now check the chksum */
{
EVP_MD_CTX ctx;
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 0a259b1f4f..beef06f96b 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -695,7 +695,7 @@ int ssl3_setup_read_buffer(SSL *s)
len += SSL3_RT_MAX_EXTRA;
}
#ifndef OPENSSL_NO_COMP
- if (!(s->options & SSL_OP_NO_COMPRESSION))
+ if (ssl_allow_compression(s))
len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
#endif
if ((p=freelist_extract(s->ctx, 1, len)) == NULL)
@@ -732,7 +732,7 @@ int ssl3_setup_write_buffer(SSL *s)
+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
+ headerlen + align;
#ifndef OPENSSL_NO_COMP
- if (!(s->options & SSL_OP_NO_COMPRESSION))
+ if (ssl_allow_compression(s))
len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
#endif
if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
@@ -782,3 +782,10 @@ int ssl3_release_read_buffer(SSL *s)
return 1;
}
+int ssl_allow_compression(SSL *s)
+ {
+ if (s->options & SSL_OP_NO_COMPRESSION)
+ return 0;
+ return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL);
+ }
+
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index efc3710abd..9a0b1bda8e 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -240,6 +240,13 @@ int ssl3_connect(SSL *s)
ret = -1;
goto end;
}
+
+ if (!ssl_security(s, SSL_SECOP_VERSION, 0,
+ s->version, NULL))
+ {
+ SSLerr(SSL_F_SSL3_CONNECT, SSL_R_VERSION_TOO_LOW);
+ return -1;
+ }
/* s->version=SSL3_VERSION; */
s->type=SSL_ST_CONNECT;
@@ -871,8 +878,7 @@ int ssl3_client_hello(SSL *s)
*(p++)=1;
#else
- if ((s->options & SSL_OP_NO_COMPRESSION)
- || !s->ctx->comp_methods)
+ if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
j=0;
else
j=sk_SSL_COMP_num(s->ctx->comp_methods);
@@ -1079,7 +1085,7 @@ int ssl3_get_server_hello(SSL *s)
/* If it is a disabled cipher we didn't send it in client hello,
* so return an error.
*/
- if (ssl_cipher_disabled(s, c))
+ if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK))
{
al=SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
@@ -1148,7 +1154,7 @@ int ssl3_get_server_hello(SSL *s)
}
if (j == 0)
comp=NULL;
- else if (s->options & SSL_OP_NO_COMPRESSION)
+ else if (!ssl_allow_compression(s))
{
al=SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED);
@@ -1290,6 +1296,12 @@ int ssl3_get_server_certificate(SSL *s)
goto f_err;
}
ERR_clear_error(); /* but we keep s->verify_result */
+ if (i > 1)
+ {
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, i);
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
sc=ssl_sess_cert_new();
if (sc == NULL) goto err;
@@ -1709,6 +1721,14 @@ int ssl3_get_key_exchange(SSL *s)
p+=i;
n-=param_len;
+ if (!ssl_security(s, SSL_SECOP_TMP_DH,
+ DH_security_bits(dh), 0, dh))
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_DH_KEY_TOO_SMALL);
+ goto f_err;
+ }
+
#ifndef OPENSSL_NO_RSA
if (alg_a & SSL_aRSA)
pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 517b1a27d1..9ff7f15877 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3228,6 +3228,12 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER);
return(ret);
}
+ if (!ssl_security(s, SSL_SECOP_TMP_DH,
+ DH_security_bits(dh), 0, dh))
+ {
+ SSLerr(SSL_F_SSL3_CTRL, SSL_R_DH_KEY_TOO_SMALL);
+ return(ret);
+ }
if ((dh = DHparams_dup(dh)) == NULL)
{
SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB);
@@ -3415,17 +3421,17 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
case SSL_CTRL_CHAIN:
if (larg)
- return ssl_cert_set1_chain(s->cert,
+ return ssl_cert_set1_chain(s, NULL,
(STACK_OF (X509) *)parg);
else
- return ssl_cert_set0_chain(s->cert,
+ return ssl_cert_set0_chain(s, NULL,
(STACK_OF (X509) *)parg);
case SSL_CTRL_CHAIN_CERT:
if (larg)
- return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg);
+ return ssl_cert_add1_chain_cert(s, NULL, (X509 *)parg);
else
- return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg);
+ return ssl_cert_add0_chain_cert(s, NULL, (X509 *)parg);
case SSL_CTRL_GET_CHAIN_CERTS:
*(STACK_OF(X509) **)parg = s->cert->key->chain;
@@ -3533,7 +3539,7 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
return ssl3_set_req_cert_type(s->cert, parg, larg);
case SSL_CTRL_BUILD_CERT_CHAIN:
- return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg);
+ return ssl_build_cert_chain(s, NULL, larg);
case SSL_CTRL_SET_VERIFY_CERT_STORE:
return ssl_cert_set_cert_store(s->cert, parg, 0, larg);
@@ -3736,6 +3742,12 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
DH *new=NULL,*dh;
dh=(DH *)parg;
+ if (!ssl_ctx_security(ctx, SSL_SECOP_TMP_DH,
+ DH_security_bits(dh), 0, dh))
+ {
+ SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_DH_KEY_TOO_SMALL);
+ return 0;
+ }
if ((new=DHparams_dup(dh)) == NULL)
{
SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_DH_LIB);
@@ -3911,7 +3923,7 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
return ssl3_set_req_cert_type(ctx->cert, parg, larg);
case SSL_CTRL_BUILD_CERT_CHAIN:
- return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg);
+ return ssl_build_cert_chain(NULL, ctx, larg);
case SSL_CTRL_SET_VERIFY_CERT_STORE:
return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg);
@@ -3948,17 +3960,17 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
case SSL_CTRL_CHAIN:
if (larg)
- return ssl_cert_set1_chain(ctx->cert,
+ return ssl_cert_set1_chain(NULL, ctx,
(STACK_OF (X509) *)parg);
else
- return ssl_cert_set0_chain(ctx->cert,
+ return ssl_cert_set0_chain(NULL, ctx,
(STACK_OF (X509) *)parg);
case SSL_CTRL_CHAIN_CERT:
if (larg)
- return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg);
+ return ssl_cert_add1_chain_cert(NULL, ctx, (X509 *)parg);
else
- return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
+ return ssl_cert_add0_chain_cert(NULL, ctx, (X509 *)parg);
case SSL_CTRL_GET_CHAIN_CERTS:
*(STACK_OF(X509) **)parg = ctx->cert->key->chain;
@@ -4203,6 +4215,10 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
ii=sk_SSL_CIPHER_find(allow,c);
if (ii >= 0)
{
+ /* Check security callback permits this cipher */
+ if (!ssl_security(s, SSL_SECOP_CIPHER_SHARED,
+ c->strength_bits, 0, c))
+ continue;
#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT)
if ((alg_k & SSL_kECDHE) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari)
{
@@ -4220,14 +4236,8 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
{
int ret=0;
- const unsigned char *sig;
- size_t i, siglen;
- int have_rsa_sign = 0, have_dsa_sign = 0;
-#ifndef OPENSSL_NO_ECDSA
- int have_ecdsa_sign = 0;
-#endif
int nostrict = 1;
- unsigned long alg_k;
+ unsigned long alg_k, alg_a = 0;
/* If we have custom certificate types set, use them */
if (s->cert->ctypes)
@@ -4235,28 +4245,10 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
memcpy(p, s->cert->ctypes, s->cert->ctype_num);
return (int)s->cert->ctype_num;
}
- /* get configured sigalgs */
- siglen = tls12_get_psigalgs(s, &sig);
+ /* Get mask of algorithms disabled by signature list */
+ ssl_set_sig_mask(&alg_a, s, SSL_SECOP_SIGALG_MASK);
if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
nostrict = 0;
- for (i = 0; i < siglen; i+=2, sig+=2)
- {
- switch(sig[1])
- {
- case TLSEXT_signature_rsa:
- have_rsa_sign = 1;
- break;
-
- case TLSEXT_signature_dsa:
- have_dsa_sign = 1;
- break;
-#ifndef OPENSSL_NO_ECDSA
- case TLSEXT_signature_ecdsa:
- have_ecdsa_sign = 1;
- break;
-#endif
- }
- }
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
@@ -4279,11 +4271,11 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
/* Since this refers to a certificate signed with an RSA
* algorithm, only check for rsa signing in strict mode.
*/
- if (nostrict || have_rsa_sign)
+ if (nostrict || !(alg_a & SSL_aRSA))
p[ret++]=SSL3_CT_RSA_FIXED_DH;
# endif
# ifndef OPENSSL_NO_DSA
- if (nostrict || have_dsa_sign)
+ if (nostrict || !(alg_a & SSL_aDSS))
p[ret++]=SSL3_CT_DSS_FIXED_DH;
# endif
}
@@ -4299,19 +4291,19 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
}
#endif /* !OPENSSL_NO_DH */
#ifndef OPENSSL_NO_RSA
- if (have_rsa_sign)
+ if (!(alg_a & SSL_aRSA))
p[ret++]=SSL3_CT_RSA_SIGN;
#endif
#ifndef OPENSSL_NO_DSA
- if (have_dsa_sign)
+ if (!(alg_a & SSL_aDSS))
p[ret++]=SSL3_CT_DSS_SIGN;
#endif
#ifndef OPENSSL_NO_ECDH
if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->version >= TLS1_VERSION))
{
- if (nostrict || have_rsa_sign)
+ if (nostrict || !(alg_a & SSL_aRSA))
p[ret++]=TLS_CT_RSA_FIXED_ECDH;
- if (nostrict || have_ecdsa_sign)
+ if (nostrict || !(alg_a & SSL_aECDSA))
p[ret++]=TLS_CT_ECDSA_FIXED_ECDH;
}
#endif
@@ -4322,7 +4314,7 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
*/
if (s->version >= TLS1_VERSION)
{
- if (have_ecdsa_sign)
+ if (!(alg_a & SSL_aECDSA))
p[ret++]=TLS_CT_ECDSA_SIGN;
}
#endif
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 411b6f6af8..9434923d0d 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -272,6 +272,14 @@ int ssl3_accept(SSL *s)
SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
return -1;
}
+
+ if (!ssl_security(s, SSL_SECOP_VERSION, 0,
+ s->version, NULL))
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_VERSION_TOO_LOW);
+ return -1;
+ }
+
s->type=SSL_ST_ACCEPT;
if (s->init_buf == NULL)
@@ -1305,7 +1313,7 @@ int ssl3_get_client_hello(SSL *s)
int m, comp_id = s->session->compress_meth;
/* Perform sanity checks on resumed compression algorithm */
/* Can't disable compression */
- if (s->options & SSL_OP_NO_COMPRESSION)
+ if (!ssl_allow_compression(s))
{
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
@@ -1340,7 +1348,7 @@ int ssl3_get_client_hello(SSL *s)
}
else if (s->hit)
comp = NULL;
- else if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods)
+ else if (ssl_allow_compression(s) && s->ctx->comp_methods)
{ /* See if we have a match */
int m,nn,o,v,done=0;
@@ -1701,7 +1709,13 @@ int ssl3_send_server_key_exchange(SSL *s)
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
-
+ if (!ssl_security(s, SSL_SECOP_TMP_DH,
+ DH_security_bits(dhp), 0, dhp))
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_DH_KEY_TOO_SMALL);
+ goto f_err;
+ }
if (s->s3->tmp.dh != NULL)
{
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
@@ -2115,9 +2129,13 @@ int ssl3_send_certificate_request(SSL *s)
if (SSL_USE_SIGALGS(s))
{
const unsigned char *psigs;
+ unsigned char *etmp = p;
nl = tls12_get_psigalgs(s, &psigs);
- s2n(nl, p);
- memcpy(p, psigs, nl);
+ /* Skip over length for now */
+ p += 2;
+ nl = tls12_copy_sigalgs(s, p, psigs, nl);
+ /* Now fill in length */
+ s2n(nl, etmp);
p += nl;
n += nl + 2;
}
@@ -3413,6 +3431,7 @@ int ssl3_get_client_certificate(SSL *s)
}
else
{
+ EVP_PKEY *pkey;
i=ssl_verify_cert_chain(s,sk);
if (i <= 0)
{
@@ -3420,6 +3439,21 @@ int ssl3_get_client_certificate(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
}
+ if (i > 1)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, i);
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+ pkey = X509_get_pubkey(sk_X509_value(sk, 0));
+ if (pkey == NULL)
+ {
+ al=SSL3_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
+ SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ goto f_err;
+ }
+ EVP_PKEY_free(pkey);
}
if (s->session->peer != NULL) /* This should not be needed */
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 9c200b798e..92ffae95c1 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2573,6 +2573,80 @@ void SSL_trace(int write_p, int version, int content_type,
const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c);
#endif
+/* What the "other" parameter contains in security callback */
+/* Mask for type */
+#define SSL_SECOP_OTHER_TYPE 0xffff0000
+#define SSL_SECOP_OTHER_NONE 0
+#define SSL_SECOP_OTHER_CIPHER (1 << 16)
+#define SSL_SECOP_OTHER_CURVE (2 << 16)
+#define SSL_SECOP_OTHER_DH (3 << 16)
+#define SSL_SECOP_OTHER_PKEY (4 << 16)
+#define SSL_SECOP_OTHER_SIGALG (5 << 16)
+#define SSL_SECOP_OTHER_CERT (6 << 16)
+
+/* Indicated operation refers to peer key or certificate */
+#define SSL_SECOP_PEER 0x1000
+
+/* Values for "op" parameter in security callback */
+
+/* Called to filter ciphers */
+/* Ciphers client supports */
+#define SSL_SECOP_CIPHER_SUPPORTED (1 | SSL_SECOP_OTHER_CIPHER)
+/* Cipher shared by client/server */
+#define SSL_SECOP_CIPHER_SHARED (2 | SSL_SECOP_OTHER_CIPHER)
+/* Sanity check of cipher server selects */
+#define SSL_SECOP_CIPHER_CHECK (3 | SSL_SECOP_OTHER_CIPHER)
+/* Curves supported by client */
+#define SSL_SECOP_CURVE_SUPPORTED (4 | SSL_SECOP_OTHER_CURVE)
+/* Curves shared by client/server */
+#define SSL_SECOP_CURVE_SHARED (5 | SSL_SECOP_OTHER_CURVE)
+/* Sanity check of curve server selects */
+#define SSL_SECOP_CURVE_CHECK (6 | SSL_SECOP_OTHER_CURVE)
+/* Temporary DH key */
+#define SSL_SECOP_TMP_DH (7 | SSL_SECOP_OTHER_DH)
+/* Whether to use SSLv2 compatible client hello */
+#define SSL_SECOP_SSL2_COMPAT (8 | SSL_SECOP_OTHER_NONE)
+/* SSL/TLS version */
+#define SSL_SECOP_VERSION (9 | SSL_SECOP_OTHER_NONE)
+/* Session tickets */
+#define SSL_SECOP_TICKET (10 | SSL_SECOP_OTHER_NONE)
+/* Supported signature algorithms sent to peer */
+#define SSL_SECOP_SIGALG_SUPPORTED (11 | SSL_SECOP_OTHER_SIGALG)
+/* Shared signature algorithm */
+#define SSL_SECOP_SIGALG_SHARED (12 | SSL_SECOP_OTHER_SIGALG)
+/* Sanity check signature algorithm allowed */
+#define SSL_SECOP_SIGALG_CHECK (13 | SSL_SECOP_OTHER_SIGALG)
+/* Used to get mask of supported public key signature algorithms */
+#define SSL_SECOP_SIGALG_MASK (14 | SSL_SECOP_OTHER_SIGALG)
+/* Use to see if compression is allowed */
+#define SSL_SECOP_COMPRESSION (15 | SSL_SECOP_OTHER_NONE)
+/* EE key in certificate */
+#define SSL_SECOP_EE_KEY (16 | SSL_SECOP_OTHER_CERT)
+/* CA key in certificate */
+#define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT)
+/* CA digest algorithm in certificate */
+#define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT)
+/* Peer EE key in certificate */
+#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER)
+/* Peer CA key in certificate */
+#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER)
+/* Peer CA digest algorithm in certificate */
+#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER)
+
+void SSL_set_security_level(SSL *s, int level);
+int SSL_get_security_level(const SSL *s);
+void SSL_set_security_callback(SSL *s, int (*cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex));
+int (*SSL_get_security_callback(const SSL *s))(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex);
+void SSL_set0_security_ex_data(SSL *s, void *ex);
+void *SSL_get0_security_ex_data(const SSL *s);
+
+void SSL_CTX_set_security_level(SSL_CTX *ctx, int level);
+int SSL_CTX_get_security_level(const SSL_CTX *ctx);
+void SSL_CTX_set_security_callback(SSL_CTX *ctx, int (*cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex));
+int (*SSL_CTX_get_security_callback(const SSL_CTX *ctx))(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex);
+void SSL_CTX_set0_security_ex_data(SSL_CTX *ctx, void *ex);
+void *SSL_CTX_get0_security_ex_data(const SSL_CTX *ctx);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -2710,10 +2784,12 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL_BAD_METHOD 160
#define SSL_F_SSL_BUILD_CERT_CHAIN 332
#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
+#define SSL_F_SSL_CERT_ADD0_CHAIN_CERT 339
#define SSL_F_SSL_CERT_DUP 221
#define SSL_F_SSL_CERT_INST 222
#define SSL_F_SSL_CERT_INSTANTIATE 214
#define SSL_F_SSL_CERT_NEW 162
+#define SSL_F_SSL_CERT_SET0_CHAIN 340
#define SSL_F_SSL_CHECK_PRIVATE_KEY 163
#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280
#define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279
@@ -2874,6 +2950,8 @@ void ERR_load_SSL_strings(void);
#define SSL_R_BN_LIB 130
#define SSL_R_CA_DN_LENGTH_MISMATCH 131
#define SSL_R_CA_DN_TOO_LONG 132
+#define SSL_R_CA_KEY_TOO_SMALL 397
+#define SSL_R_CA_MD_TOO_WEAK 398
#define SSL_R_CCS_RECEIVED_EARLY 133
#define SSL_R_CERTIFICATE_VERIFY_FAILED 134
#define SSL_R_CERT_CB_ERROR 377
@@ -2895,6 +2973,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_DATA_LENGTH_TOO_LONG 146
#define SSL_R_DECRYPTION_FAILED 147
#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281
+#define SSL_R_DH_KEY_TOO_SMALL 394
#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148
#define SSL_R_DIGEST_CHECK_FAILED 149
#define SSL_R_DTLS_MESSAGE_TOO_BIG 334
@@ -2904,6 +2983,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322
#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323
#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310
+#define SSL_R_EE_KEY_TOO_SMALL 399
#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354
#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150
#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282
@@ -2931,6 +3011,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325
#define SSL_R_INVALID_TRUST 279
#define SSL_R_KEY_ARG_TOO_LONG 284
+#define SSL_R_KEY_TOO_SMALL 395
#define SSL_R_KRB5 285
#define SSL_R_KRB5_C_CC_PRINC 286
#define SSL_R_KRB5_C_GET_CRED 287
@@ -3132,6 +3213,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_UNSUPPORTED_SSL_VERSION 259
#define SSL_R_UNSUPPORTED_STATUS_TYPE 329
#define SSL_R_USE_SRTP_NOT_NEGOTIATED 369
+#define SSL_R_VERSION_TOO_LOW 396
#define SSL_R_WRITE_BIO_NOT_SET 260
#define SSL_R_WRONG_CERTIFICATE_TYPE 383
#define SSL_R_WRONG_CIPHER_RETURNED 261
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 665623eed8..d56b2c5dd5 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -132,6 +132,8 @@
#include <openssl/bn.h>
#include "ssl_locl.h"
+static int ssl_security_default_callback(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex);
+
int SSL_get_ex_data_X509_STORE_CTX_idx(void)
{
static volatile int ssl_x509_store_ctx_idx= -1;
@@ -190,6 +192,9 @@ CERT *ssl_cert_new(void)
ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
ret->references=1;
ssl_cert_set_default_md(ret);
+ ret->sec_cb = ssl_security_default_callback;
+ ret->sec_level = OPENSSL_TLS_SECURITY_LEVEL;
+ ret->sec_ex = NULL;
return(ret);
}
@@ -414,6 +419,10 @@ CERT *ssl_cert_dup(CERT *cert)
ret->ciphers_raw = NULL;
+ ret->sec_cb = cert->sec_cb;
+ ret->sec_level = cert->sec_level;
+ ret->sec_ex = cert->sec_ex;
+
return(ret);
#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
@@ -553,26 +562,36 @@ int ssl_cert_inst(CERT **o)
return(1);
}
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain)
+int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain)
{
- CERT_PKEY *cpk = c->key;
+ int i, r;
+ CERT_PKEY *cpk = s ? s->cert->key : ctx->cert->key;
if (!cpk)
return 0;
if (cpk->chain)
sk_X509_pop_free(cpk->chain, X509_free);
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ r = ssl_security_cert(s, ctx, sk_X509_value(chain, i), 0, 0);
+ if (r != 1)
+ {
+ SSLerr(SSL_F_SSL_CERT_SET0_CHAIN, r);
+ return 0;
+ }
+ }
cpk->chain = chain;
return 1;
}
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain)
+int ssl_cert_set1_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain)
{
STACK_OF(X509) *dchain;
if (!chain)
- return ssl_cert_set0_chain(c, NULL);
+ return ssl_cert_set0_chain(s, ctx, NULL);
dchain = X509_chain_up_ref(chain);
if (!dchain)
return 0;
- if (!ssl_cert_set0_chain(c, dchain))
+ if (!ssl_cert_set0_chain(s, ctx, dchain))
{
sk_X509_pop_free(dchain, X509_free);
return 0;
@@ -580,11 +599,18 @@ int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain)
return 1;
}
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x)
+int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x)
{
- CERT_PKEY *cpk = c->key;
+ int r;
+ CERT_PKEY *cpk = s ? s->cert->key : ctx->cert->key;
if (!cpk)
return 0;
+ r = ssl_security_cert(s, ctx, x, 0, 0);
+ if (r != 1)
+ {
+ SSLerr(SSL_F_SSL_CERT_ADD0_CHAIN_CERT, r);
+ return 0;
+ }
if (!cpk->chain)
cpk->chain = sk_X509_new_null();
if (!cpk->chain || !sk_X509_push(cpk->chain, x))
@@ -592,9 +618,9 @@ int ssl_cert_add0_chain_cert(CERT *c, X509 *x)
return 1;
}
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x)
+int ssl_cert_add1_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x)
{
- if (!ssl_cert_add0_chain_cert(c, x))
+ if (!ssl_cert_add0_chain_cert(s, ctx, x))
return 0;
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
return 1;
@@ -790,6 +816,14 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
{
#ifndef OPENSSL_NO_X509_VERIFY
i=X509_verify_cert(&ctx);
+#if 0
+ /* Dummy error calls so mkerr generates them */
+ SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,SSL_R_EE_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,SSL_R_CA_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,SSL_R_CA_MD_TOO_WEAK);
+#endif
+ if (i > 0)
+ i = ssl_security_cert_chain(s, ctx.chain, NULL, 1);
#else
i=0;
ctx.error=X509_V_ERR_APPLICATION_VERIFICATION;
@@ -1159,6 +1193,13 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
X509_verify_cert(&xs_ctx);
/* Don't leave errors in the queue */
ERR_clear_error();
+ i = ssl_security_cert_chain(s, xs_ctx.chain, NULL, 0);
+ if (i != 1)
+ {
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, i);
+ return 0;
+ }
for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
{
x = sk_X509_value(xs_ctx.chain, i);
@@ -1173,6 +1214,12 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
}
else
{
+ i = ssl_security_cert_chain(s, extra_certs, x, 0);
+ if (i != 1)
+ {
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, i);
+ return 0;
+ }
if (!ssl_add_cert_to_buf(buf, l, x))
return 0;
for (i=0; i<sk_X509_num(extra_certs); i++)
@@ -1186,9 +1233,11 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
}
/* Build a certificate chain for current certificate */
-int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
+int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags)
{
+ CERT *c = s ? s->cert : ctx->cert;
CERT_PKEY *cpk = c->key;
+ X509_STORE *chain_store = NULL;
X509_STORE_CTX xs_ctx;
STACK_OF(X509) *chain = NULL, *untrusted = NULL;
X509 *x;
@@ -1232,6 +1281,10 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
{
if (c->chain_store)
chain_store = c->chain_store;
+ else if (s)
+ chain_store = s->ctx->cert_store;
+ else
+ chain_store = ctx->cert_store;
if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
untrusted = cpk->chain;
@@ -1266,8 +1319,6 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
goto err;
}
X509_STORE_CTX_cleanup(&xs_ctx);
- if (cpk->chain)
- sk_X509_pop_free(cpk->chain, X509_free);
/* Remove EE certificate from chain */
x = sk_X509_shift(chain);
X509_free(x);
@@ -1285,6 +1336,23 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
}
}
}
+ /* Check security level of all CA certificates: EE will have been
+ * checked already.
+ */
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ x = sk_X509_value(chain, i);
+ rv = ssl_security_cert(s, ctx, x, 0, 0);
+ if (rv != 1)
+ {
+ SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, rv);
+ sk_X509_pop_free(chain, X509_free);
+ rv = 0;
+ goto err;
+ }
+ }
+ if (cpk->chain)
+ sk_X509_pop_free(cpk->chain, X509_free);
cpk->chain = chain;
if (rv == 0)
rv = 1;
@@ -1310,3 +1378,86 @@ int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)
return 1;
}
+static int ssl_security_default_callback(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex)
+ {
+ int level, minbits;
+ static const int minbits_table[5] = {80, 112, 128, 192, 256};
+ if (ctx)
+ level = SSL_CTX_get_security_level(ctx);
+ else
+ level = SSL_get_security_level(s);
+ /* Level 0: anything goes */
+ if (level <= 0)
+ return 1;
+ if (level > 5)
+ level = 5;
+ minbits = minbits_table[level - 1];
+ switch (op)
+ {
+ case SSL_SECOP_CIPHER_SUPPORTED:
+ case SSL_SECOP_CIPHER_SHARED:
+ case SSL_SECOP_CIPHER_CHECK:
+ {
+ const SSL_CIPHER *c = other;
+ /* No ciphers below security level */
+ if (bits < minbits)
+ return 0;
+ /* No SSLv2 ciphers */
+ if ((SSL_CIPHER_get_id(c) >> 24) == 0x2)
+ return 0;
+ /* No unauthenticated ciphersuites */
+ if (c->algorithm_auth & SSL_aNULL)
+ return 0;
+ /* No MD5 mac ciphersuites */
+ if (c->algorithm_mac & SSL_MD5)
+ return 0;
+ /* Level 2: no RC4 */
+ if (level >= 2 && c->algorithm_enc == SSL_RC4)
+ return 0;
+ /* Level 3: forward secure ciphersuites only */
+ if (level >= 3 && !(c->algorithm_mkey & (SSL_kEDH|SSL_kEECDH)))
+ return 0;
+ break;
+ }
+ case SSL_SECOP_VERSION:
+ /* SSLv2 allowed only on level zero */
+ if (nid == SSL2_VERSION)
+ return 0;
+ /* SSLv3 not allowed on level 2 */
+ if (nid <= SSL3_VERSION && level >= 2)
+ return 0;
+ /* TLS v1.1 and above only for level 3 */
+ if (nid <= TLS1_VERSION && level >= 3)
+ return 0;
+ /* TLS v1.2 only for level 4 and above */
+ if (nid <= TLS1_1_VERSION && level >= 4)
+ return 0;
+ break;
+
+ case SSL_SECOP_COMPRESSION:
+ if (level >= 2)
+ return 0;
+ break;
+ case SSL_SECOP_TICKET:
+ if (level >= 3)
+ return 0;
+ break;
+ case SSL_SECOP_SSL2_COMPAT:
+ /* SSLv2 compatible client hello only for level zero */
+ return 0;
+ default:
+ if (bits < minbits)
+ return 0;
+ }
+ return 1;
+ }
+