From b362ccab5c1d52086f19d29a32f4acc11073b86b Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 15 Dec 2013 13:32:24 +0000 Subject: 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... --- ssl/s23_clnt.c | 14 +- ssl/s23_srvr.c | 6 + ssl/s2_clnt.c | 6 + ssl/s2_srvr.c | 6 + ssl/s3_both.c | 11 +- ssl/s3_clnt.c | 28 +++- ssl/s3_lib.c | 80 +++++------ ssl/s3_srvr.c | 44 +++++- ssl/ssl.h | 82 +++++++++++ ssl/ssl_cert.c | 175 +++++++++++++++++++++-- ssl/ssl_err.c | 10 +- ssl/ssl_lib.c | 65 ++++++++- ssl/ssl_locl.h | 32 ++++- ssl/ssl_rsa.c | 15 ++ ssl/t1_lib.c | 440 +++++++++++++++++++++++++++++++++++++++++---------------- 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 */ diff --git a/ssl/ssl.h b/ssl/ssl.h index 9c200b798e..92ffae95c1 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -2573,6 +2573,80 @@ void SSL_trace(int write_p, int version, int content_type, const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c); #endif +/* What the "other" parameter contains in security callback */ +/* Mask for type */ +#define SSL_SECOP_OTHER_TYPE 0xffff0000 +#define SSL_SECOP_OTHER_NONE 0 +#define SSL_SECOP_OTHER_CIPHER (1 << 16) +#define SSL_SECOP_OTHER_CURVE (2 << 16) +#define SSL_SECOP_OTHER_DH (3 << 16) +#define SSL_SECOP_OTHER_PKEY (4 << 16) +#define SSL_SECOP_OTHER_SIGALG (5 << 16) +#define SSL_SECOP_OTHER_CERT (6 << 16) + +/* Indicated operation refers to peer key or certificate */ +#define SSL_SECOP_PEER 0x1000 + +/* Values for "op" parameter in security callback */ + +/* Called to filter ciphers */ +/* Ciphers client supports */ +#define SSL_SECOP_CIPHER_SUPPORTED (1 | SSL_SECOP_OTHER_CIPHER) +/* Cipher shared by client/server */ +#define SSL_SECOP_CIPHER_SHARED (2 | SSL_SECOP_OTHER_CIPHER) +/* Sanity check of cipher server selects */ +#define SSL_SECOP_CIPHER_CHECK (3 | SSL_SECOP_OTHER_CIPHER) +/* Curves supported by client */ +#define SSL_SECOP_CURVE_SUPPORTED (4 | SSL_SECOP_OTHER_CURVE) +/* Curves shared by client/server */ +#define SSL_SECOP_CURVE_SHARED (5 | SSL_SECOP_OTHER_CURVE) +/* Sanity check of curve server selects */ +#define SSL_SECOP_CURVE_CHECK (6 | SSL_SECOP_OTHER_CURVE) +/* Temporary DH key */ +#define SSL_SECOP_TMP_DH (7 | SSL_SECOP_OTHER_DH) +/* Whether to use SSLv2 compatible client hello */ +#define SSL_SECOP_SSL2_COMPAT (8 | SSL_SECOP_OTHER_NONE) +/* SSL/TLS version */ +#define SSL_SECOP_VERSION (9 | SSL_SECOP_OTHER_NONE) +/* Session tickets */ +#define SSL_SECOP_TICKET (10 | SSL_SECOP_OTHER_NONE) +/* Supported signature algorithms sent to peer */ +#define SSL_SECOP_SIGALG_SUPPORTED (11 | SSL_SECOP_OTHER_SIGALG) +/* Shared signature algorithm */ +#define SSL_SECOP_SIGALG_SHARED (12 | SSL_SECOP_OTHER_SIGALG) +/* Sanity check signature algorithm allowed */ +#define SSL_SECOP_SIGALG_CHECK (13 | SSL_SECOP_OTHER_SIGALG) +/* Used to get mask of supported public key signature algorithms */ +#define SSL_SECOP_SIGALG_MASK (14 | SSL_SECOP_OTHER_SIGALG) +/* Use to see if compression is allowed */ +#define SSL_SECOP_COMPRESSION (15 | SSL_SECOP_OTHER_NONE) +/* EE key in certificate */ +#define SSL_SECOP_EE_KEY (16 | SSL_SECOP_OTHER_CERT) +/* CA key in certificate */ +#define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) +/* CA digest algorithm in certificate */ +#define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) +/* Peer EE key in certificate */ +#define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +#define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +#define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) + +void SSL_set_security_level(SSL *s, int level); +int SSL_get_security_level(const SSL *s); +void SSL_set_security_callback(SSL *s, int (*cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex)); +int (*SSL_get_security_callback(const SSL *s))(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex); +void SSL_set0_security_ex_data(SSL *s, void *ex); +void *SSL_get0_security_ex_data(const SSL *s); + +void SSL_CTX_set_security_level(SSL_CTX *ctx, int level); +int SSL_CTX_get_security_level(const SSL_CTX *ctx); +void SSL_CTX_set_security_callback(SSL_CTX *ctx, int (*cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex)); +int (*SSL_CTX_get_security_callback(const SSL_CTX *ctx))(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex); +void SSL_CTX_set0_security_ex_data(SSL_CTX *ctx, void *ex); +void *SSL_CTX_get0_security_ex_data(const SSL_CTX *ctx); + /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes * made after this point may be overwritten when the script is next run. @@ -2710,10 +2784,12 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_BAD_METHOD 160 #define SSL_F_SSL_BUILD_CERT_CHAIN 332 #define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 +#define SSL_F_SSL_CERT_ADD0_CHAIN_CERT 339 #define SSL_F_SSL_CERT_DUP 221 #define SSL_F_SSL_CERT_INST 222 #define SSL_F_SSL_CERT_INSTANTIATE 214 #define SSL_F_SSL_CERT_NEW 162 +#define SSL_F_SSL_CERT_SET0_CHAIN 340 #define SSL_F_SSL_CHECK_PRIVATE_KEY 163 #define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280 #define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279 @@ -2874,6 +2950,8 @@ void ERR_load_SSL_strings(void); #define SSL_R_BN_LIB 130 #define SSL_R_CA_DN_LENGTH_MISMATCH 131 #define SSL_R_CA_DN_TOO_LONG 132 +#define SSL_R_CA_KEY_TOO_SMALL 397 +#define SSL_R_CA_MD_TOO_WEAK 398 #define SSL_R_CCS_RECEIVED_EARLY 133 #define SSL_R_CERTIFICATE_VERIFY_FAILED 134 #define SSL_R_CERT_CB_ERROR 377 @@ -2895,6 +2973,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_DATA_LENGTH_TOO_LONG 146 #define SSL_R_DECRYPTION_FAILED 147 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281 +#define SSL_R_DH_KEY_TOO_SMALL 394 #define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 #define SSL_R_DIGEST_CHECK_FAILED 149 #define SSL_R_DTLS_MESSAGE_TOO_BIG 334 @@ -2904,6 +2983,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322 #define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323 #define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310 +#define SSL_R_EE_KEY_TOO_SMALL 399 #define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354 #define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 #define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282 @@ -2931,6 +3011,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_INVALID_TICKET_KEYS_LENGTH 325 #define SSL_R_INVALID_TRUST 279 #define SSL_R_KEY_ARG_TOO_LONG 284 +#define SSL_R_KEY_TOO_SMALL 395 #define SSL_R_KRB5 285 #define SSL_R_KRB5_C_CC_PRINC 286 #define SSL_R_KRB5_C_GET_CRED 287 @@ -3132,6 +3213,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNSUPPORTED_SSL_VERSION 259 #define SSL_R_UNSUPPORTED_STATUS_TYPE 329 #define SSL_R_USE_SRTP_NOT_NEGOTIATED 369 +#define SSL_R_VERSION_TOO_LOW 396 #define SSL_R_WRITE_BIO_NOT_SET 260 #define SSL_R_WRONG_CERTIFICATE_TYPE 383 #define SSL_R_WRONG_CIPHER_RETURNED 261 diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 665623eed8..d56b2c5dd5 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -132,6 +132,8 @@ #include #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; icert : 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); + } diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index e66348324f..6a30748f3d 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -1,6 +1,6 @@ /* ssl/ssl_err.c */ /* ==================================================================== - * Copyright (c) 1999-2013 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2014 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -198,10 +198,12 @@ 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"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1b8c0f42bc..c6ca1379a0 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -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 diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 07ea0d2972..0f51594739 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -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); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 49bd03596a..7c02878abb 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -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); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 37cc6f6abf..26fc45c7df 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -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; + } diff --git a/ssl/tls1.h b/ssl/tls1.h index dbc612ca47..f288bb96b3 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -157,6 +157,11 @@ extern "C" { #endif +/* Default security level if not overriden at config time */ +#ifndef OPENSSL_TLS_SECURITY_LEVEL +#define OPENSSL_TLS_SECURITY_LEVEL 1 +#endif + #define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 #define TLS1_2_VERSION 0x0303 -- cgit v1.2.3