Security framework.
authorDr. Stephen Henson <steve@openssl.org>
Sun, 15 Dec 2013 13:32:24 +0000 (13:32 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 28 Mar 2014 14:56:30 +0000 (14:56 +0000)
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...

16 files changed:
ssl/s23_clnt.c
ssl/s23_srvr.c
ssl/s2_clnt.c
ssl/s2_srvr.c
ssl/s3_both.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_cert.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssl_rsa.c
ssl/t1_lib.c
ssl/tls1.h

index 60a0284..dad7e3a 100644 (file)
@@ -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 */
index 9d47c22..cb2b138 100644 (file)
@@ -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
index 299389a..3621cf9 100644 (file)
@@ -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)
index a16c33a..71f677b 100644 (file)
@@ -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;
index 0a259b1..beef06f 100644 (file)
@@ -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);
+       }
+
index efc3710..9a0b1bd 100644 (file)
@@ -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);
index 517b1a2..9ff7f15 100644 (file)
@@ -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 
index 411b6f6..9434923 100644 (file)
@@ -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 */
index 9c200b7..92ffae9 100644 (file)
--- 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
index 665623e..d56b2c5 100644 (file)
 #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;
+       }
+
+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);
+       }
index e663483..6a30748 100644 (file)
@@ -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 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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"},
index 1b8c0f4..c6ca137 100644 (file)
@@ -1353,7 +1353,7 @@ STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
        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 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
                {
                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 @@ int SSL_is_server(SSL *s)
        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
index 07ea0d2..0f51594 100644 (file)
@@ -627,6 +627,13 @@ typedef struct cert_st
        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_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
 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 @@ void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg);
 
 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 @@ int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p);
 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 @@ int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
                                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 @@ void tls1_set_cert_validity(SSL *s);
 #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_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
 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);
index 49bd035..7c02878 100644 (file)
@@ -68,11 +68,19 @@ static int ssl_set_cert(CERT *c, X509 *x509);
 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_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len
 
 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);
index 37cc6f6..26fc45c 100644 (file)
@@ -222,36 +222,46 @@ void tls1_clear(SSL *s)
 
 #ifndef OPENSSL_NO_EC
 
-static int nid_list[] =
+typedef struct
+       {
+       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, /* 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) */  
+               {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 @@ int tls1_ec_curve_id2nid(int curve_id)
        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 @@ static void tls1_get_curvelist(SSL *s, int sess,
                *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 @@ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
        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 @@ int tls1_shared_curve(SSL *s, int nmatch)
                        {
                        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 @@ static int tls1_check_ec_key(SSL *s,
                        return 0;
                /* For clients can only check sent curve list */
                if (!s->server)
-                       return 1;
+                       break;
                }
        return 1;
        }
@@ -1005,6 +1031,14 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
                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 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
                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 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
 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 @@ void ssl_set_client_disabled(SSL *s)
                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 @@ void ssl_set_client_disabled(SSL *s)
        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 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                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 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        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 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                {
                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 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        /* 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 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                                *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 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
        /* 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 @@ int tls12_get_sigid(const EVP_PKEY *pk)
                                sizeof(tls12_sig)/sizeof(tls12_lookup));
        }
 
-const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+typedef struct 
        {
-       switch(hash_alg)
-               {
-#ifndef OPENSSL_NO_MD5
-               case TLSEXT_hash_md5:
-#ifdef OPENSSL_FIPS
-               if (FIPS_mode())
-                       return NULL;
+       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
-               return EVP_md5();
+#ifdef OPENSSL_NO_SHA
+       {NID_sha1, 80, 0},
+#else
+       {NID_sha1, 80, EVP_sha1},
 #endif
-#ifndef OPENSSL_NO_SHA
-               case TLSEXT_hash_sha1:
-               return EVP_sha1();
+#ifdef OPENSSL_NO_SHA256
+       {NID_sha224, 112, 0},
+       {NID_sha256, 128, 0},
+#else
+       {NID_sha224, 112, EVP_sha224},
+       {NID_sha256, 128, EVP_sha256},
 #endif
-#ifndef OPENSSL_NO_SHA256
-               case TLSEXT_hash_sha224:
-               return EVP_sha224();
-
-               case TLSEXT_hash_sha256:
-               return EVP_sha256();
+#ifdef OPENSSL_NO_SHA512
+       {NID_sha384, 192, 0},
+       {NID_sha512, 256, 0}
+#else
+       {NID_sha384, 192, EVP_sha384},
+       {NID_sha512, 256, EVP_sha512}
 #endif
-#ifndef OPENSSL_NO_SHA512
-               case TLSEXT_hash_sha384:
-               return EVP_sha384();
+};
 
-               case TLSEXT_hash_sha512:
-               return EVP_sha512();
-#endif
-               default:
+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)
+       {
+       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 @@ static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
                        *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 @@ static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
        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 @@ static int tls1_set_shared_sigalgs(SSL *s)
                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 @@ DH *ssl_get_auto_dh(SSL *s)
        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;
+       }
index dbc612c..f288bb9 100644 (file)
 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