*/
#include <stdio.h>
-#include "ssl_locl.h"
+#include "ssl_local.h"
+#include "e_os.h"
#include <openssl/objects.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
/* Clear the verification result peername */
X509_VERIFY_PARAM_move_peername(s->param, NULL);
+ /* Clear any shared connection state */
+ OPENSSL_free(s->shared_sigalgs);
+ s->shared_sigalgs = NULL;
+ s->shared_sigalgslen = 0;
+
/*
* Check to see if we were changed into a different method, if so, revert
* back.
ctx->method = meth;
- if (!SSL_CTX_set_ciphersuites(ctx, TLS_DEFAULT_CIPHERSUITES)) {
+ if (!SSL_CTX_set_ciphersuites(ctx, OSSL_default_ciphersuites())) {
SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
return 0;
}
ctx->tls13_ciphersuites,
&(ctx->cipher_list),
&(ctx->cipher_list_by_id),
- SSL_DEFAULT_CIPHER_LIST, ctx->cert);
+ OSSL_default_cipher_list(), ctx->cert);
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) {
SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
return 0;
s->ext.ecpointformats_len =
ctx->ext.ecpointformats_len;
}
+#endif
if (ctx->ext.supportedgroups) {
s->ext.supportedgroups =
OPENSSL_memdup(ctx->ext.supportedgroups,
goto err;
s->ext.supportedgroups_len = ctx->ext.supportedgroups_len;
}
-#endif
+
#ifndef OPENSSL_NO_NEXTPROTONEG
s->ext.npn = NULL;
#endif
int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
unsigned int sid_ctx_len)
{
- if (sid_ctx_len > sizeof(ctx->sid_ctx)) {
+ if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,
SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
return 0;
sk_SSL_CIPHER_free(s->cipher_list);
sk_SSL_CIPHER_free(s->cipher_list_by_id);
sk_SSL_CIPHER_free(s->tls13_ciphersuites);
+ sk_SSL_CIPHER_free(s->peer_ciphers);
/* Make the next call work :-) */
if (s->session != NULL) {
clear_ciphers(s);
ssl_cert_free(s->cert);
+ OPENSSL_free(s->shared_sigalgs);
/* Free up if allocated */
OPENSSL_free(s->ext.hostname);
SSL_CTX_free(s->session_ctx);
#ifndef OPENSSL_NO_EC
OPENSSL_free(s->ext.ecpointformats);
- OPENSSL_free(s->ext.supportedgroups);
+ OPENSSL_free(s->ext.peer_ecpointformats);
#endif /* OPENSSL_NO_EC */
+ OPENSSL_free(s->ext.supportedgroups);
+ OPENSSL_free(s->ext.peer_supportedgroups);
sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free);
#ifndef OPENSSL_NO_OCSP
sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free);
{
size_t ret = 0;
- if (s->s3 != NULL) {
- ret = s->s3->tmp.finish_md_len;
- if (count > ret)
- count = ret;
- memcpy(buf, s->s3->tmp.finish_md, count);
- }
+ ret = s->s3.tmp.finish_md_len;
+ if (count > ret)
+ count = ret;
+ memcpy(buf, s->s3.tmp.finish_md, count);
return ret;
}
{
size_t ret = 0;
- if (s->s3 != NULL) {
- ret = s->s3->tmp.peer_finish_md_len;
- if (count > ret)
- count = ret;
- memcpy(buf, s->s3->tmp.peer_finish_md, count);
- }
+ ret = s->s3.tmp.peer_finish_md_len;
+ if (count > ret)
+ count = ret;
+ memcpy(buf, s->s3.tmp.peer_finish_md, count);
return ret;
}
}
}
+ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
+{
+ ossl_ssize_t ret;
+
+ if (s->handshake_func == NULL) {
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN) {
+ s->rwstate = SSL_NOTHING;
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ if (!BIO_get_ktls_send(s->wbio)) {
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ /* If we have an alert to send, lets send it */
+ if (s->s3.alert_dispatch) {
+ ret = (ossl_ssize_t)s->method->ssl_dispatch_alert(s);
+ if (ret <= 0) {
+ /* SSLfatal() already called if appropriate */
+ return ret;
+ }
+ /* if it went, fall through and send more stuff */
+ }
+
+ s->rwstate = SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0) {
+ if (!BIO_should_retry(s->wbio)) {
+ s->rwstate = SSL_NOTHING;
+ } else {
+#ifdef EAGAIN
+ set_sys_error(EAGAIN);
+#endif
+ }
+ return -1;
+ }
+
+#ifdef OPENSSL_NO_KTLS
+ ERR_raise_data(ERR_LIB_SYS, ERR_R_INTERNAL_ERROR, "calling sendfile()");
+ return -1;
+#else
+ ret = ktls_sendfile(SSL_get_wfd(s), fd, offset, size, flags);
+ if (ret < 0) {
+#if defined(EAGAIN) && defined(EINTR) && defined(EBUSY)
+ if ((get_last_sys_error() == EAGAIN) ||
+ (get_last_sys_error() == EINTR) ||
+ (get_last_sys_error() == EBUSY))
+ BIO_set_retry_write(s->wbio);
+ else
+#endif
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+ return ret;
+ }
+ s->rwstate = SSL_NOTHING;
+ return ret;
+#endif
+}
+
int SSL_write(SSL *s, const void *buf, int num)
{
int ret;
RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
return 1;
case SSL_CTRL_GET_RI_SUPPORT:
- if (s->s3)
- return s->s3->send_connection_binding;
- else
- return 0;
+ return s->s3.send_connection_binding;
case SSL_CTRL_CERT_FLAGS:
return (s->cert->cert_flags |= larg);
case SSL_CTRL_CLEAR_CERT_FLAGS:
case SSL_CTRL_GET_RAW_CIPHERLIST:
if (parg) {
- if (s->s3->tmp.ciphers_raw == NULL)
+ if (s->s3.tmp.ciphers_raw == NULL)
return 0;
- *(unsigned char **)parg = s->s3->tmp.ciphers_raw;
- return (int)s->s3->tmp.ciphers_rawlen;
+ *(unsigned char **)parg = s->s3.tmp.ciphers_raw;
+ return (int)s->s3.tmp.ciphers_rawlen;
} else {
return TLS_CIPHER_LEN;
}
STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s)
{
- if ((s == NULL) || (s->session == NULL) || !s->server)
+ if ((s == NULL) || !s->server)
return NULL;
- return s->session->ciphers;
+ return s->peer_ciphers;
}
STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
int i;
if (!s->server
- || s->session == NULL
- || s->session->ciphers == NULL
+ || s->peer_ciphers == NULL
|| size < 2)
return NULL;
p = buf;
- clntsk = s->session->ciphers;
+ clntsk = s->peer_ciphers;
srvrsk = SSL_get_ciphers(s);
if (clntsk == NULL || srvrsk == NULL)
return NULL;
unsigned *len)
{
*data = s->ext.npn;
- if (!*data) {
+ if (*data == NULL) {
*len = 0;
} else {
*len = (unsigned int)s->ext.npn_len;
void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
unsigned int *len)
{
- *data = NULL;
- if (ssl->s3)
- *data = ssl->s3->alpn_selected;
+ *data = ssl->s3.alpn_selected;
if (*data == NULL)
*len = 0;
else
- *len = (unsigned int)ssl->s3->alpn_selected_len;
+ *len = (unsigned int)ssl->s3.alpn_selected_len;
}
int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
* via ssl.h.
*/
-SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+SSL_CTX *SSL_CTX_new_with_libctx(OPENSSL_CTX *libctx, const char *propq,
+ const SSL_METHOD *meth)
{
SSL_CTX *ret = NULL;
if (meth == NULL) {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_NULL_SSL_METHOD_PASSED);
+ SSLerr(0, SSL_R_NULL_SSL_METHOD_PASSED);
return NULL;
}
return NULL;
if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+ SSLerr(0, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
goto err;
}
ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL)
goto err;
+ ret->libctx = libctx;
+ if (propq != NULL) {
+ ret->propq = OPENSSL_strdup(propq);
+ if (ret->propq == NULL)
+ goto err;
+ }
+
ret->method = meth;
ret->min_proto_version = 0;
ret->max_proto_version = 0;
ret->references = 1;
ret->lock = CRYPTO_THREAD_lock_new();
if (ret->lock == NULL) {
- SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ SSLerr(0, ERR_R_MALLOC_FAILURE);
OPENSSL_free(ret);
return NULL;
}
goto err;
#endif
- if (!SSL_CTX_set_ciphersuites(ret, TLS_DEFAULT_CIPHERSUITES))
+ if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites()))
goto err;
if (!ssl_create_cipher_list(ret->method,
ret->tls13_ciphersuites,
&ret->cipher_list, &ret->cipher_list_by_id,
- SSL_DEFAULT_CIPHER_LIST, ret->cert)
+ OSSL_default_cipher_list(), ret->cert)
|| sk_SSL_CIPHER_num(ret->cipher_list) <= 0) {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_LIBRARY_HAS_NO_CIPHERS);
+ SSLerr(0, SSL_R_LIBRARY_HAS_NO_CIPHERS);
goto err2;
}
goto err;
if ((ret->md5 = EVP_get_digestbyname("ssl3-md5")) == NULL) {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
+ SSLerr(0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
goto err2;
}
if ((ret->sha1 = EVP_get_digestbyname("ssl3-sha1")) == NULL) {
- SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
+ SSLerr(0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
goto err2;
}
ret->split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
/* Setup RFC5077 ticket keys */
- if ((RAND_bytes(ret->ext.tick_key_name,
- sizeof(ret->ext.tick_key_name)) <= 0)
- || (RAND_priv_bytes(ret->ext.secure->tick_hmac_key,
- sizeof(ret->ext.secure->tick_hmac_key)) <= 0)
- || (RAND_priv_bytes(ret->ext.secure->tick_aes_key,
- sizeof(ret->ext.secure->tick_aes_key)) <= 0))
+ if ((RAND_bytes_ex(libctx, ret->ext.tick_key_name,
+ sizeof(ret->ext.tick_key_name)) <= 0)
+ || (RAND_priv_bytes_ex(libctx, ret->ext.secure->tick_hmac_key,
+ sizeof(ret->ext.secure->tick_hmac_key)) <= 0)
+ || (RAND_priv_bytes_ex(libctx, ret->ext.secure->tick_aes_key,
+ sizeof(ret->ext.secure->tick_aes_key)) <= 0))
ret->options |= SSL_OP_NO_TICKET;
- if (RAND_priv_bytes(ret->ext.cookie_hmac_key,
- sizeof(ret->ext.cookie_hmac_key)) <= 0)
+ if (RAND_priv_bytes_ex(libctx, ret->ext.cookie_hmac_key,
+ sizeof(ret->ext.cookie_hmac_key)) <= 0)
goto err;
#ifndef OPENSSL_NO_SRP
return ret;
err:
- SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ SSLerr(0, ERR_R_MALLOC_FAILURE);
err2:
SSL_CTX_free(ret);
return NULL;
}
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+{
+ return SSL_CTX_new_with_libctx(NULL, NULL, meth);
+}
+
int SSL_CTX_up_ref(SSL_CTX *ctx)
{
int i;
#ifndef OPENSSL_NO_EC
OPENSSL_free(a->ext.ecpointformats);
- OPENSSL_free(a->ext.supportedgroups);
#endif
+ OPENSSL_free(a->ext.supportedgroups);
OPENSSL_free(a->ext.alpn);
OPENSSL_secure_free(a->ext.secure);
CRYPTO_THREAD_lock_free(a->lock);
+ OPENSSL_free(a->propq);
+
OPENSSL_free(a);
}
void ssl_set_masks(SSL *s)
{
CERT *c = s->cert;
- uint32_t *pvalid = s->s3->tmp.valid_flags;
+ uint32_t *pvalid = s->s3.tmp.valid_flags;
int rsa_enc, rsa_sign, dh_tmp, dsa_sign;
unsigned long mask_k, mask_a;
#ifndef OPENSSL_NO_EC
mask_k |= SSL_kECDHEPSK;
#endif
- s->s3->tmp.mask_k = mask_k;
- s->s3->tmp.mask_a = mask_a;
+ s->s3.tmp.mask_k = mask_k;
+ s->s3.tmp.mask_a = mask_a;
}
#ifndef OPENSSL_NO_EC
int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
{
- if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA) {
+ if (s->s3.tmp.new_cipher->algorithm_auth & SSL_aECDSA) {
/* key usage, if present, must allow signing */
if (!(X509_get_key_usage(x) & X509v3_KU_DIGITAL_SIGNATURE)) {
SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG,
int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
size_t *serverinfo_length)
{
- CERT_PKEY *cpk = s->s3->tmp.cert;
+ CERT_PKEY *cpk = s->s3.tmp.cert;
*serverinfo_length = 0;
if (cpk == NULL || cpk->serverinfo == NULL)
return SSL_ERROR_WANT_CLIENT_HELLO_CB;
if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
- (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY))
+ (s->s3.warn_alert == SSL_AD_CLOSE_NOTIFY))
return SSL_ERROR_ZERO_RETURN;
return SSL_ERROR_SYSCALL;
const SSL_CIPHER *SSL_get_pending_cipher(const SSL *s)
{
- return s->s3->tmp.new_cipher;
+ return s->s3.tmp.new_cipher;
}
const COMP_METHOD *SSL_get_current_compression(const SSL *s)
lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_hash_dir());
if (lookup == NULL)
return 0;
+
+ /* We ignore errors, in case the directory doesn't exist */
+ ERR_set_mark();
+
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
- /* Clear any errors if the default directory does not exist */
- ERR_clear_error();
+ ERR_pop_to_mark();
return 1;
}
if (lookup == NULL)
return 0;
+ /* We ignore errors, in case the directory doesn't exist */
+ ERR_set_mark();
+
X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
- /* Clear any errors if the default file does not exist */
- ERR_clear_error();
+ ERR_pop_to_mark();
+
+ return 1;
+}
+
+int SSL_CTX_set_default_verify_store(SSL_CTX *ctx)
+{
+ X509_LOOKUP *lookup;
+
+ lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_store());
+ if (lookup == NULL)
+ return 0;
+
+ /* We ignore errors, in case the directory doesn't exist */
+ ERR_set_mark();
+
+ X509_LOOKUP_add_store(lookup, NULL);
+
+ ERR_pop_to_mark();
return 1;
}
+int SSL_CTX_load_verify_file(SSL_CTX *ctx, const char *CAfile)
+{
+ return X509_STORE_load_file(ctx->cert_store, CAfile);
+}
+
+int SSL_CTX_load_verify_dir(SSL_CTX *ctx, const char *CApath)
+{
+ return X509_STORE_load_path(ctx->cert_store, CApath);
+}
+
+int SSL_CTX_load_verify_store(SSL_CTX *ctx, const char *CAstore)
+{
+ return X509_STORE_load_store(ctx->cert_store, CAstore);
+}
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath)
{
- return X509_STORE_load_locations(ctx->cert_store, CAfile, CApath);
+ if (CAfile == NULL && CApath == NULL)
+ return 0;
+ if (CAfile != NULL && !SSL_CTX_load_verify_file(ctx, CAfile))
+ return 0;
+ if (CApath != NULL && !SSL_CTX_load_verify_dir(ctx, CApath))
+ return 0;
+ return 1;
}
+#endif
void SSL_set_info_callback(SSL *ssl,
void (*cb) (const SSL *ssl, int type, int val))
size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen)
{
if (outlen == 0)
- return sizeof(ssl->s3->client_random);
- if (outlen > sizeof(ssl->s3->client_random))
- outlen = sizeof(ssl->s3->client_random);
- memcpy(out, ssl->s3->client_random, outlen);
+ return sizeof(ssl->s3.client_random);
+ if (outlen > sizeof(ssl->s3.client_random))
+ outlen = sizeof(ssl->s3.client_random);
+ memcpy(out, ssl->s3.client_random, outlen);
return outlen;
}
size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen)
{
if (outlen == 0)
- return sizeof(ssl->s3->server_random);
- if (outlen > sizeof(ssl->s3->server_random))
- outlen = sizeof(ssl->s3->server_random);
- memcpy(out, ssl->s3->server_random, outlen);
+ return sizeof(ssl->s3.server_random);
+ if (outlen > sizeof(ssl->s3.server_random))
+ outlen = sizeof(ssl->s3.server_random);
+ memcpy(out, ssl->s3.server_random, outlen);
return outlen;
}
size_t *hashlen)
{
EVP_MD_CTX *ctx = NULL;
- EVP_MD_CTX *hdgst = s->s3->handshake_dgst;
+ EVP_MD_CTX *hdgst = s->s3.handshake_dgst;
int hashleni = EVP_MD_CTX_size(hdgst);
int ret = 0;
return ret;
}
-int SSL_session_reused(SSL *s)
+int SSL_session_reused(const SSL *s)
{
return s->hit;
}
return s->server;
}
-#if !OPENSSL_API_1_1_0
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
void SSL_set_debug(SSL *s, int debug)
{
/* Old function was do-nothing anyway... */
{
return nss_keylog_int(label,
ssl,
- ssl->s3->client_random,
+ ssl->s3.client_random,
SSL3_RANDOM_SIZE,
secret,
secret_len);
return 0;
}
- OPENSSL_free(s->s3->tmp.ciphers_raw);
- s->s3->tmp.ciphers_raw = NULL;
- s->s3->tmp.ciphers_rawlen = 0;
+ OPENSSL_free(s->s3.tmp.ciphers_raw);
+ s->s3.tmp.ciphers_raw = NULL;
+ s->s3.tmp.ciphers_rawlen = 0;
if (sslv2format) {
size_t numciphers = PACKET_remaining(cipher_suites) / n;
* problem.
*/
raw = OPENSSL_malloc(numciphers * TLS_CIPHER_LEN);
- s->s3->tmp.ciphers_raw = raw;
+ s->s3.tmp.ciphers_raw = raw;
if (raw == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
ERR_R_MALLOC_FAILURE);
return 0;
}
- for (s->s3->tmp.ciphers_rawlen = 0;
+ for (s->s3.tmp.ciphers_rawlen = 0;
PACKET_remaining(&sslv2ciphers) > 0;
raw += TLS_CIPHER_LEN) {
if (!PACKET_get_1(&sslv2ciphers, &leadbyte)
&& !PACKET_forward(&sslv2ciphers, TLS_CIPHER_LEN))) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
SSL_R_BAD_PACKET);
- OPENSSL_free(s->s3->tmp.ciphers_raw);
- s->s3->tmp.ciphers_raw = NULL;
- s->s3->tmp.ciphers_rawlen = 0;
+ OPENSSL_free(s->s3.tmp.ciphers_raw);
+ s->s3.tmp.ciphers_raw = NULL;
+ s->s3.tmp.ciphers_rawlen = 0;
return 0;
}
if (leadbyte == 0)
- s->s3->tmp.ciphers_rawlen += TLS_CIPHER_LEN;
+ s->s3.tmp.ciphers_rawlen += TLS_CIPHER_LEN;
}
- } else if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
- &s->s3->tmp.ciphers_rawlen)) {
+ } else if (!PACKET_memdup(cipher_suites, &s->s3.tmp.ciphers_raw,
+ &s->s3.tmp.ciphers_rawlen)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_CACHE_CIPHERLIST,
ERR_R_INTERNAL_ERROR);
return 0;
ERR_clear_error();
- s->s3->flags |= TLS1_FLAGS_STATELESS;
+ s->s3.flags |= TLS1_FLAGS_STATELESS;
ret = SSL_accept(s);
- s->s3->flags &= ~TLS1_FLAGS_STATELESS;
+ s->s3.flags &= ~TLS1_FLAGS_STATELESS;
if (ret > 0 && s->ext.cookieok)
return 1;