Exemple #1
0
/* Parse the server's renegotiation binding and abort if it's not
   right */
int
ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len,
    int *al)
{
	int expected_len = s->s3->previous_client_finished_len +
	    s->s3->previous_server_finished_len;
	int ilen;

	/* Check for logic errors */
	OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len);
	OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len);

	/* Parse the length byte */
	if (len < 1) {
		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_ENCODING_ERR);
		*al = SSL_AD_ILLEGAL_PARAMETER;
		return 0;
	}
	ilen = *d;
	d++;

	/* Consistency check */
	if (ilen + 1 != len) {
		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_ENCODING_ERR);
		*al = SSL_AD_ILLEGAL_PARAMETER;
		return 0;
	}

	/* Check that the extension matches */
	if (ilen != expected_len) {
		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_MISMATCH);
		*al = SSL_AD_HANDSHAKE_FAILURE;
		return 0;
	}

	if (timingsafe_memcmp(d, s->s3->previous_client_finished,
	    s->s3->previous_client_finished_len) != 0) {
		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_MISMATCH);
		*al = SSL_AD_HANDSHAKE_FAILURE;
		return 0;
	}
	d += s->s3->previous_client_finished_len;

	if (timingsafe_memcmp(d, s->s3->previous_server_finished,
	    s->s3->previous_server_finished_len)) {
		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_MISMATCH);
		*al = SSL_AD_ILLEGAL_PARAMETER;
		return 0;
	}

	s->s3->send_connection_binding = 1;

	return 1;
}
Exemple #2
0
int test_memcmp() {
  size_t i;
  struct timespec x,y;
  long diff[4];

  memset(a,23,sizeof(a));
  memset(b,23,sizeof(b));
  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(timingsafe_memcmp(a,b,sizeof(a))==0);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[0]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("timingsafe_memcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[0]);

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(memcmp(a,b,sizeof(a))==0);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[1]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("   regular memcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[1]);

  a[10]=24;	// now give memcmp an opportunity to exit early

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(timingsafe_memcmp(a,b,sizeof(a))==1);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[2]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("timingsafe_memcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[2]);

  assert(clock_gettime(CLOCK_MONOTONIC,&x)==0);
  for (i=0; i<100000; ++i) {
    assert(memcmp(a,b,sizeof(a))==1);
  }
  assert(clock_gettime(CLOCK_MONOTONIC,&y)==0);
  diff[3]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec;
  printf("   regular memcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[3]);

  /* we expect the timingsafe_memcmp values to be roughly the same (+- 10% for measurement inaccuracies) */
  long delta=diff[0]-diff[2];
  if (delta<0) delta=-delta;
  assert(delta*10<diff[0]);
}
Exemple #3
0
static int
aead_aes_gcm_open(const EVP_AEAD_CTX *ctx, unsigned char *out, size_t *out_len,
    size_t max_out_len, const unsigned char *nonce, size_t nonce_len,
    const unsigned char *in, size_t in_len, const unsigned char *ad,
    size_t ad_len)
{
	const struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state;
	unsigned char tag[EVP_AEAD_AES_GCM_TAG_LEN];
	GCM128_CONTEXT gcm;
	size_t plaintext_len;
	size_t bulk = 0;

	if (in_len < gcm_ctx->tag_len) {
		EVPerr(EVP_F_AEAD_AES_GCM_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	plaintext_len = in_len - gcm_ctx->tag_len;

	if (max_out_len < plaintext_len) {
		EVPerr(EVP_F_AEAD_AES_GCM_OPEN, EVP_R_BUFFER_TOO_SMALL);
		return 0;
	}

	memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm));
	CRYPTO_gcm128_setiv(&gcm, nonce, nonce_len);

	if (CRYPTO_gcm128_aad(&gcm, ad, ad_len))
		return 0;

	if (gcm_ctx->ctr) {
		if (CRYPTO_gcm128_decrypt_ctr32(&gcm, in + bulk, out + bulk,
		    in_len - bulk - gcm_ctx->tag_len, gcm_ctx->ctr))
			return 0;
	} else {
		if (CRYPTO_gcm128_decrypt(&gcm, in + bulk, out + bulk,
		    in_len - bulk - gcm_ctx->tag_len))
			return 0;
	}

	CRYPTO_gcm128_tag(&gcm, tag, gcm_ctx->tag_len);
	if (timingsafe_memcmp(tag, in + plaintext_len, gcm_ctx->tag_len) != 0) {
		EVPerr(EVP_F_AEAD_AES_GCM_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	*out_len = plaintext_len;

	return 1;
}
Exemple #4
0
/* Parse the client's renegotiation binding and abort if it's not
   right */
int
ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
    int *al)
{
	int ilen;

	/* Parse the length byte */
	if (len < 1) {
		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_ENCODING_ERR);
		*al = SSL_AD_ILLEGAL_PARAMETER;
		return 0;
	}
	ilen = *d;
	d++;

	/* Consistency check */
	if ((ilen + 1) != len) {
		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_ENCODING_ERR);
		*al = SSL_AD_ILLEGAL_PARAMETER;
		return 0;
	}

	/* Check that the extension matches */
	if (ilen != s->s3->previous_client_finished_len) {
		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_MISMATCH);
		*al = SSL_AD_HANDSHAKE_FAILURE;
		return 0;
	}

	if (timingsafe_memcmp(d, s->s3->previous_client_finished,
	    s->s3->previous_client_finished_len) != 0) {
		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
		    SSL_R_RENEGOTIATION_MISMATCH);
		*al = SSL_AD_HANDSHAKE_FAILURE;
		return 0;
	}


	s->s3->send_connection_binding = 1;

	return 1;
}
Exemple #5
0
/* tls_decrypt_ticket attempts to decrypt a session ticket.
 *
 *   etick: points to the body of the session ticket extension.
 *   eticklen: the length of the session tickets extenion.
 *   sess_id: points at the session ID.
 *   sesslen: the length of the session ID.
 *   psess: (output) on return, if a ticket was decrypted, then this is set to
 *       point to the resulting session.
 *
 * Returns:
 *   -1: fatal error, either from parsing or decrypting the ticket.
 *    2: the ticket couldn't be decrypted.
 *    3: a ticket was successfully decrypted and *psess was set.
 *    4: same as 3, but the ticket needs to be renewed.
 */
static int
tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
    const unsigned char *sess_id, int sesslen, SSL_SESSION **psess)
{
	SSL_SESSION *sess;
	unsigned char *sdec;
	const unsigned char *p;
	int slen, mlen, renew_ticket = 0;
	unsigned char tick_hmac[EVP_MAX_MD_SIZE];
	HMAC_CTX hctx;
	EVP_CIPHER_CTX ctx;
	SSL_CTX *tctx = s->initial_ctx;

	/*
	 * The API guarantees EVP_MAX_IV_LENGTH bytes of space for
	 * the iv to tlsext_ticket_key_cb().  Since the total space
	 * required for a session cookie is never less than this,
	 * this check isn't too strict.  The exact check comes later.
	 */
	if (eticklen < 16 + EVP_MAX_IV_LENGTH)
		return 2;

	/* Initialize session ticket encryption and HMAC contexts */
	HMAC_CTX_init(&hctx);
	EVP_CIPHER_CTX_init(&ctx);
	if (tctx->internal->tlsext_ticket_key_cb) {
		unsigned char *nctick = (unsigned char *)etick;
		int rv = tctx->internal->tlsext_ticket_key_cb(s,
		    nctick, nctick + 16, &ctx, &hctx, 0);
		if (rv < 0) {
			HMAC_CTX_cleanup(&hctx);
			EVP_CIPHER_CTX_cleanup(&ctx);
			return -1;
		}
		if (rv == 0) {
			HMAC_CTX_cleanup(&hctx);
			EVP_CIPHER_CTX_cleanup(&ctx);
			return 2;
		}
		if (rv == 2)
			renew_ticket = 1;
	} else {
		/* Check key name matches */
		if (timingsafe_memcmp(etick,
		    tctx->internal->tlsext_tick_key_name, 16))
			return 2;
		HMAC_Init_ex(&hctx, tctx->internal->tlsext_tick_hmac_key,
		    16, tlsext_tick_md(), NULL);
		EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
		    tctx->internal->tlsext_tick_aes_key, etick + 16);
	}

	/*
	 * Attempt to process session ticket, first conduct sanity and
	 * integrity checks on ticket.
	 */
	mlen = HMAC_size(&hctx);
	if (mlen < 0) {
		HMAC_CTX_cleanup(&hctx);
		EVP_CIPHER_CTX_cleanup(&ctx);
		return -1;
	}

	/* Sanity check ticket length: must exceed keyname + IV + HMAC */
	if (eticklen <= 16 + EVP_CIPHER_CTX_iv_length(&ctx) + mlen) {
		HMAC_CTX_cleanup(&hctx);
		EVP_CIPHER_CTX_cleanup(&ctx);
		return 2;
	}
	eticklen -= mlen;

	/* Check HMAC of encrypted ticket */
	if (HMAC_Update(&hctx, etick, eticklen) <= 0 ||
	    HMAC_Final(&hctx, tick_hmac, NULL) <= 0) {
		HMAC_CTX_cleanup(&hctx);
		EVP_CIPHER_CTX_cleanup(&ctx);
		return -1;
	}

	HMAC_CTX_cleanup(&hctx);
	if (timingsafe_memcmp(tick_hmac, etick + eticklen, mlen)) {
		EVP_CIPHER_CTX_cleanup(&ctx);
		return 2;
	}

	/* Attempt to decrypt session data */
	/* Move p after IV to start of encrypted ticket, update length */
	p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
	eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
	sdec = malloc(eticklen);
	if (sdec == NULL ||
	    EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen) <= 0) {
		free(sdec);
		EVP_CIPHER_CTX_cleanup(&ctx);
		return -1;
	}
	if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0) {
		free(sdec);
		EVP_CIPHER_CTX_cleanup(&ctx);
		return 2;
	}
	slen += mlen;
	EVP_CIPHER_CTX_cleanup(&ctx);
	p = sdec;

	sess = d2i_SSL_SESSION(NULL, &p, slen);
	free(sdec);
	if (sess) {
		/* The session ID, if non-empty, is used by some clients to
		 * detect that the ticket has been accepted. So we copy it to
		 * the session structure. If it is empty set length to zero
		 * as required by standard.
		 */
		if (sesslen)
			memcpy(sess->session_id, sess_id, sesslen);
		sess->session_id_length = sesslen;
		*psess = sess;
		if (renew_ticket)
			return 4;
		else
			return 3;
	}
	ERR_clear_error();
	/* For session parse failure, indicate that we need to send a new
	 * ticket. */
	return 2;
}
/**
 * Timing-safe version of memcmp.  As memcmp, compare the <b>sz</b> bytes at
 * <b>a</b> with the <b>sz</b> bytes at <b>b</b>, and return less than 0 if
 * the bytes at <b>a</b> lexically precede those at <b>b</b>, 0 if the byte
 * ranges are equal, and greater than zero if the bytes at <b>a</b> lexically
 * follow those at <b>b</b>.
 *
 * This implementation differs from memcmp in that its timing behavior is not
 * data-dependent: it should return in the same amount of time regardless of
 * the contents of <b>a</b> and <b>b</b>.
 */
int
tor_memcmp(const void *a, const void *b, size_t len)
{
#ifdef HAVE_TIMINGSAFE_MEMCMP
  return timingsafe_memcmp(a, b, len);
#else
  const uint8_t *x = a;
  const uint8_t *y = b;
  size_t i = len;
  int retval = 0;

  /* This loop goes from the end of the arrays to the start.  At the
   * start of every iteration, before we decrement i, we have set
   * "retval" equal to the result of memcmp(a+i,b+i,len-i).  During the
   * loop, we update retval by leaving it unchanged if x[i]==y[i] and
   * setting it to x[i]-y[i] if x[i]!= y[i].
   *
   * The following assumes we are on a system with two's-complement
   * arithmetic.  We check for this at configure-time with the check
   * that sets USING_TWOS_COMPLEMENT.  If we aren't two's complement, then
   * torint.h will stop compilation with an error.
   */
  while (i--) {
    int v1 = x[i];
    int v2 = y[i];
    int equal_p = v1 ^ v2;

    /* The following sets bits 8 and above of equal_p to 'equal_p ==
     * 0', and thus to v1 == v2.  (To see this, note that if v1 ==
     * v2, then v1^v2 == equal_p == 0, so equal_p-1 == -1, which is the
     * same as ~0 on a two's-complement machine.  Then note that if
     * v1 != v2, then 0 < v1 ^ v2 < 256, so 0 <= equal_p - 1 < 255.)
     */
    --equal_p;

    equal_p >>= 8;
    /* Thanks to (sign-preserving) arithmetic shift, equal_p is now
     * equal to -(v1 == v2), which is exactly what we need below.
     * (Since we're assuming two's-complement arithmetic, -1 is the
     * same as ~0 (all bits set).)
     *
     * (The result of an arithmetic shift on a negative value is
     * actually implementation-defined in standard C.  So how do we
     * get away with assuming it?  Easy.  We check.) */
#if ((-60 >> 8) != -1)
#error "According to cpp, right-shift doesn't perform sign-extension."
#endif
#ifndef RSHIFT_DOES_SIGN_EXTEND
#error "According to configure, right-shift doesn't perform sign-extension."
#endif

    /* If v1 == v2, equal_p is ~0, so this will leave retval
     * unchanged; otherwise, equal_p is 0, so this will zero it. */
    retval &= equal_p;

    /* If v1 == v2, then this adds 0, and leaves retval unchanged.
     * Otherwise, we just zeroed retval, so this sets it to v1 - v2. */
    retval += (v1 - v2);

    /* There.  Now retval is equal to its previous value if v1 == v2, and
     * equal to v1 - v2 if v1 != v2. */
  }

  return retval;
#endif /* timingsafe_memcmp */
}
Exemple #7
0
static int
aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
    size_t *out_len, size_t max_out_len, const unsigned char *nonce,
    size_t nonce_len, const unsigned char *in, size_t in_len,
    const unsigned char *ad, size_t ad_len)
{
	const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
	unsigned char mac[POLY1305_TAG_LEN];
	unsigned char poly1305_key[32];
	const unsigned char *iv = nonce;
	poly1305_state poly1305;
	const uint64_t in_len_64 = in_len;
	size_t plaintext_len;
	uint64_t ctr = 0;

	if (in_len < c20_ctx->tag_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	/* The underlying ChaCha implementation may not overflow the block
	 * counter into the second counter word. Therefore we disallow
	 * individual operations that work on more than 2TB at a time.
	 * in_len_64 is needed because, on 32-bit platforms, size_t is only
	 * 32-bits and this produces a warning because it's always false.
	 * Casting to uint64_t inside the conditional is not sufficient to stop
	 * the warning. */
	if (in_len_64 >= (1ULL << 32) * 64 - 64) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_TOO_LARGE);
		return 0;
	}

	if (nonce_len != ctx->aead->nonce_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE);
		return 0;
	}

	plaintext_len = in_len - c20_ctx->tag_len;

	if (max_out_len < plaintext_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN,
		    EVP_R_BUFFER_TOO_SMALL);
		return 0;
	}

	if (nonce_len == CHACHA20_NONCE_LEN_OLD) {
		/* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */

		memset(poly1305_key, 0, sizeof(poly1305_key));
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
		    sizeof(poly1305_key), c20_ctx->key, nonce, 0);

		CRYPTO_poly1305_init(&poly1305, poly1305_key);
		poly1305_update_with_length(&poly1305, ad, ad_len);
		poly1305_update_with_length(&poly1305, in, plaintext_len);
	} else if (nonce_len == CHACHA20_NONCE_LEN) {
		/* RFC 7539, May 2015 */

		ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
		    nonce[2] << 16 | nonce[3] << 24) << 32;
		iv = nonce + CHACHA20_CONSTANT_LEN;

		memset(poly1305_key, 0, sizeof(poly1305_key));
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
		    sizeof(poly1305_key), c20_ctx->key, iv, ctr);

		CRYPTO_poly1305_init(&poly1305, poly1305_key);
		poly1305_update_with_pad16(&poly1305, ad, ad_len);
		poly1305_update_with_pad16(&poly1305, in, plaintext_len);
		poly1305_update_with_length(&poly1305, NULL, ad_len);
		poly1305_update_with_length(&poly1305, NULL, plaintext_len);
	}

	CRYPTO_poly1305_finish(&poly1305, mac);

	if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1);
	*out_len = plaintext_len;
	return 1;
}
Exemple #8
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;
}