コード例 #1
0
ファイル: ssl.c プロジェクト: witchu/lua-openssl
static int openssl_ssl_ctx_sessions(lua_State*L)
{
  SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
  if (lua_isstring(L, 2))
  {
    size_t s;
    unsigned char* sid_ctx = (unsigned char*)luaL_checklstring(L, 2, &s);
    int ret = SSL_CTX_set_session_id_context(ctx, sid_ctx, s);
    lua_pushboolean(L, ret);
    return 1;
  }
  else
  {
    SSL_SESSION *s = CHECK_OBJECT(2, SSL_SESSION, "openssl.ssl_session");
    int add = 1;
    if (!lua_isnoneornil(L, 3))
      add = auxiliar_checkboolean(L, 3);

    if (add)
      add = SSL_CTX_add_session(ctx, s);
    else
      add = SSL_CTX_remove_session(ctx, s);

    lua_pushboolean(L, add);
    return 1;
  }
}
コード例 #2
0
ファイル: myssl.c プロジェクト: tkrajcar/pypenn
void
ssl_read_session(FILE * fp)
{
  SSL_SESSION s;
  PEM_read_SSL_SESSION(fp, &s, NULL, NULL);
  SSL_CTX_add_session(ctx, &s);
}
コード例 #3
0
ファイル: ossl_ssl.c プロジェクト: 2220142/ruby
/*
 *  call-seq:
 *     ctx.session_add(session) -> true | false
 *
 */
static VALUE
ossl_sslctx_session_add(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;
    SSL_SESSION *sess;

    Data_Get_Struct(self, SSL_CTX, ctx);
    SafeGetSSLSession(arg, sess);

    return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
}
コード例 #4
0
/* ssl_lookup_session looks up |session_id| in the session cache and sets
 * |*out_session| to an |SSL_SESSION| object if found. The caller takes
 * ownership of the result. */
static enum ssl_session_result_t ssl_lookup_session(
    SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id,
    size_t session_id_len) {
  *out_session = NULL;

  if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
    return ssl_session_success;
  }

  SSL_SESSION *session;
  /* Try the internal cache, if it exists. */
  if (!(ssl->initial_ctx->session_cache_mode &
        SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
    SSL_SESSION data;
    data.ssl_version = ssl->version;
    data.session_id_length = session_id_len;
    memcpy(data.session_id, session_id, session_id_len);

    CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock);
    session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data);
    if (session != NULL) {
      SSL_SESSION_up_ref(session);
    }
    /* TODO(davidben): This should probably move it to the front of the list. */
    CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock);

    if (session != NULL) {
      *out_session = session;
      return ssl_session_success;
    }
  }

  /* Fall back to the external cache, if it exists. */
  if (ssl->initial_ctx->get_session_cb == NULL) {
    return ssl_session_success;
  }
  int copy = 1;
  session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id,
                                             session_id_len, &copy);
  if (session == NULL) {
    return ssl_session_success;
  }
  if (session == SSL_magic_pending_session_ptr()) {
    return ssl_session_retry;
  }

  /* 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(session);
  }

  /* Add the externally cached session to the internal cache if necessary. */
  if (!(ssl->initial_ctx->session_cache_mode &
        SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
    SSL_CTX_add_session(ssl->initial_ctx, session);
  }

  *out_session = session;
  return ssl_session_success;
}
コード例 #5
0
ファイル: handshake_helper.c プロジェクト: Beatzevo/openssl
static HANDSHAKE_RESULT *do_handshake_internal(
    SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx,
    const SSL_TEST_CTX *test_ctx, SSL_SESSION *session_in,
    SSL_SESSION **session_out)
{
    SSL *server, *client;
    BIO *client_to_server, *server_to_client;
    HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
    CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
    HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
    int client_turn = 1, shutdown = 0;
    peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY;
    handshake_status_t status = HANDSHAKE_RETRY;
    unsigned char* tick = NULL;
    size_t tick_len = 0;
    SSL_SESSION* sess = NULL;
    const unsigned char *proto = NULL;
    /* API dictates unsigned int rather than size_t. */
    unsigned int proto_len = 0;

    memset(&server_ctx_data, 0, sizeof(server_ctx_data));
    memset(&server2_ctx_data, 0, sizeof(server2_ctx_data));
    memset(&client_ctx_data, 0, sizeof(client_ctx_data));

    configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx,
                            &server_ctx_data, &server2_ctx_data, &client_ctx_data);

    server = SSL_new(server_ctx);
    client = SSL_new(client_ctx);
    OPENSSL_assert(server != NULL && client != NULL);

    configure_handshake_ssl(server, client, test_ctx);
    if (session_in != NULL) {
        /* In case we're testing resumption without tickets. */
        OPENSSL_assert(SSL_CTX_add_session(server_ctx, session_in));
        OPENSSL_assert(SSL_set_session(client, session_in));
    }

    memset(&server_ex_data, 0, sizeof(server_ex_data));
    memset(&client_ex_data, 0, sizeof(client_ex_data));

    ret->result = SSL_TEST_INTERNAL_ERROR;

    client_to_server = BIO_new(BIO_s_mem());
    server_to_client = BIO_new(BIO_s_mem());

    OPENSSL_assert(client_to_server != NULL && server_to_client != NULL);

    /* Non-blocking bio. */
    BIO_set_nbio(client_to_server, 1);
    BIO_set_nbio(server_to_client, 1);

    SSL_set_connect_state(client);
    SSL_set_accept_state(server);

    /* The bios are now owned by the SSL object. */
    SSL_set_bio(client, server_to_client, client_to_server);
    OPENSSL_assert(BIO_up_ref(server_to_client) > 0);
    OPENSSL_assert(BIO_up_ref(client_to_server) > 0);
    SSL_set_bio(server, client_to_server, server_to_client);

    ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL);
    OPENSSL_assert(ex_data_idx >= 0);

    OPENSSL_assert(SSL_set_ex_data(server, ex_data_idx,
                                   &server_ex_data) == 1);
    OPENSSL_assert(SSL_set_ex_data(client, ex_data_idx,
                                   &client_ex_data) == 1);

    SSL_set_info_callback(server, &info_cb);
    SSL_set_info_callback(client, &info_cb);

    /*
     * Half-duplex handshake loop.
     * Client and server speak to each other synchronously in the same process.
     * We use non-blocking BIOs, so whenever one peer blocks for read, it
     * returns PEER_RETRY to indicate that it's the other peer's turn to write.
     * The handshake succeeds once both peers have succeeded. If one peer
     * errors out, we also let the other peer retry (and presumably fail).
     */
    for(;;) {
        if (client_turn) {
            client_status = do_handshake_step(client, shutdown);
            status = handshake_status(client_status, server_status,
                                      1 /* client went last */);
        } else {
            server_status = do_handshake_step(server, shutdown);
            status = handshake_status(server_status, client_status,
                                      0 /* server went last */);
        }

        switch (status) {
        case HANDSHAKE_SUCCESS:
            if (shutdown) {
                ret->result = SSL_TEST_SUCCESS;
                goto err;
            } else {
                client_status = server_status = PEER_RETRY;
                shutdown = 1;
                client_turn = 1;
                break;
            }
        case CLIENT_ERROR:
            ret->result = SSL_TEST_CLIENT_FAIL;
            goto err;
        case SERVER_ERROR:
            ret->result = SSL_TEST_SERVER_FAIL;
            goto err;
        case INTERNAL_ERROR:
            ret->result = SSL_TEST_INTERNAL_ERROR;
            goto err;
        case HANDSHAKE_RETRY:
            /* Continue. */
            client_turn ^= 1;
            break;
        }
    }
 err:
    ret->server_alert_sent = server_ex_data.alert_sent;
    ret->server_alert_received = client_ex_data.alert_received;
    ret->client_alert_sent = client_ex_data.alert_sent;
    ret->client_alert_received = server_ex_data.alert_received;
    ret->server_protocol = SSL_version(server);
    ret->client_protocol = SSL_version(client);
    ret->servername = server_ex_data.servername;
    if ((sess = SSL_get0_session(client)) != NULL)
        SSL_SESSION_get0_ticket(sess, &tick, &tick_len);
    if (tick == NULL || tick_len == 0)
        ret->session_ticket = SSL_TEST_SESSION_TICKET_NO;
    else
        ret->session_ticket = SSL_TEST_SESSION_TICKET_YES;
    ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call;

    SSL_get0_next_proto_negotiated(client, &proto, &proto_len);
    ret->client_npn_negotiated = dup_str(proto, proto_len);

    SSL_get0_next_proto_negotiated(server, &proto, &proto_len);
    ret->server_npn_negotiated = dup_str(proto, proto_len);

    SSL_get0_alpn_selected(client, &proto, &proto_len);
    ret->client_alpn_negotiated = dup_str(proto, proto_len);

    SSL_get0_alpn_selected(server, &proto, &proto_len);
    ret->server_alpn_negotiated = dup_str(proto, proto_len);

    ret->client_resumed = SSL_session_reused(client);
    ret->server_resumed = SSL_session_reused(server);

    if (session_out != NULL)
        *session_out = SSL_get1_session(client);

    ctx_data_free_data(&server_ctx_data);
    ctx_data_free_data(&server2_ctx_data);
    ctx_data_free_data(&client_ctx_data);

    SSL_free(server);
    SSL_free(client);
    return ret;
}
コード例 #6
0
static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
{
    SSL_CTX *sctx = NULL, *cctx = NULL;
    SSL *serverssl1 = NULL, *clientssl1 = NULL;
    SSL *serverssl2 = NULL, *clientssl2 = NULL;
#ifndef OPENSSL_NO_TLS1_1
    SSL *serverssl3 = NULL, *clientssl3 = NULL;
#endif
    SSL_SESSION *sess1 = NULL, *sess2 = NULL;
    int testresult = 0;

    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
                             &cctx, cert, privkey)) {
        printf("Unable to create SSL_CTX pair\n");
        return 0;
    }

#ifndef OPENSSL_NO_TLS1_2
    /* Only allow TLS1.2 so we can force a connection failure later */
    SSL_CTX_set_min_proto_version(cctx, TLS1_2_VERSION);
#endif

    /* Set up session cache */
    if (fix.use_ext_cache) {
        SSL_CTX_sess_set_new_cb(cctx, new_session_cb);
        SSL_CTX_sess_set_remove_cb(cctx, remove_session_cb);
    }
    if (fix.use_int_cache) {
        /* Also covers instance where both are set */
        SSL_CTX_set_session_cache_mode(cctx, SSL_SESS_CACHE_CLIENT);
    } else {
        SSL_CTX_set_session_cache_mode(cctx,
                                       SSL_SESS_CACHE_CLIENT
                                       | SSL_SESS_CACHE_NO_INTERNAL_STORE);
    }

    if (!create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL,
                               NULL)) {
        printf("Unable to create SSL objects\n");
        goto end;
    }

    if (!create_ssl_connection(serverssl1, clientssl1)) {
        printf("Unable to create SSL connection\n");
        goto end;
    }
    sess1 = SSL_get1_session(clientssl1);
    if (sess1 == NULL) {
        printf("Unexpected NULL session\n");
        goto end;
    }

    if (fix.use_int_cache && SSL_CTX_add_session(cctx, sess1)) {
        /* Should have failed because it should already be in the cache */
        printf("Unexpected success adding session to cache\n");
        goto end;
    }

    if (fix.use_ext_cache && (new_called != 1 || remove_called != 0)) {
        printf("Session not added to cache\n");
        goto end;
    }

    if (!create_ssl_objects(sctx, cctx, &serverssl2, &clientssl2, NULL, NULL)) {
        printf("Unable to create second SSL objects\n");
        goto end;
    }

    if (!create_ssl_connection(serverssl2, clientssl2)) {
        printf("Unable to create second SSL connection\n");
        goto end;
    }

    sess2 = SSL_get1_session(clientssl2);
    if (sess2 == NULL) {
        printf("Unexpected NULL session from clientssl2\n");
        goto end;
    }

    if (fix.use_ext_cache && (new_called != 2 || remove_called != 0)) {
        printf("Remove session callback unexpectedly called\n");
        goto end;
    }

    /*
     * This should clear sess2 from the cache because it is a "bad" session. See
     * SSL_set_session() documentation.
     */
    if (!SSL_set_session(clientssl2, sess1)) {
        printf("Unexpected failure setting session\n");
        goto end;
    }

    if (fix.use_ext_cache && (new_called != 2 || remove_called != 1)) {
        printf("Failed to call callback to remove session\n");
        goto end;
    }


    if (SSL_get_session(clientssl2) != sess1) {
        printf("Unexpected session found\n");
        goto end;
    }

    if (fix.use_int_cache) {
        if (!SSL_CTX_add_session(cctx, sess2)) {
            /*
             * Should have succeeded because it should not already be in the cache
             */
            printf("Unexpected failure adding session to cache\n");
            goto end;
        }

        if (!SSL_CTX_remove_session(cctx, sess2)) {
            printf("Unexpected failure removing session from cache\n");
            goto end;
        }

        /* This is for the purposes of internal cache testing...ignore the
         * counter for external cache
         */
        if (fix.use_ext_cache)
            remove_called--;
    }

    /* This shouldn't be in the cache so should fail */
    if (SSL_CTX_remove_session(cctx, sess2)) {
        printf("Unexpected success removing session from cache\n");
        goto end;
    }

    if (fix.use_ext_cache && (new_called != 2 || remove_called != 2)) {
        printf("Failed to call callback to remove session #2\n");
        goto end;
    }

#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_2)
    /* Force a connection failure */
    SSL_CTX_set_max_proto_version(sctx, TLS1_1_VERSION);

    if (!create_ssl_objects(sctx, cctx, &serverssl3, &clientssl3, NULL, NULL)) {
        printf("Unable to create third SSL objects\n");
        goto end;
    }

    if (!SSL_set_session(clientssl3, sess1)) {
        printf("Unable to set session for third connection\n");
        goto end;
    }

    /* This should fail because of the mismatched protocol versions */
    if (create_ssl_connection(serverssl3, clientssl3)) {
        printf("Unable to create third SSL connection\n");
        goto end;
    }


    /* We should have automatically removed the session from the cache */
    if (fix.use_ext_cache && (new_called != 2 || remove_called != 3)) {
        printf("Failed to call callback to remove session #2\n");
        goto end;
    }

    if (fix.use_int_cache && !SSL_CTX_add_session(cctx, sess2)) {
        /*
         * Should have succeeded because it should not already be in the cache
         */
        printf("Unexpected failure adding session to cache #2\n");
        goto end;
    }
#endif

    testresult = 1;

 end:
    SSL_free(serverssl1);
    SSL_free(clientssl1);
    SSL_free(serverssl2);
    SSL_free(clientssl2);
#ifndef OPENSSL_NO_TLS1_1
    SSL_free(serverssl3);
    SSL_free(clientssl3);
#endif
    SSL_SESSION_free(sess1);
    SSL_SESSION_free(sess2);
    /*
     * Check if we need to remove any sessions up-refed for the external cache
     */
    if (new_called >= 1)
        SSL_SESSION_free(sess1);
    if (new_called >= 2)
        SSL_SESSION_free(sess2);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}
コード例 #7
0
ファイル: ssl_sess.c プロジェクト: friends110110/boringssl
/* 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;
}
コード例 #8
0
ファイル: ssl_sess.c プロジェクト: infinityhacks/openssl
/*-
 * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
 * connection. It is only called by servers.
 *
 *   hello: The parsed ClientHello data
 *
 * Returns:
 *   -1: fatal error
 *    0: no session found
 *    1: 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->ext.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, CLIENTHELLO_MSG *hello, int *al)
{
    /* This is used only by servers. */

    SSL_SESSION *ret = NULL;
    int fatal = 0;
    int try_session_cache = 0;
    TICKET_RETURN r;

    if (SSL_IS_TLS13(s)) {
        if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes,
                                 SSL_EXT_CLIENT_HELLO, hello->pre_proc_exts,
                                 NULL, 0, al)
                || !tls_parse_extension(s, TLSEXT_IDX_psk, SSL_EXT_CLIENT_HELLO,
                                        hello->pre_proc_exts, NULL, 0, al))
            return -1;

        ret = s->session;
    } else {
        /* sets s->ext.ticket_expected */
        r = tls_get_ticket_from_client(s, hello, &ret);
        switch (r) {
        case TICKET_FATAL_ERR_MALLOC:
        case TICKET_FATAL_ERR_OTHER:
            fatal = 1;
            goto err;
        case TICKET_NONE:
        case TICKET_EMPTY:
            try_session_cache = 1;
            break;
        case TICKET_NO_DECRYPT:
        case TICKET_SUCCESS:
        case TICKET_SUCCESS_RENEW:
            break;
        }
    }

    if (try_session_cache &&
        ret == NULL &&
        !(s->session_ctx->session_cache_mode &
          SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
        SSL_SESSION data;

        data.ssl_version = s->version;
        memcpy(data.session_id, hello->session_id, hello->session_id_len);
        data.session_id_length = hello->session_id_len;

        CRYPTO_THREAD_read_lock(s->session_ctx->lock);
        ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data);
        if (ret != NULL) {
            /* don't allow other threads to steal it: */
            SSL_SESSION_up_ref(ret);
        }
        CRYPTO_THREAD_unlock(s->session_ctx->lock);
        if (ret == NULL)
            s->session_ctx->stats.sess_miss++;
    }

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

        ret = s->session_ctx->get_session_cb(s, hello->session_id,
                                             hello->session_id_len,
                                             &copy);

        if (ret != NULL) {
            s->session_ctx->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)
                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->session_ctx->session_cache_mode &
                 SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
                /*
                 * The following should not return 1, otherwise, things are
                 * very strange
                 */
                if (SSL_CTX_add_session(s->session_ctx, ret))
                    goto err;
            }
        }
    }

    if (ret == NULL)
        goto err;

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

    /* Check TLS version consistency */
    if (ret->ssl_version != s->version)
        goto err;

    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).
         */

        SSLerr(SSL_F_SSL_GET_PREV_SESSION,
               SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
        fatal = 1;
        goto err;
    }

    if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */
        s->session_ctx->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;
    }

    /* Check extended master secret extension consistency */
    if (ret->flags & SSL_SESS_FLAG_EXTMS) {
        /* If old session includes extms, but new does not: abort handshake */
        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)) {
            SSLerr(SSL_F_SSL_GET_PREV_SESSION, SSL_R_INCONSISTENT_EXTMS);
            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
            fatal = 1;
            goto err;
        }
    } else if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
        /* If new session includes extms, but old does not: do not resume */
        goto err;
    }

    if (!SSL_IS_TLS13(s)) {
        /* We already did this for TLS1.3 */
        SSL_SESSION_free(s->session);
        s->session = ret;
    }

    s->session_ctx->stats.sess_hit++;
    s->verify_result = s->session->verify_result;
    return 1;

 err:
    if (ret != NULL) {
        SSL_SESSION_free(ret);
        /* In TLSv1.3 s->session was already set to ret, so we NULL it out */
        if (SSL_IS_TLS13(s))
            s->session = NULL;

        if (!try_session_cache) {
            /*
             * The session was from a ticket, so we should issue a ticket for
             * the new session
             */
            s->ext.ticket_expected = 1;
        }
    }
    if (fatal) {
        *al = SSL_AD_INTERNAL_ERROR;
        return -1;
    }

    return 0;
}
コード例 #9
0
ファイル: handshake_helper.c プロジェクト: Muffo/openssl
/*
 * Note that |extra| points to the correct client/server configuration
 * within |test_ctx|. When configuring the handshake, general mode settings
 * are taken from |test_ctx|, and client/server-specific settings should be
 * taken from |extra|.
 *
 * The configuration code should never reach into |test_ctx->extra| or
 * |test_ctx->resume_extra| directly.
 *
 * (We could refactor test mode settings into a substructure. This would result
 * in cleaner argument passing but would complicate the test configuration
 * parsing.)
 */
static HANDSHAKE_RESULT *do_handshake_internal(
    SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx,
    const SSL_TEST_CTX *test_ctx, const SSL_TEST_EXTRA_CONF *extra,
    SSL_SESSION *session_in, SSL_SESSION **session_out)
{
    PEER server, client;
    BIO *client_to_server, *server_to_client;
    HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
    CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
    HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
    int client_turn = 1;
    connect_phase_t phase = HANDSHAKE;
    handshake_status_t status = HANDSHAKE_RETRY;
    const unsigned char* tick = NULL;
    size_t tick_len = 0;
    SSL_SESSION* sess = NULL;
    const unsigned char *proto = NULL;
    /* API dictates unsigned int rather than size_t. */
    unsigned int proto_len = 0;

    memset(&server_ctx_data, 0, sizeof(server_ctx_data));
    memset(&server2_ctx_data, 0, sizeof(server2_ctx_data));
    memset(&client_ctx_data, 0, sizeof(client_ctx_data));
    memset(&server, 0, sizeof(server));
    memset(&client, 0, sizeof(client));

    configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx, extra,
                            &server_ctx_data, &server2_ctx_data, &client_ctx_data);

    /* Setup SSL and buffers; additional configuration happens below. */
    create_peer(&server, server_ctx);
    create_peer(&client, client_ctx);

    server.bytes_to_write = client.bytes_to_read = test_ctx->app_data_size;
    client.bytes_to_write = server.bytes_to_read = test_ctx->app_data_size;

    configure_handshake_ssl(server.ssl, client.ssl, extra);
    if (session_in != NULL) {
        /* In case we're testing resumption without tickets. */
        TEST_check(SSL_CTX_add_session(server_ctx, session_in));
        TEST_check(SSL_set_session(client.ssl, session_in));
    }

    memset(&server_ex_data, 0, sizeof(server_ex_data));
    memset(&client_ex_data, 0, sizeof(client_ex_data));

    ret->result = SSL_TEST_INTERNAL_ERROR;

    client_to_server = BIO_new(BIO_s_mem());
    server_to_client = BIO_new(BIO_s_mem());

    TEST_check(client_to_server != NULL);
    TEST_check(server_to_client != NULL);

    /* Non-blocking bio. */
    BIO_set_nbio(client_to_server, 1);
    BIO_set_nbio(server_to_client, 1);

    SSL_set_connect_state(client.ssl);
    SSL_set_accept_state(server.ssl);

    /* The bios are now owned by the SSL object. */
    SSL_set_bio(client.ssl, server_to_client, client_to_server);
    TEST_check(BIO_up_ref(server_to_client) > 0);
    TEST_check(BIO_up_ref(client_to_server) > 0);
    SSL_set_bio(server.ssl, client_to_server, server_to_client);

    ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL);
    TEST_check(ex_data_idx >= 0);

    TEST_check(SSL_set_ex_data(server.ssl, ex_data_idx, &server_ex_data) == 1);
    TEST_check(SSL_set_ex_data(client.ssl, ex_data_idx, &client_ex_data) == 1);

    SSL_set_info_callback(server.ssl, &info_cb);
    SSL_set_info_callback(client.ssl, &info_cb);

    client.status = server.status = PEER_RETRY;

    /*
     * Half-duplex handshake loop.
     * Client and server speak to each other synchronously in the same process.
     * We use non-blocking BIOs, so whenever one peer blocks for read, it
     * returns PEER_RETRY to indicate that it's the other peer's turn to write.
     * The handshake succeeds once both peers have succeeded. If one peer
     * errors out, we also let the other peer retry (and presumably fail).
     */
    for(;;) {
        if (client_turn) {
            do_connect_step(&client, phase);
            status = handshake_status(client.status, server.status,
                                      1 /* client went last */);
        } else {
            do_connect_step(&server, phase);
            status = handshake_status(server.status, client.status,
                                      0 /* server went last */);
        }

        switch (status) {
        case HANDSHAKE_SUCCESS:
            phase = next_phase(phase);
            if (phase == CONNECTION_DONE) {
                ret->result = SSL_TEST_SUCCESS;
                goto err;
            } else {
                client.status = server.status = PEER_RETRY;
                /*
                 * For now, client starts each phase. Since each phase is
                 * started separately, we can later control this more
                 * precisely, for example, to test client-initiated and
                 * server-initiated shutdown.
                 */
                client_turn = 1;
                break;
            }
        case CLIENT_ERROR:
            ret->result = SSL_TEST_CLIENT_FAIL;
            goto err;
        case SERVER_ERROR:
            ret->result = SSL_TEST_SERVER_FAIL;
            goto err;
        case INTERNAL_ERROR:
            ret->result = SSL_TEST_INTERNAL_ERROR;
            goto err;
        case HANDSHAKE_RETRY:
            /* Continue. */
            client_turn ^= 1;
            break;
        }
    }
 err:
    ret->server_alert_sent = server_ex_data.alert_sent;
    ret->server_num_fatal_alerts_sent = server_ex_data.num_fatal_alerts_sent;
    ret->server_alert_received = client_ex_data.alert_received;
    ret->client_alert_sent = client_ex_data.alert_sent;
    ret->client_num_fatal_alerts_sent = client_ex_data.num_fatal_alerts_sent;
    ret->client_alert_received = server_ex_data.alert_received;
    ret->server_protocol = SSL_version(server.ssl);
    ret->client_protocol = SSL_version(client.ssl);
    ret->servername = server_ex_data.servername;
    if ((sess = SSL_get0_session(client.ssl)) != NULL)
        SSL_SESSION_get0_ticket(sess, &tick, &tick_len);
    if (tick == NULL || tick_len == 0)
        ret->session_ticket = SSL_TEST_SESSION_TICKET_NO;
    else
        ret->session_ticket = SSL_TEST_SESSION_TICKET_YES;
    ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call;

#ifndef OPENSSL_NO_NEXTPROTONEG
    SSL_get0_next_proto_negotiated(client.ssl, &proto, &proto_len);
    ret->client_npn_negotiated = dup_str(proto, proto_len);

    SSL_get0_next_proto_negotiated(server.ssl, &proto, &proto_len);
    ret->server_npn_negotiated = dup_str(proto, proto_len);
#endif

    SSL_get0_alpn_selected(client.ssl, &proto, &proto_len);
    ret->client_alpn_negotiated = dup_str(proto, proto_len);

    SSL_get0_alpn_selected(server.ssl, &proto, &proto_len);
    ret->server_alpn_negotiated = dup_str(proto, proto_len);

    ret->client_resumed = SSL_session_reused(client.ssl);
    ret->server_resumed = SSL_session_reused(server.ssl);

    if (session_out != NULL)
        *session_out = SSL_get1_session(client.ssl);

    ctx_data_free_data(&server_ctx_data);
    ctx_data_free_data(&server2_ctx_data);
    ctx_data_free_data(&client_ctx_data);

    peer_free_data(&server);
    peer_free_data(&client);
    return ret;
}
コード例 #10
0
ファイル: ssl_sess.c プロジェクト: dgalaxy/openssl
SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id,
                                  size_t sess_id_len)
{
    SSL_SESSION *ret = NULL;

    if ((s->session_ctx->session_cache_mode
         & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) == 0) {
        SSL_SESSION data;

        data.ssl_version = s->version;
        if (!ossl_assert(sess_id_len <= SSL_MAX_SSL_SESSION_ID_LENGTH))
            return NULL;

        memcpy(data.session_id, sess_id, sess_id_len);
        data.session_id_length = sess_id_len;

        CRYPTO_THREAD_read_lock(s->session_ctx->lock);
        ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data);
        if (ret != NULL) {
            /* don't allow other threads to steal it: */
            SSL_SESSION_up_ref(ret);
        }
        CRYPTO_THREAD_unlock(s->session_ctx->lock);
        if (ret == NULL)
            tsan_counter(&s->session_ctx->stats.sess_miss);
    }

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

        ret = s->session_ctx->get_session_cb(s, sess_id, sess_id_len, &copy);

        if (ret != NULL) {
            tsan_counter(&s->session_ctx->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)
                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->session_ctx->session_cache_mode &
                 SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0) {
                /*
                 * Either return value of SSL_CTX_add_session should not
                 * interrupt the session resumption process. The return
                 * value is intentionally ignored.
                 */
                (void)SSL_CTX_add_session(s->session_ctx, ret);
            }
        }
    }

    return ret;
}
コード例 #11
0
ファイル: ssl_sess.c プロジェクト: bbbrumley/openbsd
/*
 * 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;
}