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...
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 60a0284..dad7e3a 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -259,10 +259,13 @@
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 @@
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 @@
#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 @@
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 9d47c22..cb2b138 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -441,6 +441,12 @@
}
#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 299389a..3621cf9 100644
--- a/ssl/s2_clnt.c
+++ b/ssl/s2_clnt.c
@@ -1056,6 +1056,12 @@
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 a16c33a..71f677b 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -1053,6 +1053,12 @@
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 0a259b1..beef06f 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -695,7 +695,7 @@
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 @@
+ 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 @@
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 efc3710..9a0b1bd 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -240,6 +240,13 @@
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 @@
*(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 @@
/* 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 @@
}
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 @@
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 @@
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 517b1a2..9ff7f15 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3228,6 +3228,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
}
#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 @@
*/
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 411b6f6..9434923 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -272,6 +272,14 @@
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 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 @@
}
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 @@
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 @@
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 @@
}
else
{
+ EVP_PKEY *pkey;
i=ssl_verify_cert_chain(s,sk);
if (i <= 0)
{
@@ -3420,6 +3439,21 @@
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 9c200b7..92ffae9 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2573,6 +2573,80 @@
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 @@
#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 @@
#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 @@
#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 @@
#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 @@
#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 @@
#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 665623e..d56b2c5 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
#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 @@
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 @@
}
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 @@
}
/* 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 @@
{
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 @@
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 @@
}
}
}
+ /* 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 @@
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;
+ }
+
+int ssl_security(SSL *s, int op, int bits, int nid, void *other)
+ {
+ return s->cert->sec_cb(s, NULL, op, bits, nid, other, s->cert->sec_ex);
+ }
+
+int ssl_ctx_security(SSL_CTX *ctx, int op, int bits, int nid, void *other)
+ {
+ return ctx->cert->sec_cb(NULL, ctx, op, bits, nid, other, ctx->cert->sec_ex);
+ }
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index e663483..6a30748 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -1,6 +1,6 @@
/* ssl/ssl_err.c */
/* ====================================================================
- * Copyright (c) 1999-2013 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1999-2014 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -198,10 +198,12 @@
{ERR_FUNC(SSL_F_SSL_BAD_METHOD), "ssl_bad_method"},
{ERR_FUNC(SSL_F_SSL_BUILD_CERT_CHAIN), "ssl_build_cert_chain"},
{ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "ssl_bytes_to_cipher_list"},
+{ERR_FUNC(SSL_F_SSL_CERT_ADD0_CHAIN_CERT), "ssl_cert_add0_chain_cert"},
{ERR_FUNC(SSL_F_SSL_CERT_DUP), "ssl_cert_dup"},
{ERR_FUNC(SSL_F_SSL_CERT_INST), "ssl_cert_inst"},
{ERR_FUNC(SSL_F_SSL_CERT_INSTANTIATE), "SSL_CERT_INSTANTIATE"},
{ERR_FUNC(SSL_F_SSL_CERT_NEW), "ssl_cert_new"},
+{ERR_FUNC(SSL_F_SSL_CERT_SET0_CHAIN), "ssl_cert_set0_chain"},
{ERR_FUNC(SSL_F_SSL_CHECK_PRIVATE_KEY), "SSL_check_private_key"},
{ERR_FUNC(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT), "SSL_CHECK_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG), "ssl_check_srvr_ecc_cert_and_alg"},
@@ -365,6 +367,8 @@
{ERR_REASON(SSL_R_BN_LIB) ,"bn lib"},
{ERR_REASON(SSL_R_CA_DN_LENGTH_MISMATCH) ,"ca dn length mismatch"},
{ERR_REASON(SSL_R_CA_DN_TOO_LONG) ,"ca dn too long"},
+{ERR_REASON(SSL_R_CA_KEY_TOO_SMALL) ,"ca key too small"},
+{ERR_REASON(SSL_R_CA_MD_TOO_WEAK) ,"ca md too weak"},
{ERR_REASON(SSL_R_CCS_RECEIVED_EARLY) ,"ccs received early"},
{ERR_REASON(SSL_R_CERTIFICATE_VERIFY_FAILED),"certificate verify failed"},
{ERR_REASON(SSL_R_CERT_CB_ERROR) ,"cert cb error"},
@@ -386,6 +390,7 @@
{ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG) ,"data length too long"},
{ERR_REASON(SSL_R_DECRYPTION_FAILED) ,"decryption failed"},
{ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),"decryption failed or bad record mac"},
+{ERR_REASON(SSL_R_DH_KEY_TOO_SMALL) ,"dh key too small"},
{ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),"dh public value length is wrong"},
{ERR_REASON(SSL_R_DIGEST_CHECK_FAILED) ,"digest check failed"},
{ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG) ,"dtls message too big"},
@@ -395,6 +400,7 @@
{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE),"ecc cert should have rsa signature"},
{ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE),"ecc cert should have sha1 signature"},
{ERR_REASON(SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER),"ecgroup too large for cipher"},
+{ERR_REASON(SSL_R_EE_KEY_TOO_SMALL) ,"ee key too small"},
{ERR_REASON(SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),"empty srtp protection profile list"},
{ERR_REASON(SSL_R_ENCRYPTED_LENGTH_TOO_LONG),"encrypted length too long"},
{ERR_REASON(SSL_R_ERROR_GENERATING_TMP_RSA_KEY),"error generating tmp rsa key"},
@@ -422,6 +428,7 @@
{ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
{ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"},
+{ERR_REASON(SSL_R_KEY_TOO_SMALL) ,"key too small"},
{ERR_REASON(SSL_R_KRB5) ,"krb5"},
{ERR_REASON(SSL_R_KRB5_C_CC_PRINC) ,"krb5 client cc principal (no tkt?)"},
{ERR_REASON(SSL_R_KRB5_C_GET_CRED) ,"krb5 client get cred"},
@@ -623,6 +630,7 @@
{ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"},
{ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED),"use srtp not negotiated"},
+{ERR_REASON(SSL_R_VERSION_TOO_LOW) ,"version too low"},
{ERR_REASON(SSL_R_WRITE_BIO_NOT_SET) ,"write bio not set"},
{ERR_REASON(SSL_R_WRONG_CERTIFICATE_TYPE),"wrong certificate type"},
{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 1b8c0f4..c6ca137 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1353,7 +1353,7 @@
for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++)
{
const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
- if (!ssl_cipher_disabled(s, c))
+ if (!ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
{
if (!sk)
sk = sk_SSL_CIPHER_new_null();
@@ -1498,7 +1498,7 @@
{
c=sk_SSL_CIPHER_value(sk,i);
/* Skip disabled ciphers */
- if (ssl_cipher_disabled(s, c))
+ if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
continue;
#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
if (c->id == SSL3_CK_SCSV)
@@ -3640,6 +3640,67 @@
return s->server;
}
+void SSL_set_security_level(SSL *s, int level)
+ {
+ s->cert->sec_level = level;
+ }
+
+int SSL_get_security_level(const SSL *s)
+ {
+ return s->cert->sec_level;
+ }
+
+void SSL_set_security_callback(SSL *s, int (*cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex))
+ {
+ s->cert->sec_cb = cb;
+ }
+
+int (*SSL_get_security_callback(const SSL *s))(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex)
+ {
+ return s->cert->sec_cb;
+ }
+
+void SSL_set0_security_ex_data(SSL *s, void *ex)
+ {
+ s->cert->sec_ex = ex;
+ }
+
+void *SSL_get0_security_ex_data(const SSL *s)
+ {
+ return s->cert->sec_ex;
+ }
+
+void SSL_CTX_set_security_level(SSL_CTX *ctx, int level)
+ {
+ ctx->cert->sec_level = level;
+ }
+
+int SSL_CTX_get_security_level(const SSL_CTX *ctx)
+ {
+ return ctx->cert->sec_level;
+ }
+
+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))
+ {
+ ctx->cert->sec_cb = cb;
+ }
+
+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)
+ {
+ return ctx->cert->sec_cb;
+ }
+
+void SSL_CTX_set0_security_ex_data(SSL_CTX *ctx, void *ex)
+ {
+ ctx->cert->sec_ex = ex;
+ }
+
+void *SSL_CTX_get0_security_ex_data(const SSL_CTX *ctx)
+ {
+ return ctx->cert->sec_ex;
+ }
+
+
#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
#include "../crypto/bio/bss_file.c"
#endif
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 07ea0d2..0f51594 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -627,6 +627,13 @@
unsigned char *ciphers_raw;
size_t ciphers_rawlen;
+ /* Security callback */
+ int (*sec_cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex);
+ /* Security level */
+ int sec_level;
+
+ void *sec_ex;
+
int references; /* >1 only if SSL_copy_session_id is used */
} CERT;
@@ -995,10 +1002,10 @@
int ssl_get_handshake_digest(int i,long *mask,const EVP_MD **md);
int ssl_cipher_get_cert_index(const SSL_CIPHER *c);
const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr);
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x);
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x);
+int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
+int ssl_cert_set1_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
+int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x);
+int ssl_cert_add1_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x);
int ssl_cert_select_current(CERT *c, X509 *x);
int ssl_cert_set_current(CERT *c, long arg);
X509 *ssl_cert_get0_next_certificate(CERT *c, int first);
@@ -1006,8 +1013,12 @@
int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk);
int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l);
-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);
int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref);
+
+int ssl_security(SSL *s, int op, int bits, int nid, void *other);
+int ssl_ctx_security(SSL_CTX *ctx, int op, int bits, int nid, void *other);
+
int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);
@@ -1124,6 +1135,8 @@
const SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p);
long ssl23_default_timeout(void );
+int ssl_allow_compression(SSL *s);
+
long tls1_default_timeout(void);
int dtls1_do_write(SSL *s,int type);
int ssl3_read_n(SSL *s, int n, int max, int extend);
@@ -1304,6 +1317,7 @@
const EVP_MD *md);
int tls12_get_sigid(const EVP_PKEY *pk);
const EVP_MD *tls12_get_hash(unsigned char hash_alg);
+void ssl_set_sig_mask(unsigned long *pmask_a, SSL *s, int op);
int tls1_set_sigalgs_list(CERT *c, const char *str, int client);
int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client);
@@ -1315,6 +1329,10 @@
#ifndef OPENSSL_NO_DH
DH *ssl_get_auto_dh(SSL *s);
#endif
+
+int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee);
+int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex, int vfy);
+
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
@@ -1326,12 +1344,14 @@
int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
int *al);
long ssl_get_algorithm2(SSL *s);
+size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
+ const unsigned char *psig, size_t psiglen);
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_cipher_disabled(SSL *s, const SSL_CIPHER *c);
+int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op);
int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen);
int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al);
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index 49bd035..7c02878 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -68,11 +68,19 @@
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
int SSL_use_certificate(SSL *ssl, X509 *x)
{
+ int rv;
if (x == NULL)
{
SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER);
return(0);
}
+ rv = ssl_security_cert(ssl, NULL, x, 0, 1);
+ if (rv != 1)
+ {
+ SSLerr(SSL_F_SSL_USE_CERTIFICATE, rv);
+ return 0;
+ }
+
if (!ssl_cert_inst(&ssl->cert))
{
SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE);
@@ -393,11 +401,18 @@
int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
{
+ int rv;
if (x == NULL)
{
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER);
return(0);
}
+ rv = ssl_security_cert(NULL, ctx, x, 0, 1);
+ if (rv != 1)
+ {
+ SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, rv);
+ return 0;
+ }
if (!ssl_cert_inst(&ctx->cert))
{
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 37cc6f6..26fc45c 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -222,36 +222,46 @@
#ifndef OPENSSL_NO_EC
-static int nid_list[] =
+typedef struct
{
- NID_sect163k1, /* sect163k1 (1) */
- NID_sect163r1, /* sect163r1 (2) */
- NID_sect163r2, /* sect163r2 (3) */
- NID_sect193r1, /* sect193r1 (4) */
- NID_sect193r2, /* sect193r2 (5) */
- NID_sect233k1, /* sect233k1 (6) */
- NID_sect233r1, /* sect233r1 (7) */
- NID_sect239k1, /* sect239k1 (8) */
- NID_sect283k1, /* sect283k1 (9) */
- NID_sect283r1, /* sect283r1 (10) */
- NID_sect409k1, /* sect409k1 (11) */
- NID_sect409r1, /* sect409r1 (12) */
- NID_sect571k1, /* sect571k1 (13) */
- NID_sect571r1, /* sect571r1 (14) */
- NID_secp160k1, /* secp160k1 (15) */
- NID_secp160r1, /* secp160r1 (16) */
- NID_secp160r2, /* secp160r2 (17) */
- NID_secp192k1, /* secp192k1 (18) */
- NID_X9_62_prime192v1, /* secp192r1 (19) */
- NID_secp224k1, /* secp224k1 (20) */
- NID_secp224r1, /* secp224r1 (21) */
- NID_secp256k1, /* secp256k1 (22) */
- NID_X9_62_prime256v1, /* secp256r1 (23) */
- NID_secp384r1, /* secp384r1 (24) */
- NID_secp521r1, /* secp521r1 (25) */
- NID_brainpoolP256r1, /* brainpoolP256r1 (26) */
- NID_brainpoolP384r1, /* brainpoolP384r1 (27) */
- NID_brainpoolP512r1 /* brainpool512r1 (28) */
+ int nid; /* Curve NID */
+ int secbits; /* Bits of security (from SP800-57) */
+ unsigned int flags; /* Flags: currently just field type */
+ } tls_curve_info;
+
+#define TLS_CURVE_CHAR2 0x1
+#define TLS_CURVE_PRIME 0x0
+
+static tls_curve_info nid_list[] =
+ {
+ {NID_sect163k1, 80, TLS_CURVE_CHAR2},/* sect163k1 (1) */
+ {NID_sect163r1, 80, TLS_CURVE_CHAR2},/* sect163r1 (2) */
+ {NID_sect163r2, 80, TLS_CURVE_CHAR2},/* sect163r2 (3) */
+ {NID_sect193r1, 80, TLS_CURVE_CHAR2},/* sect193r1 (4) */
+ {NID_sect193r2, 80, TLS_CURVE_CHAR2},/* sect193r2 (5) */
+ {NID_sect233k1, 112, TLS_CURVE_CHAR2},/* sect233k1 (6) */
+ {NID_sect233r1, 112, TLS_CURVE_CHAR2},/* sect233r1 (7) */
+ {NID_sect239k1, 112, TLS_CURVE_CHAR2},/* sect239k1 (8) */
+ {NID_sect283k1, 128, TLS_CURVE_CHAR2},/* sect283k1 (9) */
+ {NID_sect283r1, 128, TLS_CURVE_CHAR2},/* sect283r1 (10) */
+ {NID_sect409k1, 192, TLS_CURVE_CHAR2},/* sect409k1 (11) */
+ {NID_sect409r1, 192, TLS_CURVE_CHAR2},/* sect409r1 (12) */
+ {NID_sect571k1, 256, TLS_CURVE_CHAR2},/* sect571k1 (13) */
+ {NID_sect571r1, 256, TLS_CURVE_CHAR2},/* sect571r1 (14) */
+ {NID_secp160k1, 80, TLS_CURVE_PRIME},/* secp160k1 (15) */
+ {NID_secp160r1, 80, TLS_CURVE_PRIME},/* secp160r1 (16) */
+ {NID_secp160r2, 80, TLS_CURVE_PRIME},/* secp160r2 (17) */
+ {NID_secp192k1, 80, TLS_CURVE_PRIME},/* secp192k1 (18) */
+ {NID_X9_62_prime192v1, 80, TLS_CURVE_PRIME},/* secp192r1 (19) */
+ {NID_secp224k1, 112, TLS_CURVE_PRIME},/* secp224k1 (20) */
+ {NID_secp224r1, 112, TLS_CURVE_PRIME},/* secp224r1 (21) */
+ {NID_secp256k1, 128, TLS_CURVE_PRIME},/* secp256k1 (22) */
+ {NID_X9_62_prime256v1, 128, TLS_CURVE_PRIME},/* secp256r1 (23) */
+ {NID_secp384r1, 192, TLS_CURVE_PRIME},/* secp384r1 (24) */
+ {NID_secp521r1, 256, TLS_CURVE_PRIME},/* secp521r1 (25) */
+ {NID_brainpoolP256r1, 128, TLS_CURVE_PRIME}, /* brainpoolP256r1 (26) */
+ {NID_brainpoolP384r1, 192, TLS_CURVE_PRIME}, /* brainpoolP384r1 (27) */
+ {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME},/* brainpool512r1 (28) */
};
@@ -306,7 +316,7 @@
if ((curve_id < 1) || ((unsigned int)curve_id >
sizeof(nid_list)/sizeof(nid_list[0])))
return 0;
- return nid_list[curve_id-1];
+ return nid_list[curve_id-1].nid;
}
int tls1_ec_nid2curve_id(int nid)
@@ -414,6 +424,20 @@
*pcurveslen = sizeof(eccurves_default);
}
}
+
+/* See if curve is allowed by security callback */
+static int tls_curve_allowed(SSL *s, const unsigned char *curve, int op)
+ {
+ tls_curve_info *cinfo;
+ if (curve[0])
+ return 1;
+ if ((curve[1] < 1) || ((size_t)curve[1] >
+ sizeof(nid_list)/sizeof(nid_list[0])))
+ return 0;
+ cinfo = &nid_list[curve[1]-1];
+ return ssl_security(s, op, cinfo->secbits, cinfo->nid, (void *)curve);
+ }
+
/* Check a curve is one of our preferences */
int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
{
@@ -445,7 +469,7 @@
for (i = 0; i < curveslen; i += 2, curves += 2)
{
if (p[1] == curves[0] && p[2] == curves[1])
- return 1;
+ return tls_curve_allowed(s, p + 1, SSL_SECOP_CURVE_CHECK);
}
return 0;
}
@@ -496,6 +520,8 @@
{
if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
{
+ if (!tls_curve_allowed(s, pref, SSL_SECOP_CURVE_SHARED))
+ continue;
if (nmatch == k)
{
int id = (pref[0] << 8) | pref[1];
@@ -678,7 +704,7 @@
return 0;
/* For clients can only check sent curve list */
if (!s->server)
- return 1;
+ break;
}
return 1;
}
@@ -1005,6 +1031,14 @@
SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_UNKNOWN_DIGEST);
return 0;
}
+ /* Make sure security callback allows algorithm */
+ if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK,
+ EVP_MD_size(*pmd) * 4, EVP_MD_type(*pmd),
+ (void *)sig))
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
/* Store the digest used so applications can retrieve it if they
* wish.
*/
@@ -1012,6 +1046,7 @@
s->session->sess_cert->peer_key->digest = *pmd;
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
@@ -1021,9 +1056,6 @@
void ssl_set_client_disabled(SSL *s)
{
CERT *c = s->cert;
- const unsigned char *sigalgs;
- size_t i, sigalgslen;
- int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
c->mask_a = 0;
c->mask_k = 0;
/* Don't allow TLS 1.2 only ciphers if we don't suppport them */
@@ -1031,50 +1063,16 @@
c->mask_ssl = SSL_TLSV1_2;
else
c->mask_ssl = 0;
- /* Now go through all signature algorithms seeing if we support
- * any for RSA, DSA, ECDSA. Do this for all versions not just
- * TLS 1.2.
- */
- sigalgslen = tls12_get_psigalgs(s, &sigalgs);
- for (i = 0; i < sigalgslen; i += 2, sigalgs += 2)
- {
- switch(sigalgs[1])
- {
-#ifndef OPENSSL_NO_RSA
- case TLSEXT_signature_rsa:
- have_rsa = 1;
- break;
-#endif
-#ifndef OPENSSL_NO_DSA
- case TLSEXT_signature_dsa:
- have_dsa = 1;
- break;
-#endif
-#ifndef OPENSSL_NO_ECDSA
- case TLSEXT_signature_ecdsa:
- have_ecdsa = 1;
- break;
-#endif
- }
- }
- /* Disable auth and static DH if we don't include any appropriate
+ ssl_set_sig_mask(&c->mask_a, s, SSL_SECOP_SIGALG_MASK);
+ /* Disable static DH if we don't include any appropriate
* signature algorithms.
*/
- if (!have_rsa)
- {
- c->mask_a |= SSL_aRSA;
+ if (c->mask_a & SSL_aRSA)
c->mask_k |= SSL_kDHr|SSL_kECDHr;
- }
- if (!have_dsa)
- {
- c->mask_a |= SSL_aDSS;
+ if (c->mask_a & SSL_aDSS)
c->mask_k |= SSL_kDHd;
- }
- if (!have_ecdsa)
- {
- c->mask_a |= SSL_aECDSA;
+ if (c->mask_a & SSL_aECDSA)
c->mask_k |= SSL_kECDHe;
- }
#ifndef OPENSSL_NO_KRB5
if (!kssl_tgt_is_available(s->kssl_ctx))
{
@@ -1093,12 +1091,19 @@
c->valid = 1;
}
-int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c)
+int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op)
{
CERT *ct = s->cert;
if (c->algorithm_ssl & ct->mask_ssl || c->algorithm_mkey & ct->mask_k || c->algorithm_auth & ct->mask_a)
return 1;
- return 0;
+ return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
+ }
+
+static int tls_use_ticket(SSL *s)
+ {
+ if (s->options & SSL_OP_NO_TICKET)
+ return 0;
+ return ssl_security(s, SSL_SECOP_TICKET, 0, 0, NULL);
}
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al)
@@ -1231,6 +1236,8 @@
long lenmax;
const unsigned char *plist;
size_t plistlen;
+ size_t i;
+ unsigned char *etmp;
tls1_get_formatlist(s, &plist, &plistlen);
@@ -1259,22 +1266,34 @@
SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
+
s2n(TLSEXT_TYPE_elliptic_curves,ret);
- s2n(plistlen + 2, ret);
+ etmp = ret + 4;
+ /* Copy curve ID if supported */
+ for (i = 0; i < plistlen; i += 2, plist += 2)
+ {
+ if (tls_curve_allowed(s, plist, SSL_SECOP_CURVE_SUPPORTED))
+ {
+ *etmp++ = plist[0];
+ *etmp++ = plist[1];
+ }
+ }
+
+ plistlen = etmp - ret - 4;
/* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
* elliptic_curve_list, but the examples use two bytes.
* http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
* resolves this to two bytes.
*/
+ s2n(plistlen + 2, ret);
s2n(plistlen, ret);
- memcpy(ret, plist, plistlen);
ret+=plistlen;
}
#endif /* OPENSSL_NO_EC */
- if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ if (tls_use_ticket(s))
{
int ticklen;
if (!s->new_session && s->session && s->session->tlsext_tick)
@@ -1314,13 +1333,18 @@
{
size_t salglen;
const unsigned char *salg;
+ unsigned char *etmp;
salglen = tls12_get_psigalgs(s, &salg);
if ((size_t)(limit - ret) < salglen + 6)
return NULL;
s2n(TLSEXT_TYPE_signature_algorithms,ret);
- s2n(salglen + 2, ret);
- s2n(salglen, ret);
- memcpy(ret, salg, salglen);
+ etmp = ret;
+ /* Skip over lengths for now */
+ ret += 4;
+ salglen = tls12_copy_sigalgs(s, etmp, salg, salglen);
+ /* Fill in lengths */
+ s2n(salglen + 2, etmp);
+ s2n(salglen, etmp);
ret += salglen;
}
@@ -1603,8 +1627,7 @@
/* Currently the server should not respond with a SupportedCurves extension */
#endif /* OPENSSL_NO_EC */
- if (s->tlsext_ticket_expected
- && !(SSL_get_options(s) & SSL_OP_NO_TICKET))
+ if (s->tlsext_ticket_expected && tls_use_ticket(s))
{
if ((long)(limit - ret - 4) < 0) return NULL;
s2n(TLSEXT_TYPE_session_ticket,ret);
@@ -2644,8 +2667,7 @@
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0))
+ if (!tls_use_ticket(s) || (size > 0))
{
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
@@ -3271,7 +3293,7 @@
/* If tickets disabled behave as if no ticket present
* to permit stateful resumption.
*/
- if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+ if (!tls_use_ticket(s))
return 0;
if ((s->version <= SSL3_VERSION) || !limit)
return 0;
@@ -3525,40 +3547,60 @@
sizeof(tls12_sig)/sizeof(tls12_lookup));
}
+typedef struct
+ {
+ int nid;
+ int secbits;
+ const EVP_MD *(*mfunc)(void);
+ } tls12_hash_info;
+
+static const tls12_hash_info tls12_md_info[] = {
+#ifdef OPENSSL_NO_MD5
+ {NID_md5, 64, 0},
+#else
+ {NID_md5, 64, EVP_md5},
+#endif
+#ifdef OPENSSL_NO_SHA
+ {NID_sha1, 80, 0},
+#else
+ {NID_sha1, 80, EVP_sha1},
+#endif
+#ifdef OPENSSL_NO_SHA256
+ {NID_sha224, 112, 0},
+ {NID_sha256, 128, 0},
+#else
+ {NID_sha224, 112, EVP_sha224},
+ {NID_sha256, 128, EVP_sha256},
+#endif
+#ifdef OPENSSL_NO_SHA512
+ {NID_sha384, 192, 0},
+ {NID_sha512, 256, 0}
+#else
+ {NID_sha384, 192, EVP_sha384},
+ {NID_sha512, 256, EVP_sha512}
+#endif
+};
+
+static const tls12_hash_info *tls12_get_hash_info(unsigned char hash_alg)
+ {
+ if (hash_alg == 0)
+ return NULL;
+ if (hash_alg > sizeof(tls12_md_info)/sizeof(tls12_md_info[0]))
+ return NULL;
+ return tls12_md_info + hash_alg - 1;
+ }
+
const EVP_MD *tls12_get_hash(unsigned char hash_alg)
{
- switch(hash_alg)
- {
-#ifndef OPENSSL_NO_MD5
- case TLSEXT_hash_md5:
-#ifdef OPENSSL_FIPS
- if (FIPS_mode())
- return NULL;
-#endif
- return EVP_md5();
-#endif
-#ifndef OPENSSL_NO_SHA
- case TLSEXT_hash_sha1:
- return EVP_sha1();
-#endif
-#ifndef OPENSSL_NO_SHA256
- case TLSEXT_hash_sha224:
- return EVP_sha224();
-
- case TLSEXT_hash_sha256:
- return EVP_sha256();
-#endif
-#ifndef OPENSSL_NO_SHA512
- case TLSEXT_hash_sha384:
- return EVP_sha384();
-
- case TLSEXT_hash_sha512:
- return EVP_sha512();
-#endif
- default:
+ const tls12_hash_info *inf;
+#ifndef OPENSSL_FIPS
+ if (hash_alg == TLSEXT_hash_md5 && FIPS_mode())
return NULL;
-
- }
+#endif
+ inf = tls12_get_hash_info(hash_alg);
+ if (!inf || !inf->mfunc)
+ return NULL;
+ return inf->mfunc();
}
static int tls12_get_pkey_idx(unsigned char sig_alg)
@@ -3611,8 +3653,86 @@
*psignhash_nid = NID_undef;
}
}
+/* Check to see if a signature algorithm is allowed */
+static int tls12_sigalg_allowed(SSL *s, int op, const unsigned char *ptmp)
+ {
+ /* See if we have an entry in the hash table and it is enabled */
+ const tls12_hash_info *hinf = tls12_get_hash_info(ptmp[0]);
+ if (!hinf || !hinf->mfunc)
+ return 0;
+ /* See if public key algorithm allowed */
+ if (tls12_get_pkey_idx(ptmp[1]) == -1)
+ return 0;
+ /* Finally see if security callback allows it */
+ return ssl_security(s, op, hinf->secbits, hinf->nid, (void *)ptmp);
+ }
+
+/* Get a mask of disabled public key algorithms based on supported
+ * signature algorithms. For example if no signature algorithm supports RSA
+ * then RSA is disabled.
+ */
+
+void ssl_set_sig_mask(unsigned long *pmask_a, SSL *s, int op)
+ {
+ const unsigned char *sigalgs;
+ size_t i, sigalgslen;
+ int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
+ /* Now go through all signature algorithms seeing if we support
+ * any for RSA, DSA, ECDSA. Do this for all versions not just
+ * TLS 1.2. To keep down calls to security callback only check
+ * if we have to.
+ */
+ sigalgslen = tls12_get_psigalgs(s, &sigalgs);
+ for (i = 0; i < sigalgslen; i += 2, sigalgs += 2)
+ {
+ switch(sigalgs[1])
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ if (!have_rsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_rsa = 1;
+ break;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ if (!have_dsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_dsa = 1;
+ break;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ if (!have_ecdsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_ecdsa = 1;
+ break;
+#endif
+ }
+ }
+ if (!have_rsa)
+ *pmask_a |= SSL_aRSA;
+ if (!have_dsa)
+ *pmask_a |= SSL_aDSS;
+ if (!have_ecdsa)
+ *pmask_a |= SSL_aECDSA;
+ }
+
+size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
+ const unsigned char *psig, size_t psiglen)
+ {
+ unsigned char *tmpout = out;
+ size_t i;
+ for (i = 0; i < psiglen; i += 2, psig += 2)
+ {
+ if (tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, psig))
+ {
+ *tmpout++ = psig[0];
+ *tmpout++ = psig[1];
+ }
+ }
+ return tmpout - out;
+ }
+
/* Given preference and allowed sigalgs set shared sigalgs */
-static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
+static int tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
const unsigned char *pref, size_t preflen,
const unsigned char *allow, size_t allowlen)
{
@@ -3621,9 +3741,7 @@
for (i = 0, ptmp = pref; i < preflen; i+=2, ptmp+=2)
{
/* Skip disabled hashes or signature algorithms */
- if (tls12_get_hash(ptmp[0]) == NULL)
- continue;
- if (tls12_get_pkey_idx(ptmp[1]) == -1)
+ if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SHARED, ptmp))
continue;
for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
{
@@ -3688,13 +3806,13 @@
pref = c->peer_sigalgs;
preflen = c->peer_sigalgslen;
}
- nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
+ nmatch = tls12_shared_sigalgs(s, NULL, pref, preflen, allow, allowlen);
if (!nmatch)
return 1;
salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
if (!salgs)
return 0;
- nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
+ nmatch = tls12_shared_sigalgs(s, salgs, pref, preflen, allow, allowlen);
c->shared_sigalgs = salgs;
c->shared_sigalgslen = nmatch;
return 1;
@@ -4495,3 +4613,87 @@
return DH_get_1024_160();
}
#endif
+
+static int ssl_security_cert_key(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+ {
+ int secbits;
+ EVP_PKEY *pkey = X509_get_pubkey(x);
+ if (pkey)
+ {
+ secbits = EVP_PKEY_security_bits(pkey);
+ EVP_PKEY_free(pkey);
+ }
+ else
+ secbits = -1;
+ if (s)
+ return ssl_security(s, op, secbits, 0, x);
+ else
+ return ssl_ctx_security(ctx, op, secbits, 0, x);
+ }
+
+static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+ {
+ /* Lookup signature algorithm digest */
+ int secbits = -1, md_nid = NID_undef, sig_nid;
+ sig_nid = X509_get_signature_nid(x);
+ if (sig_nid && OBJ_find_sigid_algs(sig_nid, &md_nid, NULL))
+ {
+ const EVP_MD *md;
+ if (md_nid && (md = EVP_get_digestbynid(md_nid)))
+ secbits = EVP_MD_size(md) * 4;
+ }
+ if (s)
+ return ssl_security(s, op, secbits, md_nid, x);
+ else
+ return ssl_ctx_security(ctx, op, secbits, md_nid, x);
+ }
+
+int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee)
+ {
+ if (vfy)
+ vfy = SSL_SECOP_PEER;
+ if (is_ee)
+ {
+ if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY | vfy))
+ return SSL_R_EE_KEY_TOO_SMALL;
+ }
+ else
+ {
+ if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY | vfy))
+ return SSL_R_CA_KEY_TOO_SMALL;
+ }
+ if (!ssl_security_cert_sig(s, ctx, x, SSL_SECOP_CA_MD | vfy))
+ return SSL_R_CA_MD_TOO_WEAK;
+ return 1;
+ }
+
+/* Check security of a chain, if sk includes the end entity certificate
+ * then x is NULL. If vfy is 1 then we are verifying a peer chain and
+ * not sending one to the peer.
+ * Return values: 1 if ok otherwise error code to use
+ */
+
+int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy)
+ {
+ int rv, start_idx, i;
+ if (x == NULL)
+ {
+ x = sk_X509_value(sk, 0);
+ start_idx = 1;
+ }
+ else
+ start_idx = 0;
+
+ rv = ssl_security_cert(s, NULL, x, vfy, 1);
+ if (rv != 1)
+ return rv;
+
+ for (i = start_idx; i < sk_X509_num(sk); i++)
+ {
+ x = sk_X509_value(sk, i);
+ rv = ssl_security_cert(s, NULL, x, vfy, 0);
+ if (rv != 1)
+ return rv;
+ }
+ return 1;
+ }
diff --git a/ssl/tls1.h b/ssl/tls1.h
index dbc612c..f288bb9 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -157,6 +157,11 @@
extern "C" {
#endif
+/* Default security level if not overriden at config time */
+#ifndef OPENSSL_TLS_SECURITY_LEVEL
+#define OPENSSL_TLS_SECURITY_LEVEL 1
+#endif
+
#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0
#define TLS1_2_VERSION 0x0303