int ircd_client_init_ssl(struct ircd_client* const client) { if (ssl_init(&client->ssl_ctx) != 0) return -1; // We are a server (void) ssl_set_endpoint(&client->ssl_ctx, SSL_IS_SERVER); // Tell the library how to send and receive data to the client (void) ssl_set_bio(&client->ssl_ctx, net_recv, &client->fd, net_send, &client->fd); // Tell the library how to generate random data for the client (e.g. session ticket encryption key) (void) ssl_set_rng(&client->ssl_ctx, hmac_drbg_random, &ircd_ssl_hmac_drbg_ctx); // Normally DHE- ciphersuites are enabled anyway, but do so with a stronger prime (void) ssl_set_dh_param_ctx(&client->ssl_ctx, &ircd_ssl_dh_ctx); // To request (but not require) a certificate from the client (void) ssl_set_authmode(&client->ssl_ctx, SSL_VERIFY_OPTIONAL); //(void) ssl_set_ca_chain(&client->ssl_ctx, &ircd_ssl_ca_certificates, NULL, NULL); (void) ssl_set_ca_chain(&client->ssl_ctx, &ircd_ssl_certificate, NULL, NULL); // To test if the client supports RC4 (bad, in violation of TLS standards; see RFC 7465) (void) ssl_set_arc4_support(&client->ssl_ctx, SSL_ARC4_ENABLED); // To test if the client supports SNI (good) (void) ssl_set_sni(&client->ssl_ctx, ircd_server_ssl_sni_cb, (void*) client); // To test if the client supports Session Tickets (concerning) (void) ssl_set_session_tickets(&client->ssl_ctx, SSL_SESSION_TICKETS_ENABLED); (void) ssl_set_session_ticket_lifetime(&client->ssl_ctx, 300); // We could do this in the SNI callback, but that would require all clients to support SNI (void) ssl_set_own_cert(&client->ssl_ctx, &ircd_ssl_certificate, &ircd_ssl_private_key); #ifdef POLARSSL_SSL_CIPHERSUITES_CB // This is an addition of mine to the library - see the patch in patches/ (void) ssl_set_cs_cb(&client->ssl_ctx, ircd_server_ssl_cs_cb, (void*) client); #endif #ifdef POLARSSL_SSL_TICKETS_CB // This is an addition of mine to the library - see the patch in patches/ (void) ssl_set_tick_cb(&client->ssl_ctx, ircd_server_ssl_tick_cb, (void*) client); #endif return 0; }
/* Accept incoming SSL connection */ int ssl_accept(t_ssl_accept_data *sad) { int result, handshake; struct timeval timer; time_t start_time; if (ssl_init(sad->context) != 0) { return -1; } ssl_set_endpoint(sad->context, SSL_IS_SERVER); if (sad->ca_certificate == NULL) { ssl_set_authmode(sad->context, SSL_VERIFY_NONE); } else { ssl_set_authmode(sad->context, SSL_VERIFY_REQUIRED); ssl_set_ca_chain(sad->context, sad->ca_certificate, sad->ca_crl, NULL); sad->timeout = HS_TIMEOUT_CERT_SELECT; } ssl_set_min_version(sad->context, SSL_MAJOR_VERSION_3, sad->min_ssl_version); ssl_set_renegotiation(sad->context, SSL_RENEGOTIATION_DISABLED); ssl_set_rng(sad->context, ssl_random, &ctr_drbg); #ifdef ENABLE_DEBUG ssl_set_dbg(sad->context, ssl_debug, stderr); #endif ssl_set_bio(sad->context, net_recv, sad->client_fd, net_send, sad->client_fd); ssl_set_sni(sad->context, sni_callback, sad); ssl_set_session_cache(sad->context, ssl_get_cache, &cache, ssl_set_cache, &cache); #if POLARSSL_VERSION_NUMBER >= 0x01020700 ssl_set_ciphersuites_for_version(sad->context, ciphersuites, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0); ssl_set_ciphersuites_for_version(sad->context, ciphersuites, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1); ssl_set_ciphersuites_for_version(sad->context, ciphersuites + 1, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_2); ssl_set_ciphersuites_for_version(sad->context, ciphersuites_tls12, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3); #else int skip = 0; if ((sad->min_ssl_version >= SSL_MINOR_VERSION_2) && (ciphersuites[0] == TLS_RSA_WITH_RC4_128_SHA)) { skip = 1; } ssl_set_ciphersuites(sad->context, ciphersuites + skip); #endif ssl_set_own_cert(sad->context, sad->certificate, sad->private_key); if (sad->dh_size == 1024) { ssl_set_dh_param(sad->context, POLARSSL_DHM_RFC5114_MODP_1024_P, POLARSSL_DHM_RFC5114_MODP_1024_G); } else if (sad->dh_size == 2048) { ssl_set_dh_param(sad->context, POLARSSL_DHM_RFC5114_MODP_2048_P, POLARSSL_DHM_RFC5114_MODP_2048_G); } else if (sad->dh_size == 4096) { ssl_set_dh_param(sad->context, dhm_4096_P, dhm_4096_G); } timer.tv_sec = sad->timeout; timer.tv_usec = 0; setsockopt(*(sad->client_fd), SOL_SOCKET, SO_RCVTIMEO, (void*)&timer, sizeof(struct timeval)); start_time = time(NULL); result = 0; while ((handshake = ssl_handshake(sad->context)) != 0) { if ((handshake != POLARSSL_ERR_NET_WANT_READ) && (handshake != POLARSSL_ERR_NET_WANT_WRITE)) { ssl_free(sad->context); sad->context = NULL; result = -1; break; } if (time(NULL) - start_time >= sad->timeout) { ssl_free(sad->context); sad->context = NULL; result = -2; break; } } timer.tv_sec = 0; timer.tv_usec = 0; setsockopt(*(sad->client_fd), SOL_SOCKET, SO_RCVTIMEO, (void*)&timer, sizeof(struct timeval)); return result; }
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) { ngx_ssl_connection_t *sc; ngx_ssl_conn_t *ssl_ctx; ngx_ssl_session_cache_t *cache; int sslerr; sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t)); if (sc == NULL) { return NGX_ERROR; } sc->buffer = ((flags % NGX_SSL_BUFFER) != 0); /* Allocate the PolarSSL context */ ssl_ctx = ngx_pcalloc(c->pool, sizeof(ngx_ssl_conn_t)); if (sc == NULL) { return NGX_ERROR; } /* * Initialize this PolarSSL context * * Note: We also setup the options traditionally set in ngx_ssl_create * here since each ssl_ctx is unique to each fd. */ sslerr = ssl_init(ssl_ctx); if (sslerr != 0) { ngx_mbedtls_error(NGX_LOG_ALERT, ssl->log, 0, sslerr, "ssl_init failed"); return NGX_ERROR; } if (flags & NGX_SSL_CLIENT) { ssl_set_endpoint(ssl_ctx, SSL_IS_CLIENT); if (ssl->have_own_cert) { ssl_set_own_cert(ssl_ctx, &ssl->own_cert, &ssl->own_key); } } else { ssl_set_endpoint(ssl_ctx, SSL_IS_SERVER); ssl_set_own_cert(ssl_ctx, &ssl->own_cert, &ssl->own_key); } if (ssl->have_ca_cert) { if (ssl->have_ca_crl) { ssl_set_ca_chain(ssl_ctx, &ssl->ca_cert, &ssl->ca_crl, NULL); } else { ssl_set_ca_chain(ssl_ctx, &ssl->ca_cert, NULL, NULL); } /* * ngx_event_openssl has the callback rigged to allow the handshake * to continue even if verification fails. We shall do the same. */ ssl_set_authmode(ssl_ctx, SSL_VERIFY_OPTIONAL); } else { ssl_set_authmode(ssl_ctx, SSL_VERIFY_NONE); } ssl_set_min_version(ssl_ctx, SSL_MAJOR_VERSION_3, ssl->minor_min); ssl_set_max_version(ssl_ctx, SSL_MAJOR_VERSION_3, ssl->minor_max); ssl_set_renegotiation(ssl_ctx, SSL_RENEGOTIATION_ENABLED); ssl_legacy_renegotiation(ssl_ctx, SSL_LEGACY_NO_RENEGOTIATION); ssl_set_rng(ssl_ctx, ngx_mbedtls_rng, &ngx_ctr_drbg); ssl_set_bio(ssl_ctx, net_recv, &c->fd, net_send, &c->fd); ssl_set_dh_param_ctx(ssl_ctx, &ssl->dhm_ctx); ssl_set_ciphersuites(ssl_ctx, ssl->ciphersuites); if (ssl->builtin_session_cache == NGX_SSL_NONE_SCACHE) { ssl_set_session_cache(ssl_ctx, ngx_mbedtls_get_cache, NULL, ngx_mbedtls_set_cache, NULL); } if (ssl->builtin_session_cache != NGX_SSL_NO_SCACHE) { cache = ssl->cache_shm_zone->data; cache->ttl = ssl->cache_ttl; ssl_set_session_cache(ssl_ctx, ngx_mbedtls_get_cache, ssl->cache_shm_zone, ngx_mbedtls_set_cache, ssl->cache_shm_zone); } if (ssl->sni_fn) { ssl_set_sni(ssl_ctx, ssl->sni_fn, c); } /* All done, the connection is good to go now */ sc->connection = ssl_ctx; c->ssl = sc; return NGX_OK; }