* OTHERWISE.
*/
-#ifdef REF_CHECK
+#ifdef REF_DEBUG
# include <assert.h>
#endif
#include <stdio.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/ocsp.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-#ifndef OPENSSL_NO_ENGINE
-# include <openssl/engine.h>
-#endif
+#include <openssl/dh.h>
+#include <openssl/engine.h>
#include <openssl/async.h>
+#include <openssl/ct.h>
const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
* evil casts, but these functions are only called if there's a library
* bug
*/
- (int (*)(SSL *, int))ssl_undefined_function,
- (int (*)(SSL *, unsigned char *, int))ssl_undefined_function,
+ (int (*)(SSL *, SSL3_RECORD *, unsigned int, int))ssl_undefined_function,
+ (int (*)(SSL *, SSL3_RECORD *, unsigned char *, int))ssl_undefined_function,
ssl_undefined_function,
(int (*)(SSL *, unsigned char *, unsigned char *, int))
ssl_undefined_function,
SSL *s;
void *buf;
int num;
- int type;
+ enum { READFUNC, WRITEFUNC, OTHERFUNC} type;
union {
- int (*func1)(SSL *, void *, int);
- int (*func2)(SSL *, const void *, int);
+ int (*func_read)(SSL *, void *, int);
+ int (*func_write)(SSL *, const void *, int);
+ int (*func_other)(SSL *);
} f;
};
if (s == NULL)
goto err;
+ s->lock = CRYPTO_THREAD_lock_new();
+ if (s->lock == NULL) {
+ SSLerr(SSL_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(s);
+ return NULL;
+ }
+
RECORD_LAYER_init(&s->rlayer, s);
s->options = ctx->options;
X509_VERIFY_PARAM_inherit(s->param, ctx->param);
s->quiet_shutdown = ctx->quiet_shutdown;
s->max_send_fragment = ctx->max_send_fragment;
-
- CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
+ s->split_send_fragment = ctx->split_send_fragment;
+ s->max_pipelines = ctx->max_pipelines;
+ if (s->max_pipelines > 1)
+ RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
+ if (ctx->default_read_buf_len > 0)
+ SSL_set_default_read_buffer_len(s, ctx->default_read_buf_len);
+
+ SSL_CTX_up_ref(ctx);
s->ctx = ctx;
s->tlsext_debug_cb = 0;
s->tlsext_debug_arg = NULL;
s->tlsext_ocsp_exts = NULL;
s->tlsext_ocsp_resp = NULL;
s->tlsext_ocsp_resplen = -1;
- CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
+ SSL_CTX_up_ref(ctx);
s->initial_ctx = ctx;
# ifndef OPENSSL_NO_EC
if (ctx->tlsext_ecpointformatlist) {
s->alpn_client_proto_list_len = s->ctx->alpn_client_proto_list_len;
}
+ s->verified_chain = NULL;
s->verify_result = X509_V_OK;
s->default_passwd_callback = ctx->default_passwd_callback;
s->job = NULL;
- return (s);
+#ifndef OPENSSL_NO_CT
+ if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
+ ctx->ct_validation_callback_arg))
+ goto err;
+#endif
+
+ return s;
err:
SSL_free(s);
SSLerr(SSL_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
- return (NULL);
+ return NULL;
+}
+
+void SSL_up_ref(SSL *s)
+{
+ int i;
+ CRYPTO_atomic_add(&s->references, 1, &i, s->lock);
}
int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
{
- CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+ CRYPTO_THREAD_write_lock(ctx->lock);
ctx->generate_session_id = cb;
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+ CRYPTO_THREAD_unlock(ctx->lock);
return 1;
}
int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
{
- CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+ CRYPTO_THREAD_write_lock(ssl->lock);
ssl->generate_session_id = cb;
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+ CRYPTO_THREAD_unlock(ssl->lock);
return 1;
}
r.session_id_length = id_len;
memcpy(r.session_id, id, id_len);
- CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+ CRYPTO_THREAD_read_lock(ssl->ctx->lock);
p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r);
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+ CRYPTO_THREAD_unlock(ssl->ctx->lock);
return (p != NULL);
}
{
struct dane_st *dane = &s->dane;
- if (!DANETLS_ENABLED(dane))
+ if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
return -1;
if (dane->mtlsa) {
if (mcert)
{
struct dane_st *dane = &s->dane;
- if (!DANETLS_ENABLED(dane))
+ if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
return -1;
if (dane->mtlsa) {
if (usage)
if (s == NULL)
return;
- i = CRYPTO_add(&s->references, -1, CRYPTO_LOCK_SSL);
-#ifdef REF_PRINT
- REF_PRINT("SSL", s);
-#endif
+ CRYPTO_atomic_add(&s->references, -1, &i, s->lock);
+ REF_PRINT_COUNT("SSL", s);
if (i > 0)
return;
-#ifdef REF_CHECK
- if (i < 0) {
- fprintf(stderr, "SSL_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
+ REF_ASSERT_ISNT(i < 0);
X509_VERIFY_PARAM_free(s->param);
dane_final(&s->dane);
#endif /* OPENSSL_NO_EC */
sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free);
sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+#ifndef OPENSSL_NO_CT
+ SCT_LIST_free(s->scts);
+ OPENSSL_free(s->tlsext_scts);
+#endif
OPENSSL_free(s->tlsext_ocsp_resp);
OPENSSL_free(s->alpn_client_proto_list);
sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free);
+ sk_X509_pop_free(s->verified_chain, X509_free);
+
if (s->method != NULL)
s->method->ssl_free(s);
SSL_CTX_free(s->ctx);
+ ASYNC_WAIT_CTX_free(s->waitctx);
+
#if !defined(OPENSSL_NO_NEXTPROTONEG)
OPENSSL_free(s->next_proto_negotiated);
#endif
sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
#endif
+ CRYPTO_THREAD_lock_free(s->lock);
+
OPENSSL_free(s);
}
*/
if (s->bbio != NULL) {
if (s->wbio == s->bbio) {
- s->wbio = s->wbio->next_bio;
- s->bbio->next_bio = NULL;
+ s->wbio = BIO_next(s->wbio);
+ BIO_set_next(s->bbio, NULL);
}
}
if (s->wbio != wbio && s->rbio != s->wbio)
return (s->method->ssl_pending(s));
}
+int SSL_has_pending(const SSL *s)
+{
+ /*
+ * Similar to SSL_pending() but returns a 1 to indicate that we have
+ * unprocessed data available or 0 otherwise (as opposed to the number of
+ * bytes available). Unlike SSL_pending() this will take into account
+ * read_ahead data. A 1 return simply indicates that we have unprocessed
+ * data. That data may not result in any application data, or we may fail
+ * to parse the records for some reason.
+ */
+ if (SSL_pending(s))
+ return 1;
+
+ return RECORD_LAYER_read_pending(&s->rlayer);
+}
+
X509 *SSL_get_peer_certificate(const SSL *s)
{
X509 *r;
*/
int SSL_copy_session_id(SSL *t, const SSL *f)
{
+ int i;
/* Do we need to to SSL locking? */
if (!SSL_set_session(t, SSL_get_session(f))) {
return 0;
return 0;
}
- CRYPTO_add(&f->cert->references, 1, CRYPTO_LOCK_SSL_CERT);
+ CRYPTO_atomic_add(&f->cert->references, 1, &i, f->cert->lock);
ssl_cert_free(t->cert);
t->cert = f->cert;
if (!SSL_set_session_id_context(t, f->sid_ctx, f->sid_ctx_length)) {
return 0;
}
-int SSL_get_async_wait_fd(SSL *s)
+int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds)
{
- if (!s->job)
- return -1;
+ ASYNC_WAIT_CTX *ctx = s->waitctx;
+
+ if (ctx == NULL)
+ return 0;
+ return ASYNC_WAIT_CTX_get_all_fds(ctx, fds, numfds);
+}
+
+int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, size_t *numaddfds,
+ OSSL_ASYNC_FD *delfd, size_t *numdelfds)
+{
+ ASYNC_WAIT_CTX *ctx = s->waitctx;
- return ASYNC_get_wait_fd(s->job);
+ if (ctx == NULL)
+ return 0;
+ return ASYNC_WAIT_CTX_get_changed_fds(ctx, addfd, numaddfds, delfd,
+ numdelfds);
}
int SSL_accept(SSL *s)
{
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
/* Not properly initialized yet */
SSL_set_accept_state(s);
}
int SSL_connect(SSL *s)
{
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
/* Not properly initialized yet */
SSL_set_connect_state(s);
}
static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
int (*func)(void *)) {
int ret;
- switch(ASYNC_start_job(&s->job, &ret, func, args,
+ if (s->waitctx == NULL) {
+ s->waitctx = ASYNC_WAIT_CTX_new();
+ if (s->waitctx == NULL)
+ return -1;
+ }
+ switch(ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
sizeof(struct ssl_async_args))) {
case ASYNC_ERR:
s->rwstate = SSL_NOTHING;
s = args->s;
buf = args->buf;
num = args->num;
- if (args->type == 1)
- return args->f.func1(s, buf, num);
- else
- return args->f.func2(s, buf, num);
+ switch (args->type) {
+ case READFUNC:
+ return args->f.func_read(s, buf, num);
+ case WRITEFUNC:
+ return args->f.func_write(s, buf, num);
+ case OTHERFUNC:
+ return args->f.func_other(s);
+ }
+ return -1;
}
int SSL_read(SSL *s, void *buf, int num)
{
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
return -1;
}
args.s = s;
args.buf = buf;
args.num = num;
- args.type = 1;
- args.f.func1 = s->method->ssl_read;
+ args.type = READFUNC;
+ args.f.func_read = s->method->ssl_read;
return ssl_start_async_job(s, &args, ssl_io_intern);
} else {
int SSL_peek(SSL *s, void *buf, int num)
{
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_PEEK, SSL_R_UNINITIALIZED);
return -1;
}
args.s = s;
args.buf = buf;
args.num = num;
- args.type = 1;
- args.f.func1 = s->method->ssl_peek;
+ args.type = READFUNC;
+ args.f.func_read = s->method->ssl_peek;
return ssl_start_async_job(s, &args, ssl_io_intern);
} else {
int SSL_write(SSL *s, const void *buf, int num)
{
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
return -1;
}
args.s = s;
args.buf = (void *)buf;
args.num = num;
- args.type = 2;
- args.f.func2 = s->method->ssl_write;
+ args.type = WRITEFUNC;
+ args.f.func_write = s->method->ssl_write;
return ssl_start_async_job(s, &args, ssl_io_intern);
} else {
* (see ssl3_shutdown).
*/
- if (s->handshake_func == 0) {
+ if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
return -1;
}
- return s->method->ssl_shutdown(s);
+ if (!SSL_in_init(s)) {
+ if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+ struct ssl_async_args args;
+
+ args.s = s;
+ args.type = OTHERFUNC;
+ args.f.func_other = s->method->ssl_shutdown;
+
+ return ssl_start_async_job(s, &args, ssl_io_intern);
+ } else {
+ return s->method->ssl_shutdown(s);
+ }
+ } else {
+ SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_SHUTDOWN_WHILE_IN_INIT);
+ return -1;
+ }
}
int SSL_renegotiate(SSL *s)
if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
return 0;
s->max_send_fragment = larg;
+ if (s->max_send_fragment < s->split_send_fragment)
+ s->split_send_fragment = s->max_send_fragment;
+ return 1;
+ case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
+ if ((unsigned int)larg > s->max_send_fragment || larg == 0)
+ return 0;
+ s->split_send_fragment = larg;
+ return 1;
+ case SSL_CTRL_SET_MAX_PIPELINES:
+ if (larg < 1 || larg > SSL_MAX_PIPELINES)
+ return 0;
+ s->max_pipelines = larg;
+ if (larg > 1)
+ RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
return 1;
case SSL_CTRL_GET_RI_SUPPORT:
if (s->s3)
if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
return 0;
ctx->max_send_fragment = larg;
+ if (ctx->max_send_fragment < ctx->split_send_fragment)
+ ctx->split_send_fragment = ctx->split_send_fragment;
+ return 1;
+ case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
+ if ((unsigned int)larg > ctx->max_send_fragment || larg == 0)
+ return 0;
+ ctx->split_send_fragment = larg;
+ return 1;
+ case SSL_CTRL_SET_MAX_PIPELINES:
+ if (larg < 1 || larg > SSL_MAX_PIPELINES)
+ return 0;
+ ctx->max_pipelines = larg;
return 1;
case SSL_CTRL_CERT_FLAGS:
return (ctx->cert->cert_flags |= larg);
*p = '\0';
return buf;
}
- strcpy(p, c->name);
+ memcpy(p, c->name, n + 1);
p += n;
*(p++) = ':';
len -= n + 1;
* length-prefixed strings). Returns 0 on success.
*/
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
- unsigned protos_len)
+ unsigned int protos_len)
{
OPENSSL_free(ctx->alpn_client_proto_list);
- ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len);
- if (ctx->alpn_client_proto_list == NULL)
+ ctx->alpn_client_proto_list = OPENSSL_memdup(protos, protos_len);
+ if (ctx->alpn_client_proto_list == NULL) {
+ SSLerr(SSL_F_SSL_CTX_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
- memcpy(ctx->alpn_client_proto_list, protos, protos_len);
+ }
ctx->alpn_client_proto_list_len = protos_len;
return 0;
* length-prefixed strings). Returns 0 on success.
*/
int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
- unsigned protos_len)
+ unsigned int protos_len)
{
OPENSSL_free(ssl->alpn_client_proto_list);
- ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len);
- if (ssl->alpn_client_proto_list == NULL)
+ ssl->alpn_client_proto_list = OPENSSL_memdup(protos, protos_len);
+ if (ssl->alpn_client_proto_list == NULL) {
+ SSLerr(SSL_F_SSL_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
- memcpy(ssl->alpn_client_proto_list, protos, protos_len);
+ }
ssl->alpn_client_proto_list_len = protos_len;
return 0;
* respond with a negotiated protocol then |*len| will be zero.
*/
void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
- unsigned *len)
+ unsigned int *len)
{
*data = NULL;
if (ssl->s3)
return (NULL);
}
+ if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
+ return NULL;
+
if (FIPS_mode() && (meth->version < TLS1_VERSION)) {
SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE);
return NULL;
/* We take the system default. */
ret->session_timeout = meth->get_timeout();
ret->references = 1;
+ ret->lock = CRYPTO_THREAD_lock_new();
+ if (ret->lock == NULL) {
+ SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(ret);
+ return NULL;
+ }
ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT;
ret->verify_mode = SSL_VERIFY_NONE;
if ((ret->cert = ssl_cert_new()) == NULL)
ret->cert_store = X509_STORE_new();
if (ret->cert_store == NULL)
goto err;
-
+#ifndef OPENSSL_NO_CT
+ ret->ctlog_store = CTLOG_STORE_new();
+ if (ret->ctlog_store == NULL)
+ goto err;
+#endif
if (!ssl_create_cipher_list(ret->method,
&ret->cipher_list, &ret->cipher_list_by_id,
SSL_DEFAULT_CIPHER_LIST, ret->cert)
ret->comp_methods = SSL_COMP_get_compression_methods();
ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+ ret->split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
/* Setup RFC4507 ticket keys */
if ((RAND_bytes(ret->tlsext_tick_key_name, 16) <= 0)
* deployed might change this.
*/
ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+ /*
+ * Disable compression by default to prevent CRIME. Applications can
+ * re-enable compression by configuring
+ * SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION);
+ * or by using the SSL_CONF library.
+ */
+ ret->options |= SSL_OP_NO_COMPRESSION;
- return (ret);
+ return ret;
err:
SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
err2:
SSL_CTX_free(ret);
- return (NULL);
+ return NULL;
+}
+
+void SSL_CTX_up_ref(SSL_CTX *ctx)
+{
+ int i;
+ CRYPTO_atomic_add(&ctx->references, 1, &i, ctx->lock);
}
void SSL_CTX_free(SSL_CTX *a)
if (a == NULL)
return;
- i = CRYPTO_add(&a->references, -1, CRYPTO_LOCK_SSL_CTX);
-#ifdef REF_PRINT
- REF_PRINT("SSL_CTX", a);
-#endif
+ CRYPTO_atomic_add(&a->references, -1, &i, a->lock);
+ REF_PRINT_COUNT("SSL_CTX", a);
if (i > 0)
return;
-#ifdef REF_CHECK
- if (i < 0) {
- fprintf(stderr, "SSL_CTX_free, bad reference count\n");
- abort(); /* ok */
- }
-#endif
+ REF_ASSERT_ISNT(i < 0);
X509_VERIFY_PARAM_free(a->param);
dane_ctx_final(&a->dane);
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
lh_SSL_SESSION_free(a->sessions);
X509_STORE_free(a->cert_store);
+#ifndef OPENSSL_NO_CT
+ CTLOG_STORE_free(a->ctlog_store);
+#endif
sk_SSL_CIPHER_free(a->cipher_list);
sk_SSL_CIPHER_free(a->cipher_list_by_id);
ssl_cert_free(a->cert);
SSL_CTX_SRP_CTX_free(a);
#endif
#ifndef OPENSSL_NO_ENGINE
- if (a->client_cert_engine)
- ENGINE_finish(a->client_cert_engine);
+ ENGINE_finish(a->client_cert_engine);
#endif
#ifndef OPENSSL_NO_EC
#endif
OPENSSL_free(a->alpn_client_proto_list);
+ CRYPTO_THREAD_lock_free(a->lock);
+
OPENSSL_free(a);
}
ctx->default_passwd_callback_userdata = u;
}
+pem_password_cb *SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
+{
+ return ctx->default_passwd_callback;
+}
+
+void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
+{
+ return ctx->default_passwd_callback_userdata;
+}
+
void SSL_set_default_passwd_cb(SSL *s, pem_password_cb *cb)
{
s->default_passwd_callback = cb;
s->default_passwd_callback_userdata = u;
}
+pem_password_cb *SSL_get_default_passwd_cb(SSL *s)
+{
+ return s->default_passwd_callback;
+}
+
+void *SSL_get_default_passwd_cb_userdata(SSL *s)
+{
+ return s->default_passwd_callback_userdata;
+}
+
void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
int (*cb) (X509_STORE_CTX *, void *),
void *arg)
ssl_cert_set_cert_cb(s->cert, cb, arg);
}
-void ssl_set_masks(SSL *s, const SSL_CIPHER *cipher)
+void ssl_set_masks(SSL *s)
{
#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_GOST)
CERT_PKEY *cpk;
unsigned long mask_k, mask_a;
#ifndef OPENSSL_NO_EC
int have_ecc_cert, ecdsa_ok;
- int ecdh_ok;
X509 *x = NULL;
- int pk_nid = 0, md_nid = 0;
#endif
if (c == NULL)
return;
mask_a = 0;
#ifdef CIPHER_DEBUG
- fprintf(stderr,
- "dht=%d re=%d rs=%d ds=%d dhr=%d dhd=%d\n",
- dh_tmp, rsa_enc, rsa_sign, dsa_sign, dh_rsa, dh_dsa);
+ fprintf(stderr, "dht=%d re=%d rs=%d ds=%d\n",
+ dh_tmp, rsa_enc, rsa_sign, dsa_sign);
#endif
#ifndef OPENSSL_NO_GOST
cpk = &c->pkeys[SSL_PKEY_ECC];
x = cpk->x509;
ex_kusage = X509_get_key_usage(x);
- ecdh_ok = ex_kusage & X509v3_KU_KEY_AGREEMENT;
ecdsa_ok = ex_kusage & X509v3_KU_DIGITAL_SIGNATURE;
if (!(pvalid[SSL_PKEY_ECC] & CERT_PKEY_SIGN))
ecdsa_ok = 0;
- OBJ_find_sigid_algs(X509_get_signature_nid(x), &md_nid, &pk_nid);
- if (ecdh_ok) {
-
- if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa) {
- mask_k |= SSL_kECDHr;
- mask_a |= SSL_aECDH;
- }
-
- if (pk_nid == NID_X9_62_id_ecPublicKey) {
- mask_k |= SSL_kECDHe;
- mask_a |= SSL_aECDH;
- }
- }
- if (ecdsa_ok) {
+ if (ecdsa_ok)
mask_a |= SSL_aECDSA;
- }
}
#endif
int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
{
- unsigned long alg_k, alg_a;
- int md_nid = 0, pk_nid = 0;
- const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
- uint32_t ex_kusage = X509_get_key_usage(x);
-
- alg_k = cs->algorithm_mkey;
- alg_a = cs->algorithm_auth;
-
- OBJ_find_sigid_algs(X509_get_signature_nid(x), &md_nid, &pk_nid);
-
- if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr) {
- /* key usage, if present, must allow key agreement */
- if (!(ex_kusage & X509v3_KU_KEY_AGREEMENT)) {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
- SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
- return 0;
- }
- if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION) {
- /* signature alg must be ECDSA */
- if (pk_nid != NID_X9_62_id_ecPublicKey) {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
- SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE);
- return 0;
- }
- }
- if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION) {
- /* signature alg must be RSA */
-
- if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa) {
- SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
- SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE);
- return 0;
- }
- }
- }
- if (alg_a & SSL_aECDSA) {
+ if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA) {
/* key usage, if present, must allow signing */
- if (!(ex_kusage & X509v3_KU_DIGITAL_SIGNATURE)) {
+ if (!(X509_get_key_usage(x) & X509v3_KU_DIGITAL_SIGNATURE)) {
SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
SSL_R_ECC_CERT_NOT_FOR_SIGNING);
return 0;
}
}
-
return 1; /* all checks are ok */
}
c = s->cert;
if (!s->s3 || !s->s3->tmp.new_cipher)
return NULL;
- ssl_set_masks(s, s->s3->tmp.new_cipher);
-
-#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
- /*
- * Broken protocol test: return last used certificate: which may mismatch
- * the one expected.
- */
- if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
- return c->key;
-#endif
+ ssl_set_masks(s);
i = ssl_get_server_cert_index(s);
alg_a = cipher->algorithm_auth;
c = s->cert;
-#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
- /*
- * Broken protocol test: use last key: which may mismatch the one
- * expected.
- */
- if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
- idx = c->key - c->pkeys;
- else
-#endif
-
if ((alg_a & SSL_aDSS) &&
(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
idx = SSL_PKEY_DSA_SIGN;
&& ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
|| SSL_CTX_add_session(s->session_ctx, s->session))
&& (s->session_ctx->new_session_cb != NULL)) {
- CRYPTO_add(&s->session->references, 1, CRYPTO_LOCK_SSL_SESSION);
+ SSL_SESSION_up_ref(s->session);
if (!s->session_ctx->new_session_cb(s, s->session))
SSL_SESSION_free(s->session);
}
return (0);
}
-SSL_METHOD *ssl_bad_method(int ver)
+const SSL_METHOD *ssl_bad_method(int ver)
{
SSLerr(SSL_F_SSL_BAD_METHOD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return (NULL);
}
-const char *SSL_get_version(const SSL *s)
-{
- if (s->version == TLS1_2_VERSION)
- return ("TLSv1.2");
- else if (s->version == TLS1_1_VERSION)
- return ("TLSv1.1");
- else if (s->version == TLS1_VERSION)
- return ("TLSv1");
- else if (s->version == SSL3_VERSION)
- return ("SSLv3");
- else if (s->version == DTLS1_BAD_VER)
- return ("DTLSv0.9");
- else if (s->version == DTLS1_VERSION)
- return ("DTLSv1");
- else if (s->version == DTLS1_2_VERSION)
- return ("DTLSv1.2");
+const char *ssl_protocol_to_string(int version)
+{
+ if (version == TLS1_2_VERSION)
+ return "TLSv1.2";
+ else if (version == TLS1_1_VERSION)
+ return "TLSv1.1";
+ else if (version == TLS1_VERSION)
+ return "TLSv1";
+ else if (version == SSL3_VERSION)
+ return "SSLv3";
+ else if (version == DTLS1_BAD_VER)
+ return "DTLSv0.9";
+ else if (version == DTLS1_VERSION)
+ return "DTLSv1";
+ else if (version == DTLS1_2_VERSION)
+ return "DTLSv1.2";
else
return ("unknown");
}
+const char *SSL_get_version(const SSL *s)
+{
+ return ssl_protocol_to_string(s->version);
+}
+
SSL *SSL_dup(SSL *s)
{
STACK_OF(X509_NAME) *sk;
/* If we're not quiescent, just up_ref! */
if (!SSL_in_init(s) || !SSL_in_before(s)) {
- CRYPTO_add(&s->references, 1, CRYPTO_LOCK_SSL);
+ CRYPTO_atomic_add(&s->references, 1, &i, s->lock);
return s;
}
if (s->bbio == s->wbio) {
/* remove buffering */
s->wbio = BIO_pop(s->wbio);
-#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids
- * adding one more preprocessor symbol */
+#ifdef REF_DEBUG
+ /*
+ * not the usual REF_DEBUG, but this avoids
+ * adding one more preprocessor symbol
+ */
assert(s->wbio != NULL);
#endif
}
memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
}
- CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
+ SSL_CTX_up_ref(ctx);
SSL_CTX_free(ssl->ctx); /* decrement reference count */
ssl->ctx = ctx;
- return (ssl->ctx);
+ return ssl->ctx;
}
int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
return ret;
}
-int SSL_cache_hit(SSL *s)
+int SSL_session_reused(SSL *s)
{
return s->hit;
}
}
void SSL_set_security_callback(SSL *s,
- int (*cb) (SSL *s, SSL_CTX *ctx, int op,
+ int (*cb) (const SSL *s, const 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 (*SSL_get_security_callback(const SSL *s)) (const SSL *s, const SSL_CTX *ctx, int op,
int bits, int nid,
void *other, void *ex) {
return s->cert->sec_cb;
}
void SSL_CTX_set_security_callback(SSL_CTX *ctx,
- int (*cb) (SSL *s, SSL_CTX *ctx, int op,
+ int (*cb) (const SSL *s, const 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 (*SSL_CTX_get_security_callback(const SSL_CTX *ctx)) (const SSL *s,
+ const SSL_CTX *ctx,
int op, int bits,
int nid,
void *other,
return s->options &= ~op;
}
+STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s)
+{
+ return s->verified_chain;
+}
+
IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
+
+#ifndef OPENSSL_NO_CT
+
+/*
+ * Moves SCTs from the |src| stack to the |dst| stack.
+ * The source of each SCT will be set to |origin|.
+ * If |dst| points to a NULL pointer, a new stack will be created and owned by
+ * the caller.
+ * Returns the number of SCTs moved, or a negative integer if an error occurs.
+ */
+static int ct_move_scts(STACK_OF(SCT) **dst, STACK_OF(SCT) *src, sct_source_t origin)
+{
+ int scts_moved = 0;
+ SCT *sct = NULL;
+
+ if (*dst == NULL) {
+ *dst = sk_SCT_new_null();
+ if (*dst == NULL) {
+ SSLerr(SSL_F_CT_MOVE_SCTS, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ while ((sct = sk_SCT_pop(src)) != NULL) {
+ if (SCT_set_source(sct, origin) != 1)
+ goto err;
+
+ if (sk_SCT_push(*dst, sct) <= 0)
+ goto err;
+ scts_moved += 1;
+ }
+
+ return scts_moved;
+err:
+ if (sct != NULL)
+ sk_SCT_push(src, sct); /* Put the SCT back */
+ return scts_moved;
+}
+
+/*
+* Look for data collected during ServerHello and parse if found.
+* Return 1 on success, 0 on failure.
+*/
+static int ct_extract_tls_extension_scts(SSL *s)
+{
+ int scts_extracted = 0;
+
+ if (s->tlsext_scts != NULL) {
+ const unsigned char *p = s->tlsext_scts;
+ STACK_OF(SCT) *scts = o2i_SCT_LIST(NULL, &p, s->tlsext_scts_len);
+
+ scts_extracted = ct_move_scts(&s->scts, scts, SCT_SOURCE_TLS_EXTENSION);
+
+ SCT_LIST_free(scts);
+ }
+
+ return scts_extracted;
+}
+
+/*
+ * Checks for an OCSP response and then attempts to extract any SCTs found if it
+ * contains an SCT X509 extension. They will be stored in |s->scts|.
+ * Returns:
+ * - The number of SCTs extracted, assuming an OCSP response exists.
+ * - 0 if no OCSP response exists or it contains no SCTs.
+ * - A negative integer if an error occurs.
+ */
+static int ct_extract_ocsp_response_scts(SSL *s)
+{
+ int scts_extracted = 0;
+ const unsigned char *p;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPONSE *rsp = NULL;
+ STACK_OF(SCT) *scts = NULL;
+ int i;
+
+ if (s->tlsext_ocsp_resp == NULL || s->tlsext_ocsp_resplen == 0)
+ goto err;
+
+ p = s->tlsext_ocsp_resp;
+ rsp = d2i_OCSP_RESPONSE(NULL, &p, s->tlsext_ocsp_resplen);
+ if (rsp == NULL)
+ goto err;
+
+ br = OCSP_response_get1_basic(rsp);
+ if (br == NULL)
+ goto err;
+
+ for (i = 0; i < OCSP_resp_count(br); ++i) {
+ OCSP_SINGLERESP *single = OCSP_resp_get0(br, i);
+
+ if (single == NULL)
+ continue;
+
+ scts = OCSP_SINGLERESP_get1_ext_d2i(single, NID_ct_cert_scts, NULL, NULL);
+ scts_extracted = ct_move_scts(&s->scts, scts,
+ SCT_SOURCE_OCSP_STAPLED_RESPONSE);
+ if (scts_extracted < 0)
+ goto err;
+ }
+err:
+ SCT_LIST_free(scts);
+ OCSP_BASICRESP_free(br);
+ OCSP_RESPONSE_free(rsp);
+ return scts_extracted;
+}
+
+/*
+ * Attempts to extract SCTs from the peer certificate.
+ * Return the number of SCTs extracted, or a negative integer if an error
+ * occurs.
+ */
+static int ct_extract_x509v3_extension_scts(SSL *s)
+{
+ int scts_extracted = 0;
+ X509 *cert = s->session != NULL ? s->session->peer : NULL;
+
+ if (cert != NULL) {
+ STACK_OF(SCT) *scts =
+ X509_get_ext_d2i(cert, NID_ct_precert_scts, NULL, NULL);
+
+ scts_extracted =
+ ct_move_scts(&s->scts, scts, SCT_SOURCE_X509V3_EXTENSION);
+
+ SCT_LIST_free(scts);
+ }
+
+ return scts_extracted;
+}
+
+/*
+ * Attempts to find all received SCTs by checking TLS extensions, the OCSP
+ * response (if it exists) and X509v3 extensions in the certificate.
+ * Returns NULL if an error occurs.
+ */
+const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s)
+{
+ if (!s->scts_parsed) {
+ if (ct_extract_tls_extension_scts(s) < 0 ||
+ ct_extract_ocsp_response_scts(s) < 0 ||
+ ct_extract_x509v3_extension_scts(s) < 0)
+ goto err;
+
+ s->scts_parsed = 1;
+ }
+ return s->scts;
+err:
+ return NULL;
+}
+
+int SSL_set_ct_validation_callback(SSL *s, ct_validation_cb callback, void *arg)
+{
+ int ret = 0;
+
+ /*
+ * Since code exists that uses the custom extension handler for CT, look
+ * for this and throw an error if they have already registered to use CT.
+ */
+ if (callback != NULL && SSL_CTX_has_client_custom_ext(s->ctx,
+ TLSEXT_TYPE_signed_certificate_timestamp)) {
+ SSLerr(SSL_F_SSL_SET_CT_VALIDATION_CALLBACK,
+ SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
+ goto err;
+ }
+
+ s->ct_validation_callback = callback;
+ s->ct_validation_callback_arg = arg;
+
+ if (callback != NULL) {
+ /* If we are validating CT, then we MUST accept SCTs served via OCSP */
+ if (!SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp))
+ goto err;
+ }
+
+ ret = 1;
+err:
+ return ret;
+}
+
+int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx, ct_validation_cb callback,
+ void *arg)
+{
+ int ret = 0;
+
+ /*
+ * Since code exists that uses the custom extension handler for CT, look for
+ * this and throw an error if they have already registered to use CT.
+ */
+ if (callback != NULL && SSL_CTX_has_client_custom_ext(ctx,
+ TLSEXT_TYPE_signed_certificate_timestamp)) {
+ SSLerr(SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK,
+ SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
+ goto err;
+ }
+
+ ctx->ct_validation_callback = callback;
+ ctx->ct_validation_callback_arg = arg;
+ ret = 1;
+err:
+ return ret;
+}
+
+ct_validation_cb SSL_get_ct_validation_callback(const SSL *s)
+{
+ return s->ct_validation_callback;
+}
+
+ct_validation_cb SSL_CTX_get_ct_validation_callback(const SSL_CTX *ctx)
+{
+ return ctx->ct_validation_callback;
+}
+
+int ssl_validate_ct(SSL *s)
+{
+ int ret = 0;
+ X509 *cert = s->session != NULL ? s->session->peer : NULL;
+ X509 *issuer = NULL;
+ CT_POLICY_EVAL_CTX *ctx = NULL;
+ const STACK_OF(SCT) *scts;
+
+ /* If no callback is set, attempt no validation - just return success */
+ if (s->ct_validation_callback == NULL)
+ return 1;
+
+ if (cert == NULL) {
+ SSLerr(SSL_F_SSL_VALIDATE_CT, SSL_R_NO_CERTIFICATE_ASSIGNED);
+ goto end;
+ }
+
+ if (s->verified_chain != NULL && sk_X509_num(s->verified_chain) > 1)
+ issuer = sk_X509_value(s->verified_chain, 1);
+
+ ctx = CT_POLICY_EVAL_CTX_new();
+ if (ctx == NULL) {
+ SSLerr(SSL_F_SSL_VALIDATE_CT, ERR_R_MALLOC_FAILURE);
+ goto end;
+ }
+
+ CT_POLICY_EVAL_CTX_set0_cert(ctx, cert);
+ CT_POLICY_EVAL_CTX_set0_issuer(ctx, issuer);
+ CT_POLICY_EVAL_CTX_set0_log_store(ctx, s->ctx->ctlog_store);
+
+ scts = SSL_get0_peer_scts(s);
+
+ if (SCT_LIST_validate(scts, ctx) != 1) {
+ SSLerr(SSL_F_SSL_VALIDATE_CT, SSL_R_SCT_VERIFICATION_FAILED);
+ goto end;
+ }
+
+ ret = s->ct_validation_callback(ctx, scts, s->ct_validation_callback_arg);
+ if (ret < 0)
+ ret = 0; /* This function returns 0 on failure */
+
+end:
+ CT_POLICY_EVAL_CTX_free(ctx);
+ return ret;
+}
+
+int SSL_CTX_set_default_ctlog_list_file(SSL_CTX *ctx)
+{
+ return CTLOG_STORE_load_default_file(ctx->ctlog_store);
+}
+
+int SSL_CTX_set_ctlog_list_file(SSL_CTX *ctx, const char *path)
+{
+ return CTLOG_STORE_load_file(ctx->ctlog_store, path);
+}
+
+void SSL_CTX_set0_ctlog_store(SSL_CTX *ctx, CTLOG_STORE *logs)
+{
+ CTLOG_STORE_free(ctx->ctlog_store);
+ ctx->ctlog_store = logs;
+}
+
+const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx)
+{
+ return ctx->ctlog_store;
+}
+
+#endif