void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) { sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(ssl_ctx) != NULL) sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; if (sock->ssl->input.encrypted->size != 0) proceed_handshake(sock, 0); else h2o_socket_read_start(sock, proceed_handshake); } else { sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) { sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(ssl_ctx) != NULL) sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; if (sock->ssl->input.encrypted->size != 0) proceed_handshake(sock, 0); else h2o_socket_read_start(sock, proceed_handshake); } else { h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(ssl_ctx); if (session_cache != NULL) { struct sockaddr_storage sa; int32_t port; if (h2o_socket_getpeername(sock, (struct sockaddr *)&sa) != 0 && (port = h2o_socket_getport((struct sockaddr *)&sa)) != -1) { /* session cache is available */ h2o_iovec_t session_cache_key; session_cache_key.base = h2o_mem_alloc(strlen(server_name) + sizeof(":" H2O_UINT16_LONGEST_STR)); session_cache_key.len = sprintf(session_cache_key.base, "%s:%" PRIu16, server_name, (uint16_t)port); sock->ssl->handshake.client.session_cache = session_cache; sock->ssl->handshake.client.session_cache_key = session_cache_key; sock->ssl->handshake.client.session_cache_key_hash = h2o_cache_calchash(session_cache_key.base, session_cache_key.len); /* fetch from session cache */ h2o_cache_ref_t *cacheref = h2o_cache_fetch(session_cache, h2o_now(h2o_socket_get_loop(sock)), sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash); if (cacheref != NULL) { SSL_set_session(sock->ssl->ssl, (SSL_SESSION *)cacheref->value.base); h2o_cache_release(session_cache, cacheref); } } } sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = { BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL }; BIO *bio; sock->ssl = h2o_malloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); h2o_mempool_init(&sock->ssl->output.pool); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = {BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL}; BIO *bio; sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
void h2o_socket_ssl_resume_server_handshake(h2o_socket_t *sock, h2o_iovec_t session_data) { if (session_data.len != 0) { const unsigned char *p = (void *)session_data.base; sock->ssl->handshake.server.async_resumption.session_data = d2i_SSL_SESSION(NULL, &p, (long)session_data.len); /* FIXME warn on failure */ } sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; proceed_handshake(sock, 0); if (sock->ssl->handshake.server.async_resumption.session_data != NULL) { SSL_SESSION_free(sock->ssl->handshake.server.async_resumption.session_data); sock->ssl->handshake.server.async_resumption.session_data = NULL; } }