static int openssl_iostream_set(struct ssl_iostream *ssl_io, const struct ssl_iostream_settings *set, const char **error_r) { const struct ssl_iostream_settings *ctx_set = ssl_io->ctx->set; int verify_flags; if (set->verbose) SSL_set_info_callback(ssl_io->ssl, openssl_info_callback); if (set->cipher_list != NULL && strcmp(ctx_set->cipher_list, set->cipher_list) != 0) { if (!SSL_set_cipher_list(ssl_io->ssl, set->cipher_list)) { *error_r = t_strdup_printf( "Can't set cipher list to '%s': %s", set->cipher_list, openssl_iostream_error()); return -1; } } if (set->protocols != NULL) { SSL_clear_options(ssl_io->ssl, OPENSSL_ALL_PROTOCOL_OPTIONS); SSL_set_options(ssl_io->ssl, openssl_get_protocol_options(set->protocols)); } if (set->cert != NULL && strcmp(ctx_set->cert, set->cert) != 0) { if (openssl_iostream_use_certificate(ssl_io, set->cert, error_r) < 0) return -1; } if (set->key != NULL && strcmp(ctx_set->key, set->key) != 0) { if (openssl_iostream_use_key(ssl_io, set, error_r) < 0) return -1; } if (set->verify_remote_cert) { if (ssl_io->ctx->client_ctx) verify_flags = SSL_VERIFY_NONE; else verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; SSL_set_verify(ssl_io->ssl, verify_flags, openssl_iostream_verify_client_cert); } if (set->cert_username_field != NULL) { ssl_io->username_nid = OBJ_txt2nid(set->cert_username_field); if (ssl_io->username_nid == NID_undef) { *error_r = t_strdup_printf( "Invalid cert_username_field: %s", set->cert_username_field); return -1; } } else { ssl_io->username_nid = ssl_io->ctx->username_nid; } ssl_io->verbose = set->verbose; ssl_io->verbose_invalid_cert = set->verbose_invalid_cert || set->verbose; ssl_io->require_valid_cert = set->require_valid_cert; return 0; }
LWS_VISIBLE int lws_ssl_close(struct lws *wsi) { lws_sockfd_type n; if (!wsi->ssl) return 0; /* not handled */ #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) /* kill ssl callbacks, becausse we will remove the fd from the * table linking it to the wsi */ if (wsi->vhost->ssl_info_event_mask) SSL_set_info_callback(wsi->ssl, NULL); #endif n = SSL_get_fd(wsi->ssl); if (!wsi->socket_is_permanently_unusable) SSL_shutdown(wsi->ssl); compatible_close(n); SSL_free(wsi->ssl); wsi->ssl = NULL; if (wsi->context->simultaneous_ssl_restriction && wsi->context->simultaneous_ssl-- == wsi->context->simultaneous_ssl_restriction) /* we made space and can do an accept */ lws_gate_accepts(wsi->context, 1); #if defined(LWS_WITH_STATS) wsi->context->updated = 1; #endif return 1; /* handled */ }
static void rb_setup_ssl_cb(rb_fde_t *F) { SSL_set_ex_data(F->ssl, libratbox_index, (char *)F); SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *, int, int))rb_ssl_info_callback); }
janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { janus_ice_component *component = (janus_ice_component *)ice_component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return NULL; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return NULL; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; } janus_dtls_srtp *dtls = calloc(1, sizeof(janus_dtls_srtp)); if(dtls == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); return NULL; } /* Create SSL context, at last */ dtls->srtp_valid = 0; dtls->dtls_last_msg = NULL; dtls->dtls_last_len = 0; dtls->ssl = SSL_new(janus_dtls_get_ssl_ctx()); if(!dtls->ssl) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component DTLS SSL session??\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } SSL_set_ex_data(dtls->ssl, 0, dtls); SSL_set_info_callback(dtls->ssl, janus_dtls_callback); dtls->read_bio = BIO_new(BIO_s_mem()); if(!dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating read BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->read_bio, -1); dtls->write_bio = BIO_new(BIO_s_mem()); if(!dtls->write_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating write BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->write_bio, -1); SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->write_bio); dtls->dtls_role = role; if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting connect state (DTLS client)\n", handle->handle_id); SSL_set_connect_state(dtls->ssl); } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting accept state (DTLS server)\n", handle->handle_id); SSL_set_accept_state(dtls->ssl); } /* Done */ dtls->component = component; return dtls; }
static long bio_rdp_tls_callback_ctrl(BIO* bio, int cmd, bio_info_cb* fp) { int status = 0; BIO_RDP_TLS* tls; if (!bio) return 0; tls = (BIO_RDP_TLS*) BIO_get_data(bio); if (!tls) return 0; switch (cmd) { case BIO_CTRL_SET_CALLBACK: SSL_set_info_callback(tls->ssl, (void (*)(const SSL*, int, int)) fp); status = 1; break; default: status = BIO_callback_ctrl(SSL_get_rbio(tls->ssl), cmd, fp); break; } return status; }
const bool QFrankSSL::K_SSLStrukturAufbauen() { if(K_OpenSSLStruktur==NULL) { K_OpenSSLFehlerText=K_KeineOpenSSLStrukturText+K_SSLFehlertext(); #ifndef QT_NO_DEBUG qCritical("%s K_SSLStrukturAufbauen: OpenSSL Struktur fehlt",this->metaObject()->className()); qCritical(qPrintable(K_SSLFehlertext())); #endif K_AllesZuruecksetzen(); return false; } K_SSLStruktur=SSL_new(K_OpenSSLStruktur); if(K_SSLStruktur==NULL) { K_OpenSSLFehlerText=K_SSLFehlertext(); #ifndef QT_NO_DEBUG qWarning("%s K_SSLStrukturAufbauen: fehlgeschlagen",this->metaObject()->className()); qWarning()<<K_OpenSSLFehlerText; #endif K_AllesZuruecksetzen(); return false; } long Parameter=0; if(!(K_ZuBenutzendeSSLVersionen&QFrankSSL::SSLv2)) Parameter=Parameter|SSL_OP_NO_SSLv2; if(!(K_ZuBenutzendeSSLVersionen&QFrankSSL::SSLv3)) Parameter=Parameter|SSL_OP_NO_SSLv3; if(!(K_ZuBenutzendeSSLVersionen&QFrankSSL::TLSv1)) Parameter=Parameter|SSL_OP_NO_TLSv1; //Damit die Callbackfunktion denn Zugriff auf die Klasse hat. K_ListeDerSSLVerbindungen.insert(K_SSLStruktur,this); SSL_set_info_callback(K_SSLStruktur,K_SSL_Info_Callback); #ifndef QT_NO_DEBUG qDebug("%s K_SSLStrukturAufbauen: erfolgreich",this->metaObject()->className()); QString SSLOptionen="SSL Optionen:"; long Optionen=SSL_set_options(K_SSLStruktur,Parameter); if(Optionen&SSL_OP_NO_SSLv2) SSLOptionen.append("\r\n\tKein SSLv2"); else SSLOptionen.append("\r\n\tSSLv2"); if(Optionen&SSL_OP_NO_SSLv3) SSLOptionen.append("\r\n\tKein SSLv3"); else SSLOptionen.append("\r\n\tSSLv3"); if(Optionen&SSL_OP_NO_TLSv1) SSLOptionen.append("\r\n\tKein TLSv1"); else SSLOptionen.append("\r\n\tTLSv1"); qDebug(SSLOptionen.toLatin1().constData()); #else SSL_set_options(K_SSLStruktur,Parameter); #endif //Nur hohlen, wenn die Liste leer ist, da sonst die Nutzervorgaben überschrieben werden. if(K_VerfuegbareAlgorithmen.isEmpty()) K_VerfuegbareAlgorithmenHohlen(); return true; }
/** Create a new client TLS session * * Configures a new client TLS session, configuring options, setting callbacks etc... * * @param ctx to alloc session data in. Should usually be NULL unless the lifetime of the * session is tied to another talloc'd object. * @param conf values for this TLS session. * @return * - A new session on success. * - NULL on error. */ tls_session_t *tls_session_init_client(TALLOC_CTX *ctx, fr_tls_conf_t *conf) { int ret; int verify_mode; tls_session_t *session = NULL; REQUEST *request; session = talloc_zero(ctx, tls_session_t); if (!session) return NULL; talloc_set_destructor(session, _tls_session_free); session->ctx = conf->ctx[(conf->ctx_count == 1) ? 0 : conf->ctx_next++ % conf->ctx_count]; /* mutex not needed */ rad_assert(session->ctx); session->ssl = SSL_new(session->ctx); if (!session->ssl) { talloc_free(session); return NULL; } request = request_alloc(session); SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request); /* * Add the message callback to identify what type of * message/handshake is passed */ SSL_set_msg_callback(session->ssl, tls_session_msg_cb); SSL_set_msg_callback_arg(session->ssl, session); SSL_set_info_callback(session->ssl, tls_session_info_cb); /* * Always verify the peer certificate. */ DEBUG2("Requiring Server certificate"); verify_mode = SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; SSL_set_verify(session->ssl, verify_mode, tls_validate_cert_cb); SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf); SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)session); ret = SSL_connect(session->ssl); if (ret <= 0) { tls_log_io_error(NULL, session, ret, "Failed in SSL_connect"); talloc_free(session); return NULL; } session->mtu = conf->fragment_size; return session; }
int lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) { #if !defined(USE_WOLFSSL) BIO *bio; #endif errno = 0; wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx); if (wsi->tls.ssl == NULL) { lwsl_err("SSL_new failed: %d (errno %d)\n", lws_ssl_get_error(wsi, 0), errno); lws_tls_err_describe(); return 1; } SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi); SSL_set_fd(wsi->tls.ssl, (int)(long long)accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->tls.ssl, 1); #else wolfSSL_set_using_nonblock(wsi->tls.ssl, 1); #endif #else SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); bio = SSL_get_rbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->tls.ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) if (wsi->vhost->tls.ssl_info_event_mask) SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); #endif return 0; }
bool Parser::init() { if (!ssl) { printf("Error: dtls::Parser::init() failed because the `ssl` member hasn't been set yet.\n"); return false; } /* in bio */ { in_bio = BIO_new(BIO_s_mem()); if (!in_bio) { printf("Error: dtls::Parser::init() failed because we can't create our in_bio.\n"); return false; } BIO_set_mem_eof_return(in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */ } /* out bio */ { out_bio = BIO_new(BIO_s_mem()); if (!out_bio) { printf("Error: dtls::Parser::init() failed because can't create out out_bio.\n"); /* @todo cleanup. */ return false; } BIO_set_mem_eof_return(out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */ } /* set info callback */ SSL_set_info_callback(ssl, dtls_parse_ssl_info_callback); /* set in and output bios. */ SSL_set_bio(ssl, in_bio, out_bio); if (mode == DTLS_MODE_SERVER) { SSL_set_accept_state(ssl); /* in case we're a server */ } else if(mode == DTLS_MODE_CLIENT) { //SSL_set_connect_state(ssl); /* in case we're a client */ printf("dtls::Parser - error: not yet handling client state for dtls::Parser().\n"); exit(1); } return true; }
static void write_server() { uv_buf_t buf; uv_link_t* serv; serv = (uv_link_t*) &server.observer; SSL_set_info_callback(server.ssl, write_info_cb); CHECK_EQ(uv_run(loop, UV_RUN_DEFAULT), 0, "uv_run()"); CHECK_EQ(handshakes_done, 1, "handshake happened"); /* NOTE: uv_run() will exit after handshake */ buf = uv_buf_init("hello", 5); CHECK_EQ(uv_link_try_write(serv, &buf, 1), 5, "uv_link_try_write(server)"); CHECK_EQ(uv_run(loop, UV_RUN_DEFAULT), 0, "uv_run()"); }
/* this sets up the SSL* */ int krx_ssl_init(krx* k, int isserver, info_callback cb) { /* create SSL* */ k->ssl = SSL_new(k->ctx); if(!k->ssl) { printf("Error: cannot create new SSL*.\n"); return -1; } /* info callback */ SSL_set_info_callback(k->ssl, cb); /* bios */ k->in_bio = BIO_new(BIO_s_mem()); if(k->in_bio == NULL) { printf("Error: cannot allocate read bio.\n"); return -2; } BIO_set_mem_eof_return(k->in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */ k->out_bio = BIO_new(BIO_s_mem()); if(k->out_bio == NULL) { printf("Error: cannot allocate write bio.\n"); return -3; } BIO_set_mem_eof_return(k->out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */ SSL_set_bio(k->ssl, k->in_bio, k->out_bio); /* either use the server or client part of the protocol */ if(isserver == 1) { SSL_set_accept_state(k->ssl); } else { SSL_set_connect_state(k->ssl); } return 0; }
static long ssl_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) { SSL *ssl; BIO_SSL *bs; long ret=1; bs=(BIO_SSL *)b->ptr; ssl=bs->ssl; switch (cmd) { case BIO_CTRL_SET_CALLBACK: { /* FIXME: setting this via a completely different prototype seems like a crap idea */ SSL_set_info_callback(ssl,(void (*)(const SSL *,int,int))fp); } break; default: ret=BIO_callback_ctrl(ssl->rbio,cmd,fp); break; } return(ret); }
int lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) { #if !defined(LWS_WITH_XRADIO) errno = 0; #endif wsi->ssl = SSL_new(wsi->vhost->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: errno %d\n", errno); lws_ssl_elaborate_error(); return 1; } SSL_set_fd(wsi->ssl, accept_fd); if (wsi->vhost->ssl_info_event_mask) SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback); SSL_set_sni_callback(wsi->ssl, lws_mbedtls_sni_cb, wsi->context); return 0; }
/** Create a new server TLS session * * Configures a new server TLS session, configuring options, setting callbacks etc... * * @param ctx to alloc session data in. Should usually be NULL unless the lifetime of the * session is tied to another talloc'd object. * @param conf values for this TLS session. * @param request The current #REQUEST. * @param client_cert Whether to require a client_cert. * @return * - A new session on success. * - NULL on error. */ tls_session_t *tls_session_init_server(TALLOC_CTX *ctx, fr_tls_conf_t *conf, REQUEST *request, bool client_cert) { tls_session_t *session = NULL; SSL *new_tls = NULL; int verify_mode = 0; VALUE_PAIR *vp; SSL_CTX *ssl_ctx; rad_assert(request != NULL); rad_assert(conf->ctx_count > 0); RDEBUG2("Initiating new TLS session"); ssl_ctx = conf->ctx[(conf->ctx_count == 1) ? 0 : conf->ctx_next++ % conf->ctx_count]; /* mutex not needed */ rad_assert(ssl_ctx); new_tls = SSL_new(ssl_ctx); if (new_tls == NULL) { tls_log_error(request, "Error creating new TLS session"); return NULL; } session = talloc_zero(ctx, tls_session_t); if (session == NULL) { RERROR("Error allocating memory for TLS session"); SSL_free(new_tls); return NULL; } session_init(session); session->ctx = ssl_ctx; session->ssl = new_tls; talloc_set_destructor(session, _tls_session_free); /* * Initialize callbacks */ session->record_init = record_init; session->record_close = record_close; session->record_from_buff = record_from_buff; session->record_to_buff = record_to_buff; /* * Create & hook the BIOs to handle the dirty side of the * SSL. This is *very important* as we want to handle * the transmission part. Now the only IO interface * that SSL is aware of, is our defined BIO buffers. * * This means that all SSL IO is done to/from memory, * and we can update those BIOs from the packets we've * received. */ session->into_ssl = BIO_new(BIO_s_mem()); session->from_ssl = BIO_new(BIO_s_mem()); SSL_set_bio(session->ssl, session->into_ssl, session->from_ssl); /* * Add the message callback to identify what type of * message/handshake is passed */ SSL_set_msg_callback(new_tls, tls_session_msg_cb); SSL_set_msg_callback_arg(new_tls, session); SSL_set_info_callback(new_tls, tls_session_info_cb); /* * This sets the context sessions can be resumed in. * This is to prevent sessions being created by one application * and used by another. In our case it prevents sessions being * reused between modules, or TLS server components such as * RADSEC. * * A context must always be set when doing session resumption * otherwise session resumption will fail. * * As the context ID must be <= 32, we digest the context * data with sha256. */ rad_assert(conf->session_id_name); { char *context_id; EVP_MD_CTX *md_ctx; uint8_t digest[SHA256_DIGEST_LENGTH]; static_assert(sizeof(digest) <= SSL_MAX_SSL_SESSION_ID_LENGTH, "SSL_MAX_SSL_SESSION_ID_LENGTH must be >= SHA256_DIGEST_LENGTH"); if (tmpl_aexpand(session, &context_id, request, conf->session_id_name, NULL, NULL) < 0) { RPEDEBUG("Failed expanding session ID"); talloc_free(session); } MEM(md_ctx = EVP_MD_CTX_create()); EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL); EVP_DigestUpdate(md_ctx, context_id, talloc_array_length(context_id) - 1); EVP_DigestFinal_ex(md_ctx, digest, NULL); EVP_MD_CTX_destroy(md_ctx); talloc_free(context_id); if (!fr_cond_assert(SSL_set_session_id_context(session->ssl, digest, sizeof(digest)) == 1)) { talloc_free(session); return NULL; } } /* * Add the session certificate to the session. */ vp = fr_pair_find_by_da(request->control, attr_tls_session_cert_file, TAG_ANY); if (vp) { RDEBUG2("Loading TLS session certificate \"%s\"", vp->vp_strvalue); if (SSL_use_certificate_file(session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) { tls_log_error(request, "Failed loading TLS session certificate \"%s\"", vp->vp_strvalue); talloc_free(session); return NULL; } if (SSL_use_PrivateKey_file(session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) { tls_log_error(request, "Failed loading TLS session certificate \"%s\"", vp->vp_strvalue); talloc_free(session); return NULL; } if (SSL_check_private_key(session->ssl) != 1) { tls_log_error(request, "Failed validating TLS session certificate \"%s\"", vp->vp_strvalue); talloc_free(session); return NULL; } /* * Better to perform explicit checks, than rely * on OpenSSL's opaque error messages. */ } else { if (!conf->chains || !conf->chains[0]->private_key_file) { ERROR("TLS Server requires a private key file"); talloc_free(session); return NULL; } if (!conf->chains || !conf->chains[0]->certificate_file) { ERROR("TLS Server requires a certificate file"); talloc_free(session); return NULL; } } /* * In Server mode we only accept. * * This sets up the SSL session to work correctly with * tls_session_handhsake. */ SSL_set_accept_state(session->ssl); /* * Verify the peer certificate, if asked. */ if (client_cert) { RDEBUG2("Setting verify mode to require certificate from client"); verify_mode = SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; verify_mode |= SSL_VERIFY_CLIENT_ONCE; } SSL_set_verify(session->ssl, verify_mode, tls_validate_cert_cb); SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf); SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)session); /* * We use default fragment size, unless the Framed-MTU * tells us it's too big. Note that we do NOT account * for the EAP-TLS headers if conf->fragment_size is * large, because that config item looks to be confusing. * * i.e. it should REALLY be called MTU, and the code here * should figure out what that means for TLS fragment size. * asking the administrator to know the internal details * of EAP-TLS in order to calculate fragment sizes is * just too much. */ session->mtu = conf->fragment_size; vp = fr_pair_find_by_da(request->packet->vps, attr_framed_mtu, TAG_ANY); if (vp && (vp->vp_uint32 > 100) && (vp->vp_uint32 < session->mtu)) { RDEBUG2("Setting fragment_len to %u from &Framed-MTU", vp->vp_uint32); session->mtu = vp->vp_uint32; } if (conf->session_cache_server) session->allow_session_resumption = true; /* otherwise it's false */ return session; }
void bud_client_create(bud_config_t* config, uv_stream_t* stream) { int r; bud_client_t* client; bud_client_error_t cerr; BIO* enc_in; BIO* enc_out; #ifdef SSL_MODE_RELEASE_BUFFERS long mode; #endif /* SSL_MODE_RELEASE_BUFFERS */ client = malloc(sizeof(*client)); if (client == NULL) return; client->config = config; client->ssl = NULL; client->last_handshake = 0; client->handshakes = 0; client->connect = kBudProgressNone; client->close = kBudProgressNone; client->cycle = kBudProgressNone; client->recycle = 0; client->destroy_waiting = 0; client->id = bud_config_get_client_id(config); client->async_hello = kBudProgressDone; if (config->sni.enabled || config->stapling.enabled) client->async_hello = kBudProgressNone; /* SNI */ client->sni_req = NULL; client->sni_ctx.ctx = NULL; /* Stapling */ client->stapling_cache_req = NULL; client->stapling_req = NULL; client->stapling_ocsp_resp = NULL; /* Availability */ client->retry = kBudProgressNone; client->retry_count = 0; client->retry_timer.data = client; client->backend_list = NULL; client->selected_backend = NULL; /* Proxyline */ client->proxyline_waiting = 2; /* X-Forward */ client->xforward.skip = 0; client->xforward.crlf = 0; r = uv_timer_init(config->loop, &client->retry_timer); if (r != 0) goto failed_timer_init; client->destroy_waiting++; /* Initialize buffers */ bud_client_side_init(&client->frontend, kBudFrontend, client); bud_client_side_init(&client->backend, kBudBackend, client); /** * Accept client on frontend */ r = uv_tcp_init(config->loop, &client->frontend.tcp); if (r != 0) goto failed_tcp_in_init; client->destroy_waiting++; r = uv_accept(stream, (uv_stream_t*) &client->frontend.tcp); if (r != 0) goto failed_accept; cerr = bud_client_read_start(client, &client->frontend); if (!bud_is_ok(cerr.err)) goto failed_accept; client->frontend.reading = kBudProgressRunning; /* Fill hosts */ cerr = bud_client_fill_host(client, &client->local); if (!bud_is_ok(cerr.err)) goto failed_accept; cerr = bud_client_fill_host(client, &client->remote); if (!bud_is_ok(cerr.err)) goto failed_accept; /* * Select a backend and connect to it, or wait for a backend to become * alive again. */ /* SNI backend comes from `backend` or sni callback */ client->backend_list = &config->contexts[0].backend; client->balance = config->balance_e; if (client->balance == kBudBalanceSNI) { client->selected_backend = NULL; client->connect = kBudProgressRunning; } else { client->selected_backend = bud_select_backend(client); } /* No backend can be selected yet, wait for SNI */ if (client->selected_backend == NULL) { client->backend.close = kBudProgressDone; cerr = bud_client_ok(&client->backend); /* No backend alive, try reconnecting */ } else if (client->selected_backend->dead) { DBG_LN(&client->backend, "all backends dead, scheduling reconnection"); cerr = bud_client_retry(client); /* Backend alive - connect immediately */ } else { cerr = bud_client_connect(client); } if (!bud_is_ok(cerr.err)) goto failed_accept; /* Adjust sockets */ r = uv_tcp_nodelay(&client->frontend.tcp, 1); if (r == 0 && config->frontend.keepalive > 0) r = uv_tcp_keepalive(&client->frontend.tcp, 1, config->frontend.keepalive); if (r != 0) goto failed_connect; /* Initialize SSL */ /* First context is always default */ client->ssl = SSL_new(config->contexts[0].ctx); if (client->ssl == NULL) goto failed_connect; if (!SSL_set_ex_data(client->ssl, kBudSSLClientIndex, client)) goto failed_connect; SSL_set_cert_cb(client->ssl, bud_client_ssl_cert_cb, client); SSL_set_info_callback(client->ssl, bud_client_ssl_info_cb); enc_in = bud_bio_new(&client->frontend.input); if (enc_in == NULL) goto failed_connect; enc_out = bud_bio_new(&client->frontend.output); if (enc_out == NULL) { BIO_free_all(enc_in); goto failed_connect; } SSL_set_bio(client->ssl, enc_in, enc_out); #ifdef SSL_MODE_RELEASE_BUFFERS mode = SSL_get_mode(client->ssl); SSL_set_mode(client->ssl, mode | SSL_MODE_RELEASE_BUFFERS); #endif /* SSL_MODE_RELEASE_BUFFERS */ SSL_set_accept_state(client->ssl); bud_trace_frontend_accept(client); DBG_LN(&client->frontend, "new"); return; failed_connect: client->connect = kBudProgressDone; client->close = kBudProgressDone; uv_close((uv_handle_t*) &client->backend.tcp, bud_client_close_cb); failed_accept: uv_close((uv_handle_t*) &client->frontend.tcp, bud_client_close_cb); failed_tcp_in_init: uv_close((uv_handle_t*) &client->retry_timer, bud_client_close_cb); return; failed_timer_init: free(client); }
/** * Run SSL handshake and store the resulting time value in the * 'time_map'. * * @param time_map where to store the current time * @param time_is_an_illusion * @param http whether to do an http request and take the date from that * instead. */ static void run_ssl (uint32_t *time_map, int time_is_an_illusion, int http) { BIO *s_bio; SSL_CTX *ctx; SSL *ssl; struct stat statbuf; uint32_t result_time; SSL_load_error_strings(); SSL_library_init(); ctx = NULL; if (0 == strcmp("sslv23", protocol)) { verb ("V: using SSLv23_client_method()"); ctx = SSL_CTX_new(SSLv23_client_method()); } else if (0 == strcmp("sslv3", protocol)) { verb ("V: using SSLv3_client_method()"); ctx = SSL_CTX_new(SSLv3_client_method()); } else if (0 == strcmp("tlsv1", protocol)) { verb ("V: using TLSv1_client_method()"); ctx = SSL_CTX_new(TLSv1_client_method()); } else die("Unsupported protocol `%s'", protocol); if (ctx == NULL) die("OpenSSL failed to support protocol `%s'", protocol); verb("V: Using OpenSSL for SSL"); if (ca_racket) { if (-1 == stat(ca_cert_container, &statbuf)) { die("Unable to stat CA certficate container %s", ca_cert_container); } else { switch (statbuf.st_mode & S_IFMT) { case S_IFREG: if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL)) fprintf(stderr, "SSL_CTX_load_verify_locations failed"); break; case S_IFDIR: if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container)) fprintf(stderr, "SSL_CTX_load_verify_locations failed"); break; default: if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container)) { fprintf(stderr, "SSL_CTX_load_verify_locations failed"); die("Unable to load CA certficate container %s", ca_cert_container); } } } } if (NULL == (s_bio = make_ssl_bio(ctx))) die ("SSL BIO setup failed"); BIO_get_ssl(s_bio, &ssl); if (NULL == ssl) die ("SSL setup failed"); if (time_is_an_illusion) { SSL_set_info_callback(ssl, openssl_time_callback); } SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); verb("V: opening socket to %s:%s", host, port); if ( (1 != BIO_set_conn_hostname(s_bio, host)) || (1 != BIO_set_conn_port(s_bio, port)) ) die ("Failed to initialize connection to `%s:%s'", host, port); if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE)) die ("BIO_new_fp returned error, possibly: %s", strerror(errno)); // This should run in seccomp // eg: prctl(PR_SET_SECCOMP, 1); if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later? die ("SSL connection failed"); if (1 != BIO_do_handshake(s_bio)) die ("SSL handshake failed"); // from /usr/include/openssl/ssl3.h // ssl->s3->server_random is an unsigned char of 32 bits memcpy(&result_time, ssl->s3->server_random, sizeof (uint32_t)); verb("V: In TLS response, T=%lu", (unsigned long)ntohl(result_time)); if (http) { char buf[1024]; verb_debug ("V: Starting HTTP"); if (snprintf(buf, sizeof(buf), HTTP_REQUEST, HTTPS_USER_AGENT, hostname_to_verify) >= 1024) die("hostname too long"); buf[1023]='\0'; /* Unneeded. */ verb_debug ("V: Writing HTTP request"); if (1 != write_all_to_bio(s_bio, buf)) die ("write all to bio failed."); verb_debug ("V: Reading HTTP response"); if (1 != read_http_date_from_bio(s_bio, &result_time)) die ("read all from bio failed."); verb ("V: Received HTTP response. T=%lu", (unsigned long)result_time); result_time = htonl(result_time); } // Verify the peer certificate against the CA certs on the local system if (ca_racket) { inspect_key (ssl, hostname_to_verify); } else { verb ("V: Certificate verification skipped!"); } check_key_length(ssl); memcpy(time_map, &result_time, sizeof (uint32_t)); SSL_free(ssl); SSL_CTX_free(ctx); }
int ssl_client_libssl(void) { //int verify_peer = ON; int verify_peer = OFF; const SSL_METHOD *client_meth; SSL_CTX *ssl_client_ctx; int clientsocketfd; struct sockaddr_in serveraddr; int handshakestatus; SSL *clientssl; char buffer[1024] = "Client Say Hello Server"; int ret; SSL_library_init(); //添加国密算法对ssl的支持 SSL_load_error_strings(); // TODO 1 //client_meth = SSLv23_client_method(); //client_meth = TLSv1_1_client_method(); client_meth = GMSSLv1_client_method(); // TODO 2 ssl_client_ctx = SSL_CTX_new(client_meth); if(!ssl_client_ctx) { ERR_print_errors_fp(stderr); return -1; } if(verify_peer) { if(SSL_CTX_use_certificate_file(ssl_client_ctx, CLIENT_CERT, FILE_TYPE) <= 0) { ERR_print_errors_fp(stderr); return -1; } if(SSL_CTX_use_PrivateKey_file(ssl_client_ctx, CLIENT_KEY,SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } // TODO 3 if(SSL_CTX_check_private_key(ssl_client_ctx) != 1) { printf("Private and certificate is not matching\n"); return -1; } //See function man pages for instructions on generating CERT files if(!SSL_CTX_load_verify_locations(ssl_client_ctx,CA_CERT, NULL)) { ERR_print_errors_fp(stderr); return -1; } SSL_CTX_set_verify(ssl_client_ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_set_verify_depth(ssl_client_ctx, 1); } if((clientsocketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("Error on socket creation\n"); return -1; } memset(&serveraddr, 0, sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; //serveraddr.sin_addr.s_addr = inet_addr("192.168.2.75"); serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); serveraddr.sin_port=htons(4433); if(connect(clientsocketfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in)) < 0) { perror("connect"); return -1; } /* ----------------------------------------------- */ /* Now we hava a real socket to use for ssl */ // TODO 4 clientssl = SSL_new(ssl_client_ctx); if(!clientssl) { printf("Error SSL_new\n"); return -1; } SSL_set_info_callback(clientssl,apps_ssl_info_callback); SSL_set_fd(clientssl, clientsocketfd); // TODO 5 if((ret = SSL_connect(clientssl)) != 1) { printf("Handshake Error %d\n", SSL_get_error(clientssl, ret)); return -1; } /* ------------------------------------------------------- */ /* SSL Connect Success Now we print some information */ printf ("SSL connection using %s\n", SSL_get_cipher (clientssl)); /* -------------------------------------------------------- */ /* There if we need verify peer */ if(verify_peer) { X509 *ssl_client_cert = NULL; ssl_client_cert = SSL_get_peer_certificate(clientssl); if(ssl_client_cert) { long verifyresult; verifyresult = SSL_get_verify_result(clientssl); if(verifyresult == X509_V_OK) printf("Certificate Verify Success\n"); else printf("Certificate Verify Failed\n"); X509_free(ssl_client_cert); } else printf("There is no client certificate\n"); } SSL_write(clientssl, buffer, strlen(buffer) + 1); SSL_read(clientssl, buffer, sizeof(buffer)); printf("SSL server send %s\n", buffer); SSL_shutdown(clientssl); close(clientsocketfd); SSL_free(clientssl); SSL_CTX_free(ssl_client_ctx); return 0; }
HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx) { SSL *server, *client; BIO *client_to_server, *server_to_client; HANDSHAKE_EX_DATA server_ex_data, client_ex_data; HANDSHAKE_RESULT ret; int client_turn = 1; peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY; handshake_status_t status = HANDSHAKE_RETRY; unsigned char* tick = NULL; size_t len = 0; SSL_SESSION* sess = NULL; configure_handshake_ctx(server_ctx, client_ctx, test_ctx); server = SSL_new(server_ctx); client = SSL_new(client_ctx); OPENSSL_assert(server != NULL && client != NULL); configure_handshake_ssl(server, client, test_ctx); memset(&server_ex_data, 0, sizeof(server_ex_data)); memset(&client_ex_data, 0, sizeof(client_ex_data)); memset(&ret, 0, sizeof(ret)); 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_callback); SSL_set_info_callback(client, &info_callback); /* * 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); status = handshake_status(client_status, server_status, 1 /* client went last */); } else { server_status = do_handshake_step(server); status = handshake_status(server_status, client_status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: ret.result = SSL_TEST_SUCCESS; goto err; 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 = ((SSL_get_SSL_CTX(server) == server_ctx) ? SSL_TEST_SERVERNAME_SERVER1 : SSL_TEST_SERVERNAME_SERVER2); if ((sess = SSL_get0_session(client)) != NULL) SSL_SESSION_get0_ticket(sess, &tick, &len); if (tick == NULL || 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_free(server); SSL_free(client); return ret; }
/* Switch a socket to SSL communication * * Creates a SSL data structure for the connection; * Sets up callbacks and initiates a SSL handshake with the peer; * Reports error conditions and performs cleanup upon failure. * * flags: ssl flags, i.e connect or listen * verify: peer certificate verification flags * loglevel: is the level to output information about the connection * and certificates. * host: contains the dns name or ip address of the peer. Used for * verification. * cb: optional callback, this function will be called after the * handshake completes. * * Return value: 0 on success, !=0 on failure. */ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, IntFunc cb) { int i, err, ret; ssl_appdata *data; struct threaddata *td = threaddata(); debug0("TLS: attempting SSL negotiation..."); if (!ssl_ctx && ssl_init()) { debug0("TLS: Failed. OpenSSL not initialized properly."); return -1; } /* find the socket in the list */ i = findsock(sock); if (i == -1) { debug0("TLS: socket not in socklist"); return -2; } if (td->socklist[i].ssl) { debug0("TLS: handshake not required - SSL session already established"); return 0; } td->socklist[i].ssl = SSL_new(ssl_ctx); if (!td->socklist[i].ssl || !SSL_set_fd(td->socklist[i].ssl, td->socklist[i].sock)) { debug1("TLS: cannot initiate SSL session - %s", ERR_error_string(ERR_get_error(), 0)); return -3; } /* Prepare a ssl appdata struct for the verify callback */ data = nmalloc(sizeof(ssl_appdata)); egg_bzero(data, sizeof(ssl_appdata)); data->flags = flags & (TLS_LISTEN | TLS_CONNECT); data->verify = flags & ~(TLS_LISTEN | TLS_CONNECT); data->loglevel = loglevel; data->cb = cb; strncpyz(data->host, host ? host : "", sizeof(data->host)); SSL_set_app_data(td->socklist[i].ssl, data); SSL_set_info_callback(td->socklist[i].ssl, (void *) ssl_info); /* We set this +1 to be able to report extra long chains properly. * Otherwise, OpenSSL will break the verification reporting about * missing certificates instead. The rest of the fix is in * ssl_verify() */ SSL_set_verify_depth(td->socklist[i].ssl, tls_maxdepth + 1); SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); if (data->flags & TLS_CONNECT) { SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify); ret = SSL_connect(td->socklist[i].ssl); if (!ret) debug0("TLS: connect handshake failed."); } else { if (data->flags & TLS_VERIFYPEER) SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify); else SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify); ret = SSL_accept(td->socklist[i].ssl); if (!ret) debug0("TLS: accept handshake failed"); } err = SSL_get_error(td->socklist[i].ssl, ret); /* Normal condition for async I/O, similar to EAGAIN */ if (ret > 0 || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { debug0("TLS: handshake in progress"); return 0; } if (ERR_peek_error()) debug0("TLS: handshake failed due to the following errors: "); while ((err = ERR_get_error())) debug1("TLS: %s", ERR_error_string(err, NULL)); /* Attempt failed, cleanup and abort */ SSL_shutdown(td->socklist[i].ssl); SSL_free(td->socklist[i].ssl); td->socklist[i].ssl = NULL; nfree(data); return -4; }
int lws_ssl_client_bio_create(struct lws *wsi) { X509_VERIFY_PARAM *param; char hostname[128], *p; const char *alpn_comma = wsi->context->tls.alpn_default; struct alpn_ctx protos; if (lws_hdr_copy(wsi, hostname, sizeof(hostname), _WSI_TOKEN_CLIENT_HOST) <= 0) { lwsl_err("%s: Unable to get hostname\n", __func__); return -1; } /* * remove any :port part on the hostname... necessary for network * connection but typical certificates do not contain it */ p = hostname; while (*p) { if (*p == ':') { *p = '\0'; break; } p++; } wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx); if (!wsi->tls.ssl) return -1; if (wsi->vhost->tls.ssl_info_event_mask) SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { param = SSL_get0_param(wsi->tls.ssl); /* Enable automatic hostname checks */ // X509_VERIFY_PARAM_set_hostflags(param, // X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, hostname, 0); } if (wsi->vhost->tls.alpn) alpn_comma = wsi->vhost->tls.alpn; if (lws_hdr_copy(wsi, hostname, sizeof(hostname), _WSI_TOKEN_CLIENT_ALPN) > 0) alpn_comma = hostname; lwsl_info("%s: %p: client conn sending ALPN list '%s'\n", __func__, wsi, alpn_comma); protos.len = lws_alpn_comma_to_openssl(alpn_comma, protos.data, sizeof(protos.data) - 1); /* with mbedtls, protos is not pointed to after exit from this call */ SSL_set_alpn_select_cb(wsi->tls.ssl, &protos); /* * use server name indication (SNI), if supported, * when establishing connection */ SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback); SSL_set_fd(wsi->tls.ssl, wsi->desc.sockfd); return 0; }
LWS_VISIBLE int lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) { struct lws_context *context = wsi->context; struct lws_vhost *vh; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; #if !defined(USE_WOLFSSL) && !defined(LWS_WITH_MBEDTLS) BIO *bio; #endif char buf[256]; (void)buf; if (!LWS_SSL_ENABLED(wsi->vhost)) return 0; switch (wsi->mode) { case LWSCM_SSL_INIT: case LWSCM_SSL_INIT_RAW: if (wsi->ssl) lwsl_err("%s: leaking ssl\n", __func__); if (accept_fd == LWS_SOCK_INVALID) assert(0); if (context->simultaneous_ssl_restriction && context->simultaneous_ssl >= context->simultaneous_ssl_restriction) { lwsl_notice("unable to deal with SSL connection\n"); return 1; } errno = 0; wsi->ssl = SSL_new(wsi->vhost->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: %d (errno %d)\n", lws_ssl_get_error(wsi, 0), errno); lws_ssl_elaborate_error(); if (accept_fd != LWS_SOCK_INVALID) compatible_close(accept_fd); goto fail; } #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) if (wsi->vhost->ssl_info_event_mask) SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback); #endif if (context->simultaneous_ssl_restriction && ++context->simultaneous_ssl == context->simultaneous_ssl_restriction) /* that was the last allowed SSL connection */ lws_gate_accepts(context, 0); #if defined(LWS_WITH_STATS) context->updated = 1; #endif #if !defined(LWS_WITH_MBEDTLS) SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi); #endif SSL_set_fd(wsi->ssl, accept_fd); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else #if defined(LWS_WITH_MBEDTLS) lws_plat_set_socket_options(wsi->vhost, accept_fd); #else SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #endif /* * we are not accepted yet, but we need to enter ourselves * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ if (wsi->mode == LWSCM_SSL_INIT) wsi->mode = LWSCM_SSL_ACK_PENDING; else wsi->mode = LWSCM_SSL_ACK_PENDING_RAW; if (insert_wsi_socket_into_fds(context, wsi)) { lwsl_err("%s: failed to insert into fds\n", __func__); goto fail; } lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, context->timeout_secs); lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWSCM_SSL_ACK_PENDING: case LWSCM_SSL_ACK_PENDING_RAW: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_err("%s: lws_change_pollfd failed\n", __func__); goto fail; } lws_latency_pre(context, wsi); if (wsi->vhost->allow_non_ssl_on_ssl_port) { n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size, MSG_PEEK); /* * optionally allow non-SSL connect on SSL listening socket * This is disabled by default, if enabled it goes around any * SSL-level access control (eg, client-side certs) so leave * it disabled unless you know it's not a problem for you */ if (n >= 1 && pt->serv_buf[0] >= ' ') { /* * TLS content-type for Handshake is 0x16, and * for ChangeCipherSpec Record, it's 0x14 * * A non-ssl session will start with the HTTP * method in ASCII. If we see it's not a legit * SSL handshake kill the SSL for this * connection and try to handle as a HTTP * connection upgrade directly. */ wsi->use_ssl = 0; SSL_shutdown(wsi->ssl); SSL_free(wsi->ssl); wsi->ssl = NULL; if (lws_check_opt(context->options, LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) wsi->redirect_to_https = 1; goto accepted; } if (!n) /* * connection is gone, or nothing to read * if it's gone, we will timeout on * PENDING_TIMEOUT_SSL_ACCEPT */ break; if (n < 0 && (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK)) { /* * well, we get no way to know ssl or not * so go around again waiting for something * to come and give us a hint, or timeout the * connection. */ m = SSL_ERROR_WANT_READ; goto go_again; } } /* normal SSL connection processing path */ #if defined(LWS_WITH_STATS) if (!wsi->accept_start_us) wsi->accept_start_us = time_in_microseconds(); #endif errno = 0; lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1); n = SSL_accept(wsi->ssl); lws_latency(context, wsi, "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); lwsl_info("SSL_accept says %d\n", n); if (n == 1) goto accepted; m = lws_ssl_get_error(wsi, n); #if defined(LWS_WITH_MBEDTLS) if (m == SSL_ERROR_SYSCALL && errno == 11) m = SSL_ERROR_WANT_READ; #endif if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL) goto failed; go_again: if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__); goto fail; } lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__); goto fail; } break; } failed: lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1); wsi->socket_is_permanently_unusable = 1; lwsl_info("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd, lws_ssl_get_error_string(m, n, buf, sizeof(buf))); lws_ssl_elaborate_error(); goto fail; accepted: lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1); #if defined(LWS_WITH_STATS) lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, time_in_microseconds() - wsi->accept_start_us); wsi->accept_start_us = time_in_microseconds(); #endif /* adapt our vhost to match the SNI SSL_CTX that was chosen */ vh = context->vhost_list; while (vh) { if (!vh->being_destroyed && wsi->ssl && vh->ssl_ctx == SSL_get_SSL_CTX(wsi->ssl)) { lwsl_info("setting wsi to vh %s\n", vh->name); wsi->vhost = vh; break; } vh = vh->vhost_next; } /* OK, we are accepted... give him some time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW) wsi->mode = LWSCM_RAW; else wsi->mode = LWSCM_HTTP_SERVING; #if defined(LWS_WITH_HTTP2) if (lws_h2_configure_if_upgraded(wsi)) goto fail; #endif lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; }
/* * 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; }
janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { janus_ice_component *component = (janus_ice_component *)ice_component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return NULL; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return NULL; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; } janus_dtls_srtp *dtls = g_malloc0(sizeof(janus_dtls_srtp)); if(dtls == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); return NULL; } /* Create SSL context, at last */ dtls->srtp_valid = 0; dtls->ssl = SSL_new(janus_dtls_get_ssl_ctx()); if(!dtls->ssl) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component DTLS SSL session??\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } SSL_set_ex_data(dtls->ssl, 0, dtls); SSL_set_info_callback(dtls->ssl, janus_dtls_callback); dtls->read_bio = BIO_new(BIO_s_mem()); if(!dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating read BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->read_bio, -1); dtls->write_bio = BIO_new(BIO_s_mem()); if(!dtls->write_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating write BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->write_bio, -1); /* The write BIO needs our custom filter, or fragmentation won't work */ dtls->filter_bio = BIO_new(BIO_janus_dtls_filter()); if(!dtls->filter_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating filter BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } /* Chain filter and write BIOs */ BIO_push(dtls->filter_bio, dtls->write_bio); /* Set the filter as the BIO to use for outgoing data */ SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->filter_bio); dtls->dtls_role = role; if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting connect state (DTLS client)\n", handle->handle_id); SSL_set_connect_state(dtls->ssl); } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting accept state (DTLS server)\n", handle->handle_id); SSL_set_accept_state(dtls->ssl); } /* https://code.google.com/p/chromium/issues/detail?id=406458 * Specify an ECDH group for ECDHE ciphers, otherwise they cannot be * negotiated when acting as the server. Use NIST's P-256 which is * commonly supported. */ EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if(ecdh == NULL) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating ECDH group!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); dtls->ready = 0; #ifdef HAVE_SCTP dtls->sctp = NULL; #endif janus_mutex_init(&dtls->srtp_mutex); /* Done */ dtls->dtls_connected = 0; dtls->component = component; return dtls; }
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; }
janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { janus_ice_component *component = (janus_ice_component *)ice_component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return NULL; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return NULL; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; } janus_dtls_srtp *dtls = g_malloc0(sizeof(janus_dtls_srtp)); g_atomic_int_set(&dtls->destroyed, 0); janus_refcount_init(&dtls->ref, janus_dtls_srtp_free); /* Create SSL context, at last */ dtls->srtp_valid = 0; dtls->ssl = SSL_new(ssl_ctx); if(!dtls->ssl) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating DTLS session! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } SSL_set_ex_data(dtls->ssl, 0, dtls); SSL_set_info_callback(dtls->ssl, janus_dtls_callback); dtls->read_bio = BIO_new(BIO_s_mem()); if(!dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating read BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } BIO_set_mem_eof_return(dtls->read_bio, -1); dtls->write_bio = BIO_new(BIO_s_mem()); if(!dtls->write_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating write BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } BIO_set_mem_eof_return(dtls->write_bio, -1); /* The write BIO needs our custom filter, or fragmentation won't work */ dtls->filter_bio = BIO_new(BIO_janus_dtls_filter()); if(!dtls->filter_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating filter BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } /* Chain filter and write BIOs */ BIO_push(dtls->filter_bio, dtls->write_bio); /* Set the filter as the BIO to use for outgoing data */ SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->filter_bio); /* The role may change later, depending on the negotiation */ dtls->dtls_role = role; /* https://code.google.com/p/chromium/issues/detail?id=406458 * Specify an ECDH group for ECDHE ciphers, otherwise they cannot be * negotiated when acting as the server. Use NIST's P-256 which is * commonly supported. */ EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if(ecdh == NULL) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating ECDH group! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_ECDH_USE; SSL_set_options(dtls->ssl, flags); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); #ifdef HAVE_DTLS_SETTIMEOUT guint ms = 100; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting DTLS initial timeout: %u\n", handle->handle_id, ms); DTLSv1_set_initial_timeout_duration(dtls->ssl, ms); #endif dtls->ready = 0; dtls->retransmissions = 0; #ifdef HAVE_SCTP dtls->sctp = NULL; #endif /* Done */ dtls->dtls_connected = 0; dtls->component = component; return dtls; }
/** * Run SSL handshake and store the resulting time value in the * 'time_map'. * * @param time_map where to store the current time */ static void run_ssl (uint32_t *time_map, int time_is_an_illusion) { BIO *s_bio; SSL_CTX *ctx; SSL *ssl; SSL_load_error_strings(); SSL_library_init(); ctx = NULL; if (0 == strcmp("sslv23", protocol)) { verb ("V: using SSLv23_client_method()\n"); ctx = SSL_CTX_new(SSLv23_client_method()); } else if (0 == strcmp("sslv3", protocol)) { verb ("V: using SSLv3_client_method()\n"); ctx = SSL_CTX_new(SSLv3_client_method()); } else if (0 == strcmp("tlsv1", protocol)) { verb ("V: using TLSv1_client_method()\n"); ctx = SSL_CTX_new(TLSv1_client_method()); } else die("Unsupported protocol `%s'\n", protocol); if (ctx == NULL) die("OpenSSL failed to support protocol `%s'\n", protocol); if (ca_racket) { if (1 != SSL_CTX_load_verify_locations(ctx, NULL, certdir)) fprintf(stderr, "SSL_CTX_load_verify_locations failed\n"); } if (NULL == (s_bio = BIO_new_ssl_connect(ctx))) die ("SSL BIO setup failed\n"); BIO_get_ssl(s_bio, &ssl); if (NULL == ssl) die ("SSL setup failed\n"); if (time_is_an_illusion) { SSL_set_info_callback(ssl, openssl_time_callback); } SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if ( (1 != BIO_set_conn_hostname(s_bio, host)) || (1 != BIO_set_conn_port(s_bio, port)) ) die ("Failed to initialize connection to `%s:%s'\n", host, port); if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE)) die ("BIO_new_fp returned error, possibly: %s", strerror(errno)); // This should run in seccomp // eg: prctl(PR_SET_SECCOMP, 1); if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later? die ("SSL connection failed\n"); if (1 != BIO_do_handshake(s_bio)) die ("SSL handshake failed\n"); // Verify the peer certificate against the CA certs on the local system if (ca_racket) { inspect_key (ssl, host); } else { verb ("V: Certificate verification skipped!\n"); } check_key_length(ssl); // from /usr/include/openssl/ssl3.h // ssl->s3->server_random is an unsigned char of 32 bits memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t)); SSL_free(ssl); SSL_CTX_free(ctx); }