Пример #1
0
static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
	{
	ERR_STRING_DATA *p;
	LHASH *hash;

	err_fns_check();
	hash = ERRFN(err_get)(0);
	if (!hash)
		return NULL;

	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
	p = (ERR_STRING_DATA *)lh_retrieve(hash, d);
	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);

	return p;
	}
Пример #2
0
static int ssleay_rand_status(void)
	{
	CRYPTO_THREADID cur;
	int ret;
	int do_not_lock;

	CRYPTO_THREADID_current(&cur);
	/* check if we already have the lock
	 * (could happen if a RAND_poll() implementation calls RAND_status()) */
	if (crypto_lock_rand)
		{
		CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
		do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
		CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
		}
	else
		do_not_lock = 0;
	
	if (!do_not_lock)
		{
		CRYPTO_w_lock(CRYPTO_LOCK_RAND);
		
		/* prevent ssleay_rand_bytes() from trying to obtain the lock again */
		CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
		CRYPTO_THREADID_cpy(&locking_threadid, &cur);
		CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
		crypto_lock_rand = 1;
		}
	
	if (!initialized)
		{
		RAND_poll();
		initialized = 1;
		}

	ret = entropy >= ENTROPY_NEEDED;

	if (!do_not_lock)
		{
		/* before unlocking, we must clear 'crypto_lock_rand' */
		crypto_lock_rand = 0;
		
		CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
		}
	
	return ret;
	}
Пример #3
0
static ERR_STATE *int_thread_get_item(const ERR_STATE *d)
	{
	ERR_STATE *p;
	LHASH *hash;

	err_fns_check();
	hash = ERRFN(thread_get)(0);
	if (!hash)
		return NULL;

	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
	p = (ERR_STATE *)lh_retrieve(hash, d);
	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);

	ERRFN(thread_release)(&hash);
	return p;
	}
Пример #4
0
static int fips_is_owning_thread(void)
	{
	int ret = 0;

	if (fips_started)
		{
		CRYPTO_r_lock(CRYPTO_LOCK_FIPS2);
		if (fips_thread_set)
			{
			CRYPTO_THREADID cur;
			CRYPTO_THREADID_current(&cur);
			if (!CRYPTO_THREADID_cmp(&cur, &fips_thread))
				ret = 1;
			}
		CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2);
		}
	return ret;
	}
Пример #5
0
/* get_impl returns the current ex_data implementatation. */
static const CRYPTO_EX_DATA_IMPL *get_impl(void) {
  const CRYPTO_EX_DATA_IMPL *impl;

  CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
  impl = global_impl;
  CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);

  if (impl != NULL) {
    return impl;
  }

  CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
  if (global_impl == NULL) {
    global_impl = &ex_data_default_impl;
  }
  impl = global_impl;
  CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
  return impl;
}
Пример #6
0
const char *ERR_lib_error_string(unsigned long e)
	{
	ERR_STRING_DATA d,*p=NULL;
	unsigned long l;

	l=ERR_GET_LIB(e);

	CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH);

	if (error_hash != NULL)
		{
		d.error=ERR_PACK(l,0,0);
		p=(ERR_STRING_DATA *)lh_retrieve(error_hash,&d);
		}

	CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH);

	return((p == NULL)?NULL:p->string);
	}
Пример #7
0
BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
					const BIGNUM *mod, BN_CTX *ctx)
	{
	BN_MONT_CTX *ret;

	CRYPTO_r_lock(lock);
	ret = *pmont;
	CRYPTO_r_unlock(lock);
	if (ret)
		return ret;

	/* We don't want to serialise globally while doing our lazy-init math in
	 * BN_MONT_CTX_set. That punishes threads that are doing independent
	 * things. Instead, punish the case where more than one thread tries to
	 * lazy-init the same 'pmont', by having each do the lazy-init math work
	 * independently and only use the one from the thread that wins the race
	 * (the losers throw away the work they've done). */
	ret = BN_MONT_CTX_new();
	if (!ret)
		return NULL;
	if (!BN_MONT_CTX_set(ret, mod, ctx))
		{
		BN_MONT_CTX_free(ret);
		return NULL;
		}

	/* The locked compare-and-set, after the local work is done. */
	CRYPTO_w_lock(lock);
	if (*pmont)
		{
		BN_MONT_CTX_free(ret);
		ret = *pmont;
		}
	else
		*pmont = ret;
	CRYPTO_w_unlock(lock);
	return ret;
	}
Пример #8
0
static void ssleay_rand_add(const void *buf, int num, double add)
	{
	int i,j,k,st_idx;
	long md_c[2];
	unsigned char local_md[MD_DIGEST_LENGTH];
	EVP_MD_CTX m;
	int do_not_lock;

	/*
	 * (Based on the rand(3) manpage)
	 *
	 * The input is chopped up into units of 20 bytes (or less for
	 * the last block).  Each of these blocks is run through the hash
	 * function as follows:  The data passed to the hash function
	 * is the current 'md', the same number of bytes from the 'state'
	 * (the location determined by in incremented looping index) as
	 * the current 'block', the new key data 'block', and 'count'
	 * (which is incremented after each use).
	 * The result of this is kept in 'md' and also xored into the
	 * 'state' at the same locations that were used as input into the
         * hash function.
	 */

	/* check if we already have the lock */
	if (crypto_lock_rand)
		{
		CRYPTO_THREADID cur;
		CRYPTO_THREADID_current(&cur);
		CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
		do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
		CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
		}
	else
		do_not_lock = 0;

	if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND);
	st_idx=state_index;

	/* use our own copies of the counters so that even
	 * if a concurrent thread seeds with exactly the
	 * same data and uses the same subarray there's _some_
	 * difference */
	md_c[0] = md_count[0];
	md_c[1] = md_count[1];

	TINYCLR_SSL_MEMCPY(local_md, md, sizeof md);

	/* state_index <= state_num <= STATE_SIZE */
	state_index += num;
	if (state_index >= STATE_SIZE)
		{
		state_index%=STATE_SIZE;
		state_num=STATE_SIZE;
		}
	else if (state_num < STATE_SIZE)	
		{
		if (state_index > state_num)
			state_num=state_index;
		}
	/* state_index <= state_num <= STATE_SIZE */

	/* state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE]
	 * are what we will use now, but other threads may use them
	 * as well */

	md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);

	if (!do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND);

	EVP_MD_CTX_init(&m);
	for (i=0; i<num; i+=MD_DIGEST_LENGTH)
		{
		j=(num-i);
		j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j;

		MD_Init(&m);
		MD_Update(&m,local_md,MD_DIGEST_LENGTH);
		k=(st_idx+j)-STATE_SIZE;
		if (k > 0)
			{
			MD_Update(&m,&(state[st_idx]),j-k);
			MD_Update(&m,&(state[0]),k);
			}
		else
			MD_Update(&m,&(state[st_idx]),j);

		/* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
		MD_Update(&m,buf,j);
		/* We know that line may cause programs such as
		   purify and valgrind to complain about use of
		   uninitialized data.  The problem is not, it's
		   with the caller.  Removing that line will make
		   sure you get really bad randomness and thereby
		   other problems such as very insecure keys. */

		MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
		MD_Final(&m,local_md);
		md_c[1]++;

		buf=(const char *)buf + j;

		for (k=0; k<j; k++)
			{
			/* Parallel threads may interfere with this,
			 * but always each byte of the new state is
			 * the XOR of some previous value of its
			 * and local_md (itermediate values may be lost).
			 * Alway using locking could hurt performance more
			 * than necessary given that conflicts occur only
			 * when the total seeding is longer than the random
			 * state. */
			state[st_idx++]^=local_md[k];
			if (st_idx >= STATE_SIZE)
				st_idx=0;
			}
		}
	EVP_MD_CTX_cleanup(&m);

	if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND);
	/* Don't just copy back local_md into md -- this could mean that
	 * other thread's seeding remains without effect (except for
	 * the incremented counter).  By XORing it we keep at least as
	 * much entropy as fits into md. */
	for (k = 0; k < (int)sizeof(md); k++)
		{
		md[k] ^= local_md[k];
		}
	if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
	    entropy += add;
	if (!do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
	
#if !defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_ARM) && !defined(OPENSSL_SYS_SH)
	TINYCLR_SSL_ASSERT(md_c[1] == md_count[1]);
#endif
	}
Пример #9
0
static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
{
	BN_BLINDING *ret;
	int got_write_lock = 0;
	CRYPTO_THREADID cur;

	CRYPTO_r_lock(CRYPTO_LOCK_RSA);

	if (rsa->blinding == NULL)
		{
		CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
		CRYPTO_w_lock(CRYPTO_LOCK_RSA);
		got_write_lock = 1;

		if (rsa->blinding == NULL)
			rsa->blinding = RSA_setup_blinding(rsa, ctx);
		}

	ret = rsa->blinding;
	if (ret == NULL)
		goto err;

	CRYPTO_THREADID_current(&cur);
	if (!CRYPTO_THREADID_cmp(&cur, BN_BLINDING_thread_id(ret)))
		{
		/* rsa->blinding is ours! */

		*local = 1;
		}
	else
		{
		/* resort to rsa->mt_blinding instead */

		*local = 0; /* instructs rsa_blinding_convert(), rsa_blinding_invert()
		             * that the BN_BLINDING is shared, meaning that accesses
		             * require locks, and that the blinding factor must be
		             * stored outside the BN_BLINDING
		             */

		if (rsa->mt_blinding == NULL)
			{
			if (!got_write_lock)
				{
				CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
				CRYPTO_w_lock(CRYPTO_LOCK_RSA);
				got_write_lock = 1;
				}
			
			if (rsa->mt_blinding == NULL)
				rsa->mt_blinding = RSA_setup_blinding(rsa, ctx);
			}
		ret = rsa->mt_blinding;
		}

 err:
	if (got_write_lock)
		CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
	else
		CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
	return ret;
}
Пример #10
0
void fips_r_unlock(void)	{ CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); }
Пример #11
0
static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
	     X509_OBJECT *ret)
	{
	BY_DIR *ctx;
	union	{
		struct	{
			X509 st_x509;
			X509_CINF st_x509_cinf;
			} x509;
		struct	{
			X509_CRL st_crl;
			X509_CRL_INFO st_crl_info;
			} crl;
		} data;
	int ok=0;
	int i,j,k;
	unsigned long h;
	BUF_MEM *b=NULL;
	struct stat st;
	X509_OBJECT stmp,*tmp;
	const char *postfix="";

	if (name == NULL) return(0);

	stmp.type=type;
	if (type == X509_LU_X509)
		{
		data.x509.st_x509.cert_info= &data.x509.st_x509_cinf;
		data.x509.st_x509_cinf.subject=name;
		stmp.data.x509= &data.x509.st_x509;
		postfix="";
		}
	else if (type == X509_LU_CRL)
		{
		data.crl.st_crl.crl= &data.crl.st_crl_info;
		data.crl.st_crl_info.issuer=name;
		stmp.data.crl= &data.crl.st_crl;
		postfix="r";
		}
	else
		{
		X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE);
		goto finish;
		}

	if ((b=BUF_MEM_new()) == NULL)
		{
		X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB);
		goto finish;
		}
	
	ctx=(BY_DIR *)xl->method_data;

	h=X509_NAME_hash(name);
	for (i=0; i<ctx->num_dirs; i++)
		{
		j=strlen(ctx->dirs[i])+1+8+6+1+1;
		if (!BUF_MEM_grow(b,j))
			{
			X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE);
			goto finish;
			}
		k=0;
		for (;;)
			{
			char c = '/';
#ifdef OPENSSL_SYS_VMS
			c = ctx->dirs[i][strlen(ctx->dirs[i])-1];
			if (c != ':' && c != '>' && c != ']')
				{
				/* If no separator is present, we assume the
				   directory specifier is a logical name, and
				   add a colon.  We really should use better
				   VMS routines for merging things like this,
				   but this will do for now...
				   -- Richard Levitte */
				c = ':';
				}
			else
				{
				c = '\0';
				}
#endif
			if (c == '\0')
				{
				/* This is special.  When c == '\0', no
				   directory separator should be added. */
				BIO_snprintf(b->data,b->max,
					"%s%08lx.%s%d",ctx->dirs[i],h,
					postfix,k);
				}
			else
				{
				BIO_snprintf(b->data,b->max,
					"%s%c%08lx.%s%d",ctx->dirs[i],c,h,
					postfix,k);
				}
			k++;
			if (stat(b->data,&st) < 0)
				break;
			/* found one. */
			if (type == X509_LU_X509)
				{
				if ((X509_load_cert_file(xl,b->data,
					ctx->dirs_type[i])) == 0)
					break;
				}
			else if (type == X509_LU_CRL)
				{
				if ((X509_load_crl_file(xl,b->data,
					ctx->dirs_type[i])) == 0)
					break;
				}
			/* else case will caught higher up */
			}

		/* we have added it to the cache so now pull
		 * it out again */
		CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
		j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp);
		if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j);
		else tmp = NULL;
		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);

		if (tmp != NULL)
			{
			ok=1;
			ret->type=tmp->type;
			memcpy(&ret->data,&tmp->data,sizeof(ret->data));
			/* If we were going to up the reference count,
			 * we would need to do it on a perl 'type'
			 * basis */
	/*		CRYPTO_add(&tmp->data.x509->references,1,
				CRYPTO_LOCK_X509);*/
			goto finish;
			}
		}
finish:
	if (b != NULL) BUF_MEM_free(b);
	return(ok);
	}
Пример #12
0
/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
 * connection. It is only called by servers.
 *
 *   ctx: contains the early callback context, which is the result of a
 *       shallow parse of the ClientHello.
 *
 * Returns:
 *   -1: error
 *    0: a session may have been found.
 *
 * Side effects:
 *   - If a session is found then s->session is pointed at it (after freeing an
 *     existing session if need be) and s->verify_result is set from the session.
 *   - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1
 *     if the server should issue a new session ticket (to 0 otherwise). */
int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) {
  /* This is used only by servers. */
  SSL_SESSION *ret = NULL;
  int fatal = 0;
  int try_session_cache = 1;
  int r;

  if (ctx->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
    goto err;
  }

  if (ctx->session_id_len == 0) {
    try_session_cache = 0;
  }

  r = tls1_process_ticket(s, ctx, &ret); /* sets s->tlsext_ticket_expected */
  switch (r) {
    case -1: /* Error during processing */
      fatal = 1;
      goto err;

    case 0:  /* No ticket found */
    case 1:  /* Zero length ticket found */
      break; /* Ok to carry on processing session id. */

    case 2:  /* Ticket found but not decrypted. */
    case 3:  /* Ticket decrypted, *ret has been set. */
      try_session_cache = 0;
      break;

    default:
      abort();
  }

  if (try_session_cache && ret == NULL &&
      !(s->initial_ctx->session_cache_mode &
        SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
    SSL_SESSION data;
    data.ssl_version = s->version;
    data.session_id_length = ctx->session_id_len;
    if (ctx->session_id_len == 0) {
      return 0;
    }
    memcpy(data.session_id, ctx->session_id, ctx->session_id_len);
    CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
    ret = SSL_SESSION_up_ref(lh_SSL_SESSION_retrieve(s->initial_ctx->sessions,
                                                     &data));
    CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
  }

  if (try_session_cache && ret == NULL &&
      s->initial_ctx->get_session_cb != NULL) {
    int copy = 1;

    ret = s->initial_ctx->get_session_cb(s, (uint8_t *)ctx->session_id,
                                         ctx->session_id_len, &copy);
    if (ret != NULL) {
      if (ret == SSL_magic_pending_session_ptr()) {
        /* This is a magic value which indicates that the callback needs to
         * unwind the stack and figure out the session asynchronously. */
        return PENDING_SESSION;
      }

      /* Increment reference count now if the session callback asks us to do so
       * (note that if the session structures returned by the callback are
       * shared between threads, it must handle the reference count itself
       * [i.e. copy == 0], or things won't be thread-safe). */
      if (copy) {
        SSL_SESSION_up_ref(ret);
      }

      /* Add the externally cached session to the internal cache as well if and
       * only if we are supposed to. */
      if (!(s->initial_ctx->session_cache_mode &
            SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
        /* The following should not return 1, otherwise, things are very
         * strange */
        SSL_CTX_add_session(s->initial_ctx, ret);
      }
    }
  }

  if (ret == NULL) {
    goto err;
  }

  /* Now ret is non-NULL and we own one of its reference counts. */

  if (ret->sid_ctx_length != s->sid_ctx_length ||
      memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) {
    /* We have the session requested by the client, but we don't want to use it
     * in this context. */
    goto err; /* treat like cache miss */
  }

  if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) {
    /* We can't be sure if this session is being used out of context, which is
     * especially important for SSL_VERIFY_PEER. The application should have
     * used SSL[_CTX]_set_session_id_context.
     *
     * For this error case, we generate an error instead of treating the event
     * like a cache miss (otherwise it would be easy for applications to
     * effectively disable the session cache by accident without anyone
     * noticing). */
    OPENSSL_PUT_ERROR(SSL, ssl_get_prev_session,
                      SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
    fatal = 1;
    goto err;
  }

  if (ret->timeout < (long)(time(NULL) - ret->time)) {
    /* timeout */
    if (try_session_cache) {
      /* session was from the cache, so remove it */
      SSL_CTX_remove_session(s->initial_ctx, ret);
    }
    goto err;
  }

  if (s->session != NULL) {
    SSL_SESSION_free(s->session);
  }
  s->session = ret;
  s->verify_result = s->session->verify_result;
  return 1;

err:
  if (ret != NULL) {
    SSL_SESSION_free(ret);
    if (!try_session_cache) {
      /* The session was from a ticket, so we should
       * issue a ticket for the new session */
      s->tlsext_ticket_expected = 1;
    }
  }
  if (fatal) {
    return -1;
  }
  return 0;
}
Пример #13
0
int ssl_get_new_session(SSL *s, int session) {
  /* This gets used by clients and servers. */

  unsigned int tmp;
  SSL_SESSION *ss = NULL;
  GEN_SESSION_CB cb = def_generate_session_id;

  if (s->mode & SSL_MODE_NO_SESSION_CREATION) {
    OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
                      SSL_R_SESSION_MAY_NOT_BE_CREATED);
    return 0;
  }

  ss = SSL_SESSION_new();
  if (ss == NULL) {
    return 0;
  }

  /* If the context has a default timeout, use it over the default. */
  if (s->initial_ctx->session_timeout != 0) {
    ss->timeout = s->initial_ctx->session_timeout;
  }

  if (s->session != NULL) {
    SSL_SESSION_free(s->session);
    s->session = NULL;
  }

  if (session) {
    if (s->version == SSL3_VERSION || s->version == TLS1_VERSION ||
        s->version == TLS1_1_VERSION || s->version == TLS1_2_VERSION ||
        s->version == DTLS1_VERSION || s->version == DTLS1_2_VERSION) {
      ss->ssl_version = s->version;
      ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
    } else {
      OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
                        SSL_R_UNSUPPORTED_SSL_VERSION);
      SSL_SESSION_free(ss);
      return 0;
    }

    /* If RFC4507 ticket use empty session ID */
    if (s->tlsext_ticket_expected) {
      ss->session_id_length = 0;
      goto sess_id_done;
    }

    /* Choose which callback will set the session ID */
    CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
    if (s->generate_session_id) {
      cb = s->generate_session_id;
    } else if (s->initial_ctx->generate_session_id) {
      cb = s->initial_ctx->generate_session_id;
    }
    CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);

    /* Choose a session ID */
    tmp = ss->session_id_length;
    if (!cb(s, ss->session_id, &tmp)) {
      /* The callback failed */
      OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
                        SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
      SSL_SESSION_free(ss);
      return 0;
    }

    /* Don't allow the callback to set the session length to zero. nor set it
     * higher than it was. */
    if (!tmp || tmp > ss->session_id_length) {
      /* The callback set an illegal length */
      OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
                        SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
      SSL_SESSION_free(ss);
      return 0;
    }

    ss->session_id_length = tmp;
    /* Finally, check for a conflict */
    if (SSL_has_matching_session_id(s, ss->session_id, ss->session_id_length)) {
      OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
                        SSL_R_SSL_SESSION_ID_CONFLICT);
      SSL_SESSION_free(ss);
      return 0;
    }

  sess_id_done:
    if (s->tlsext_hostname) {
      ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
      if (ss->tlsext_hostname == NULL) {
        OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
        SSL_SESSION_free(ss);
        return 0;
      }
    }
  } else {
    ss->session_id_length = 0;
  }

  if (s->sid_ctx_length > sizeof(ss->sid_ctx)) {
    OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
    SSL_SESSION_free(ss);
    return 0;
  }

  memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length);
  ss->sid_ctx_length = s->sid_ctx_length;
  s->session = ss;
  ss->ssl_version = s->version;
  ss->verify_result = X509_V_OK;

  return 1;
}
Пример #14
0
/*
 * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
 * connection. It is only called by servers.
 *
 *   session_id: points at the session ID in the ClientHello. This code will
 *       read past the end of this in order to parse out the session ticket
 *       extension, if any.
 *   len: the length of the session ID.
 *   limit: a pointer to the first byte after the ClientHello.
 *
 * Returns:
 *   -1: error
 *    0: a session may have been found.
 *
 * Side effects:
 *   - If a session is found then s->session is pointed at it (after freeing
 *     an existing session if need be) and s->verify_result is set from the
 *     session.
 *   - Both for new and resumed sessions, s->internal->tlsext_ticket_expected is set
 *     to 1 if the server should issue a new session ticket (to 0 otherwise).
 */
int
ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
    const unsigned char *limit)
{
	SSL_SESSION *ret = NULL;
	int fatal = 0;
	int try_session_cache = 1;
	int r;

	/* This is used only by servers. */

	if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
		goto err;

	if (len == 0)
		try_session_cache = 0;

	/* Sets s->internal->tlsext_ticket_expected. */
	r = tls1_process_ticket(s, session_id, len, limit, &ret);
	switch (r) {
	case -1: /* Error during processing */
		fatal = 1;
		goto err;
	case 0: /* No ticket found */
	case 1: /* Zero length ticket found */
		break; /* Ok to carry on processing session id. */
	case 2: /* Ticket found but not decrypted. */
	case 3: /* Ticket decrypted, *ret has been set. */
		try_session_cache = 0;
		break;
	default:
		abort();
	}

	if (try_session_cache && ret == NULL &&
	    !(s->session_ctx->internal->session_cache_mode &
	     SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
		SSL_SESSION data;
		data.ssl_version = s->version;
		data.session_id_length = len;
		memcpy(data.session_id, session_id, len);

		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
		ret = lh_SSL_SESSION_retrieve(s->session_ctx->internal->sessions, &data);
		if (ret != NULL) {
			/* Don't allow other threads to steal it. */
			CRYPTO_add(&ret->references, 1,
			    CRYPTO_LOCK_SSL_SESSION);
		}
		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);

		if (ret == NULL)
			s->session_ctx->internal->stats.sess_miss++;
	}

	if (try_session_cache && ret == NULL &&
	    s->session_ctx->internal->get_session_cb != NULL) {
		int copy = 1;

		if ((ret = s->session_ctx->internal->get_session_cb(s,
		    session_id, len, &copy))) {
			s->session_ctx->internal->stats.sess_cb_hit++;

			/*
			 * Increment reference count now if the session
			 * callback asks us to do so (note that if the session
			 * structures returned by the callback are shared
			 * between threads, it must handle the reference count
			 * itself [i.e. copy == 0], or things won't be
			 * thread-safe).
			 */
			if (copy)
				CRYPTO_add(&ret->references, 1,
				    CRYPTO_LOCK_SSL_SESSION);

			/*
			 * Add the externally cached session to the internal
			 * cache as well if and only if we are supposed to.
			 */
			if (!(s->session_ctx->internal->session_cache_mode &
			    SSL_SESS_CACHE_NO_INTERNAL_STORE))
				/*
				 * The following should not return 1,
				 * otherwise, things are very strange.
				 */
				SSL_CTX_add_session(s->session_ctx, ret);
		}
	}

	if (ret == NULL)
		goto err;

	/* Now ret is non-NULL and we own one of its reference counts. */

	if (ret->sid_ctx_length != s->sid_ctx_length ||
	    timingsafe_memcmp(ret->sid_ctx,
		s->sid_ctx, ret->sid_ctx_length) != 0) {
		/* We have the session requested by the client, but we don't
		 * want to use it in this context. */
		goto err; /* treat like cache miss */
	}

	if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) {
		/*
		 * We can't be sure if this session is being used out of
		 * context, which is especially important for SSL_VERIFY_PEER.
		 * The application should have used
		 * SSL[_CTX]_set_session_id_context.
		 *
		 * For this error case, we generate an error instead of treating
		 * the event like a cache miss (otherwise it would be easy for
		 * applications to effectively disable the session cache by
		 * accident without anyone noticing).
		 */
		SSLerror(s, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
		fatal = 1;
		goto err;
	}

	if (ret->cipher == NULL) {
		ret->cipher = ssl3_get_cipher_by_id(ret->cipher_id);
		if (ret->cipher == NULL)
			goto err;
	}

	if (ret->timeout < (time(NULL) - ret->time)) {
		/* timeout */
		s->session_ctx->internal->stats.sess_timeout++;
		if (try_session_cache) {
			/* session was from the cache, so remove it */
			SSL_CTX_remove_session(s->session_ctx, ret);
		}
		goto err;
	}

	s->session_ctx->internal->stats.sess_hit++;

	if (s->session != NULL)
		SSL_SESSION_free(s->session);
	s->session = ret;
	s->verify_result = s->session->verify_result;
	return 1;

err:
	if (ret != NULL) {
		SSL_SESSION_free(ret);
		if (!try_session_cache) {
			/*
			 * The session was from a ticket, so we should
			 * issue a ticket for the new session.
			 */
			s->internal->tlsext_ticket_expected = 1;
		}
	}
	if (fatal)
		return -1;
	else
		return 0;
}
Пример #15
0
int
ssl_get_new_session(SSL *s, int session)
{
	unsigned int tmp;
	SSL_SESSION *ss = NULL;
	GEN_SESSION_CB cb = def_generate_session_id;

	/* This gets used by clients and servers. */

	if ((ss = SSL_SESSION_new()) == NULL)
		return (0);

	/* If the context has a default timeout, use it */
	if (s->session_ctx->session_timeout == 0)
		ss->timeout = SSL_get_default_timeout(s);
	else
		ss->timeout = s->session_ctx->session_timeout;

	if (s->session != NULL) {
		SSL_SESSION_free(s->session);
		s->session = NULL;
	}

	if (session) {
		switch (s->version) {
		case TLS1_VERSION:
		case TLS1_1_VERSION:
		case TLS1_2_VERSION:
		case DTLS1_VERSION:
			ss->ssl_version = s->version;
			ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
			break;
		default:
			SSLerror(s, SSL_R_UNSUPPORTED_SSL_VERSION);
			SSL_SESSION_free(ss);
			return (0);
		}

		/* If RFC4507 ticket use empty session ID. */
		if (s->internal->tlsext_ticket_expected) {
			ss->session_id_length = 0;
			goto sess_id_done;
		}

		/* Choose which callback will set the session ID. */
		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
		if (s->internal->generate_session_id)
			cb = s->internal->generate_session_id;
		else if (s->session_ctx->internal->generate_session_id)
			cb = s->session_ctx->internal->generate_session_id;
		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);

		/* Choose a session ID. */
		tmp = ss->session_id_length;
		if (!cb(s, ss->session_id, &tmp)) {
			/* The callback failed */
			SSLerror(s, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
			SSL_SESSION_free(ss);
			return (0);
		}

		/*
		 * Don't allow the callback to set the session length to zero.
		 * nor set it higher than it was.
		 */
		if (!tmp || (tmp > ss->session_id_length)) {
			/* The callback set an illegal length */
			SSLerror(s, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
			SSL_SESSION_free(ss);
			return (0);
		}
		ss->session_id_length = tmp;

		/* Finally, check for a conflict. */
		if (SSL_has_matching_session_id(s, ss->session_id,
			ss->session_id_length)) {
			SSLerror(s, SSL_R_SSL_SESSION_ID_CONFLICT);
			SSL_SESSION_free(ss);
			return (0);
		}

sess_id_done:
		if (s->tlsext_hostname) {
			ss->tlsext_hostname = strdup(s->tlsext_hostname);
			if (ss->tlsext_hostname == NULL) {
				SSLerror(s, ERR_R_INTERNAL_ERROR);
				SSL_SESSION_free(ss);
				return 0;
			}
		}
	} else {
		ss->session_id_length = 0;
	}

	if (s->sid_ctx_length > sizeof ss->sid_ctx) {
		SSLerror(s, ERR_R_INTERNAL_ERROR);
		SSL_SESSION_free(ss);
		return 0;
	}

	memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length);
	ss->sid_ctx_length = s->sid_ctx_length;
	s->session = ss;
	ss->ssl_version = s->version;
	ss->verify_result = X509_V_OK;

	return (1);
}
Пример #16
0
static int
ldaplookup_by_subject(
	X509_LOOKUP *ctx,
	int          type,
	X509_NAME   *name,
	X509_OBJECT *ret
) {
	int count = 0;
	ldaphost *lh;
	const char *attrs[2];
	char *filter = NULL;


	if (ctx == NULL) return(0);
	if (name == NULL) return(0);

	lh = (ldaphost*) ctx->method_data;
	if (lh == NULL) return(0);

	switch(type) {
	case X509_LU_X509: {
		attrs[0] = ATTR_CACERT;
		} break;
	case X509_LU_CRL: {
		attrs[0] = ATTR_CACRL;
		} break;
	default: {
		X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_WRONG_LOOKUP_TYPE);
		goto done;
		}
	}
	attrs[1] = NULL;

	filter = ldaplookup_filter(name, attrs[0]);
	if (filter == NULL) {
		X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_GET_FILTER);
		goto done;
	}
#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: filter=%s\n", filter);
#endif

	for (; lh != NULL; lh = lh->next) {
		LDAPMessage *res = NULL;
		int result;

#ifdef TRACE_BY_LDAP
{
int version = -1;

ldap_get_option(lh->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject:"
" bind to \"%s://%s:%d\""
" using ldap v%d protocol\n"
, lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port
, version
);
}
#endif

		result = ldaplookup_bind_s(lh->ld);
		if (result != LDAP_SUCCESS) {
			X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_BIND);
			{
				char	buf[1024];
				snprintf(buf, sizeof(buf),
					" url=\"%s://%s:%d\""
					" ldaperror=0x%x(%.256s)"
					, lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port
					, result, ldap_err2string(result)
				);
				ERR_add_error_data(1, buf);
			}
			continue;
		}

		result = ldaplookup_search_s(lh->ld, lh->ldapurl->lud_dn,
				LDAP_SCOPE_SUBTREE, filter, (char**)attrs, 0, &res);
		if (result != LDAP_SUCCESS) {
			X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_SEARCH_FAIL);
			ldap_msgfree(res);
			continue;
		}

		result = ldaplookup_result2store(type, name, lh->ld, res, ctx->store_ctx);
		if (result > 0) count += result;

		ldap_msgfree(res);

		/*do not call ldap_unbind_s*/
	}

#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: count=%d\n", count);
#endif
	if (count > 0) {
		/*
		 * we have added at least one to the cache so now pull one out again
		 */
		union {
			struct {
				X509_CINF st_x509_cinf;
				X509 st_x509;
			} x509;
			struct {
				X509_CRL_INFO st_crl_info;
				X509_CRL st_crl;
			} crl;
		} data;

		X509_OBJECT stmp, *tmp;
		int k;

		memset(&data, 0, sizeof(data));
		stmp.type = type;
		switch(type) {
		case X509_LU_X509: {
			data.x509.st_x509_cinf.subject = name;
			data.x509.st_x509.cert_info = &data.x509.st_x509_cinf;
			stmp.data.x509 = &data.x509.st_x509;
			} break;
		case X509_LU_CRL: {
			data.crl.st_crl_info.issuer = name;
			data.crl.st_crl.crl = &data.crl.st_crl_info;
			stmp.data.crl = &data.crl.st_crl;
			} break;
		default:
			count = 0;
			goto done;
		}

		CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
		k = sk_X509_OBJECT_find(ctx->store_ctx->objs, &stmp);
		if (k >= 0)
			tmp = sk_X509_OBJECT_value(ctx->store_ctx->objs, k);
		else
			tmp = NULL;
		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: k=%d, tmp=%p\n", k, (void*)tmp);
#endif

		if (tmp == NULL) {
			count = 0;
			goto done;
		}

		ret->type = tmp->type;
		memcpy(&ret->data, &tmp->data, sizeof(ret->data));
	}

done:
	if (filter != NULL) OPENSSL_free(filter);
	return(count > 0);
}