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