BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) { rdpTsg* tsg = tsg_new(transport); tsg->transport = transport; transport->tsg = tsg; transport->SplitInputOutput = TRUE; if (transport->TlsIn == NULL) transport->TlsIn = tls_new(transport->settings); transport->TlsIn->sockfd = transport->TcpIn->sockfd; if (transport->TlsOut == NULL) transport->TlsOut = tls_new(transport->settings); transport->TlsOut->sockfd = transport->TcpOut->sockfd; if (tls_connect(transport->TlsIn) != TRUE) return FALSE; if (tls_connect(transport->TlsOut) != TRUE) return FALSE; if (!tsg_connect(tsg, hostname, port)) return FALSE; return TRUE; }
boolean transport_tsg_connect(rdpTransport* transport, const char* hostname, uint16 port) { rdpTsg* tsg = tsg_new(transport); tsg->transport = transport; transport->tsg = tsg; if (transport->tls_in == NULL) transport->tls_in = tls_new(transport->settings); transport->tls_in->sockfd = transport->tcp_in->sockfd; if (transport->tls_out == NULL) transport->tls_out = tls_new(transport->settings); transport->tls_out->sockfd = transport->tcp_out->sockfd; if (tls_connect(transport->tls_in) != true) return false; if (tls_connect(transport->tls_out) != true) return false; if (!tsg_connect(tsg, hostname, port)) return false; return true; }
BOOL transport_connect_tls(rdpTransport* transport) { if (transport->layer == TRANSPORT_LAYER_TSG) { transport->TsgTls = tls_new(transport->settings); transport->TsgTls->methods = BIO_s_tsg(); transport->TsgTls->tsg = (void*) transport->tsg; transport->layer = TRANSPORT_LAYER_TSG_TLS; if (tls_connect(transport->TsgTls) != TRUE) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; tls_free(transport->TsgTls); transport->TsgTls = NULL; return FALSE; } return TRUE; } if (transport->TlsIn == NULL) transport->TlsIn = tls_new(transport->settings); if (transport->TlsOut == NULL) transport->TlsOut = transport->TlsIn; transport->layer = TRANSPORT_LAYER_TLS; transport->TlsIn->sockfd = transport->TcpIn->sockfd; if (tls_connect(transport->TlsIn) != TRUE) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; tls_free(transport->TlsIn); if (transport->TlsIn == transport->TlsOut) transport->TlsIn = transport->TlsOut = NULL; else transport->TlsIn = NULL; return FALSE; } return TRUE; }
boolean transport_connect_nla(rdpTransport* transport) { if (transport->tls == NULL) transport->tls = tls_new(); transport->layer = TRANSPORT_LAYER_TLS; transport->tls->sockfd = transport->tcp->sockfd; if (tls_connect(transport->tls) != True) return False; /* Network Level Authentication */ if (transport->settings->authentication != True) return True; if (transport->credssp == NULL) transport->credssp = credssp_new(transport); if (credssp_authenticate(transport->credssp) < 0) { printf("Authentication failure, check credentials.\n" "If credentials are valid, the NTLMSSP implementation may be to blame.\n"); credssp_free(transport->credssp); return False; } credssp_free(transport->credssp); return True; }
/** callback for tls_ct_q_flush(). * * @param *ssl - ssl context. * @param *err - error reason (set on exit). * @return >0 on success (bytes written), <=0 on ssl error (should be * handled outside). * WARNING: the ssl context must have the wbio and rbio previously set! */ static int ssl_flush(void* tcp_c, void* error, const void* buf, unsigned size) { int n; int ssl_error; struct tls_extra_data* tls_c; SSL* ssl; tls_c = ((struct tcp_connection*)tcp_c)->extra_data; ssl = tls_c->ssl; ssl_error = SSL_ERROR_NONE; if (unlikely(tls_c->state == S_TLS_CONNECTING)) { n = tls_connect(tcp_c, &ssl_error); if (unlikely(n>=1)) { n = SSL_write(ssl, buf, size); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } } else if (unlikely(tls_c->state == S_TLS_ACCEPTING)) { n = tls_accept(tcp_c, &ssl_error); if (unlikely(n>=1)) { n = SSL_write(ssl, buf, size); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } } else { n = SSL_write(ssl, buf, size); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } *(long*)error = ssl_error; return n; }
BOOL transport_connect_tls(rdpTransport* transport) { if (transport->layer == TRANSPORT_LAYER_TSG) return TRUE; if (transport->TlsIn == NULL) transport->TlsIn = tls_new(transport->settings); if (transport->TlsOut == NULL) transport->TlsOut = transport->TlsIn; transport->layer = TRANSPORT_LAYER_TLS; transport->TlsIn->sockfd = transport->TcpIn->sockfd; if (tls_connect(transport->TlsIn) != TRUE) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; tls_free(transport->TlsIn); if (transport->TlsIn == transport->TlsOut) transport->TlsIn = transport->TlsOut = NULL; else transport->TlsIn = NULL; return FALSE; } return TRUE; }
/* * called before tls_read, the this function should attempt tls_accept or * tls_connect depending on the state of the connection, if this function * does not transit a connection into S_CONN_OK then tcp layer would not * call tcp_read */ int tls_fix_read_conn(struct tcp_connection *c) { /* * no lock acquired */ int ret; ret = 0; /* * We have to acquire the lock before testing c->state, otherwise a * writer could modify the structure if it gets preempted and has * something to write */ lock_get(&c->write_lock); if ( c->proto_flags & F_TLS_DO_ACCEPT ) { ret = tls_update_fd(c, c->fd); if (!ret) ret = tls_accept(c, NULL); } else if ( c->proto_flags & F_TLS_DO_CONNECT ) { ret = tls_update_fd(c, c->fd); if (!ret) ret = tls_connect(c, NULL); } lock_release(&c->write_lock); return ret; }
BOOL rdg_tls_out_connect(rdpRdg* rdg, const char* hostname, UINT16 port, int timeout) { int sockfd = 0; int status = 0; BIO* socketBio = NULL; BIO* bufferedBio = NULL; rdpSettings* settings = rdg->settings; assert(hostname != NULL); sockfd = freerdp_tcp_connect(rdg->context, settings, settings->GatewayHostname, settings->GatewayPort, timeout); if (sockfd < 1) { return FALSE; } socketBio = BIO_new(BIO_s_simple_socket()); if (!socketBio) { closesocket(sockfd); return FALSE; } BIO_set_fd(socketBio, sockfd, BIO_CLOSE); bufferedBio = BIO_new(BIO_s_buffered_socket()); if (!bufferedBio) { BIO_free(socketBio); return FALSE; } bufferedBio = BIO_push(bufferedBio, socketBio); status = BIO_set_nonblock(bufferedBio, TRUE); if (!status) { BIO_free_all(bufferedBio); return FALSE; } rdg->tlsOut->hostname = settings->GatewayHostname; rdg->tlsOut->port = settings->GatewayPort; rdg->tlsOut->isGatewayTransport = TRUE; status = tls_connect(rdg->tlsOut, bufferedBio); if (status < 1) { return FALSE; } return TRUE; }
int main(int argc, char *argv[]) { struct tls_config *conf; struct tls *ctx; struct tls_cert_info *cert; int res; const char *host; if (argc < 2) errx(1, "give host as arg\n"); host = argv[1]; res = tls_init(); if (res < 0) errx(1, "tls_init"); conf = tls_config_new(); if (!conf) errx(1, "tls_config_new"); tls_config_set_protocols(conf, TLS_PROTOCOLS_ALL); tls_config_set_ciphers(conf, "fast"); ctx = tls_client(); if (!ctx) errx(1, "tls_client"); res = tls_configure(ctx, conf); if (res < 0) errx(1, "tls_configure: %s", tls_error(ctx)); res = tls_connect(ctx, host, "443"); if (res < 0) errx(1, "tls_connect: %s", tls_error(ctx)); printf("connect ok\n"); res = tls_get_peer_cert(ctx, &cert); if (res < 0) errx(1, "tls_get_peer_cert: %s", tls_error(ctx)); tls_close(ctx); tls_free(ctx); tls_config_free(conf); printf(" CN='%s'\n", cert->subject.common_name); printf(" C='%s'\n", cert->subject.country_name); printf(" ST='%s'\n", cert->subject.state_or_province_name); printf(" L='%s'\n", cert->subject.locality_name); printf(" S='%s'\n", cert->subject.street_address); printf(" O='%s'\n", cert->subject.organization_name); printf(" OU='%s'\n", cert->subject.organizational_unit_name); tls_cert_free(cert); return 0; }
BOOL transport_connect_tls(rdpTransport* transport) { int tlsStatus; rdpTls* tls = NULL; rdpContext* context = transport->context; rdpSettings* settings = transport->settings; if (!(tls = tls_new(settings))) return FALSE; transport->tls = tls; if (transport->GatewayEnabled) transport->layer = TRANSPORT_LAYER_TSG_TLS; else transport->layer = TRANSPORT_LAYER_TLS; tls->hostname = settings->ServerHostname; tls->port = settings->ServerPort; if (tls->port == 0) tls->port = 3389; tls->isGatewayTransport = FALSE; tlsStatus = tls_connect(tls, transport->frontBio); if (tlsStatus < 1) { if (tlsStatus < 0) { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); } else { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); } return FALSE; } transport->frontBio = tls->bio; BIO_callback_ctrl(tls->bio, BIO_CTRL_SET_CALLBACK, (bio_info_cb*) transport_ssl_cb); SSL_set_app_data(tls->ssl, transport); if (!transport->frontBio) { WLog_ERR(TAG, "unable to prepend a filtering TLS bio"); return FALSE; } return TRUE; }
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) { rdpTsg* tsg = tsg_new(transport); tsg->transport = transport; transport->tsg = tsg; transport->SplitInputOutput = TRUE; if (!transport->TlsIn) transport->TlsIn = tls_new(transport->settings); transport->TlsIn->sockfd = transport->TcpIn->sockfd; transport->TlsIn->hostname = transport->settings->GatewayHostname; transport->TlsIn->port = transport->settings->GatewayPort; if (transport->TlsIn->port == 0) transport->TlsIn->port = 443; if (!transport->TlsOut) transport->TlsOut = tls_new(transport->settings); transport->TlsOut->sockfd = transport->TcpOut->sockfd; transport->TlsOut->hostname = transport->settings->GatewayHostname; transport->TlsOut->port = transport->settings->GatewayPort; if (transport->TlsOut->port == 0) transport->TlsOut->port = 443; if (!tls_connect(transport->TlsIn)) return FALSE; if (!tls_connect(transport->TlsOut)) return FALSE; if (!tsg_connect(tsg, hostname, port)) return FALSE; return TRUE; }
tbool transport_connect_tls(rdpTransport* transport) { if (transport->tls == NULL) transport->tls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TLS; transport->tls->sockfd = transport->tcp->sockfd; if (tls_connect(transport->tls) == false) return false; return true; }
boolean transport_connect_tls(rdpTransport* transport) { if (transport->tls == NULL) transport->tls = tls_new(); transport->layer = TRANSPORT_LAYER_TLS; transport->tls->sockfd = transport->tcp->sockfd; if (tls_connect(transport->tls) != True) return False; return True; }
void net_connect_cb(uv_connect_t *conn, int stat) { net_t * net = (net_t *) conn->data; err_t err; int read; if (stat < 0) { err = uv_last_error(net->loop); if (net->error_cb) { net->error_cb(net, err, (char *) uv_strerror(err)); } else { printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); net_free(net); } return; } /* * change the `connected` state */ net->connected = 1; /* * read buffers via uv */ uv_read_start((uv_stream_t *) net->handle, net_alloc, net_read); /* * call `conn_cb`, the tcp connection has been * established in user-land. */ if (net->use_ssl == NOT_SSL && net->conn_cb != NULL) { net->conn_cb(net); } /* * Handle TLS Partial */ if (net->use_ssl == USE_SSL && tls_connect(net->tls) == NET_OK) { read = 0; do { read = tls_bio_read(net->tls, 0); if (read > 0) { uv_write_t req; uv_buf_t uvbuf = uv_buf_init(net->tls->buf, read); uv_write(&req, (uv_stream_t*)net->handle, &uvbuf, 1, NULL); } } while (read > 0); } }
static bool estab_handler(int *err, bool active, void *arg) { struct tls_conn *tc = arg; DEBUG_INFO("tcp established (active=%u)\n", active); if (!active) return true; tc->active = true; *err = tls_connect(tc); return true; }
boolean transport_connect_nla(rdpTransport* transport) { freerdp* instance; rdpSettings* settings; if (transport->tls == NULL) transport->tls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TLS; transport->tls->sockfd = transport->tcp->sockfd; if (tls_connect(transport->tls) != true) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; tls_free(transport->tls); transport->tls = NULL; return false; } /* Network Level Authentication */ if (transport->settings->authentication != true) return true; settings = transport->settings; instance = (freerdp*) settings->instance; if (transport->credssp == NULL) transport->credssp = credssp_new(instance, transport->tls, settings); if (credssp_authenticate(transport->credssp) < 0) { if (!connectErrorCode) connectErrorCode = AUTHENTICATIONERROR; printf("Authentication failure, check credentials.\n" "If credentials are valid, the NTLMSSP implementation may be to blame.\n"); credssp_free(transport->credssp); return false; } credssp_free(transport->credssp); return true; }
VMINT vm_tls_connect(VMINT res_id, vm_sockaddr_ex_struct * faddr) { kal_int32 ret; vm_tls_context_t * ctx_p = NULL; sockaddr_struct int_faddr = {0}; MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_S, 3, __LINE__); if (NULL == faddr) { MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E1, 3, __LINE__); return VM_TLS_RET_BASE -3; } ctx_p = vm_tls_get_ctx_by_res(res_id); if (NULL == ctx_p) { MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E2, 3, __LINE__); return VM_TLS_RET_BASE -2; } int_faddr.addr_len = faddr->addr_len; memcpy(int_faddr.addr, faddr->addr, int_faddr.addr_len); int_faddr.port = faddr->port; int_faddr.sock_type = faddr->sock_type; MMI_TRACE(TRACE_GROUP_8, TRC_MRE_DLS_LOG, int_faddr.addr_len, int_faddr.addr[0], int_faddr.addr[1], int_faddr.addr[2], int_faddr.addr[3], int_faddr.port, 3, int_faddr.sock_type); ret = tls_connect(ctx_p->soc_id, &int_faddr); if (TLS_ERR_NONE != ret) { MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E3, 3, ret); return ret; } MMI_TRACE(TRACE_GROUP_8, TRC_MRE_SSL_E, 3, __LINE__); return ret; }
//***************************************************************************** // //! Main //! //! \param none //! //! \return None //! //***************************************************************************** void main() { long lRetVal = -1; // // Initialize board configuration // BoardInit(); PinMuxConfig(); //Initialize GPIO interrupt GPIOIntInit(); //Initialize Systick interrupt SystickIntInit(); //Initialize Uart interrupt UART1IntInit(); //Initialize SPI SPIInit(); //Initalize Adafruit Adafruit_Init(); InitTerm(); //Connect the CC3200 to the local access point lRetVal = connectToAccessPoint(); //Set time so that encryption can be used lRetVal = set_time(); if(lRetVal < 0) { UART_PRINT("Unable to set time in the device"); LOOP_FOREVER(); } //Connect to the website with TLS encryption lRetVal = tls_connect(); if(lRetVal < 0) { ERR_PRINT(lRetVal); } //remote calls sendMessage() which calls http_post() which requires the return value from tls_connect() remote(lRetVal); //http_post(lRetVal); sl_Stop(SL_STOP_TIMEOUT); LOOP_FOREVER(); }
boolean transport_connect_tls(rdpTransport* transport) { if (transport->tls == NULL) transport->tls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TLS; transport->tls->sockfd = transport->tcp->sockfd; if (tls_connect(transport->tls) != true) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; tls_free(transport->tls); transport->tls = NULL; return false; } return true; }
/* * called before tls_read, the this function should attempt tls_accept or * tls_connect depending on the state of the connection, if this function * does not transit a connection into S_CONN_OK then tcp layer would not * call tcp_read */ int tls_fix_read_conn(struct tcp_connection *c) { /* * no lock acquired */ int ret; ret = 0; /* * We have to acquire the lock before testing c->state, otherwise a * writer could modify the structure if it gets preempted and has * something to write */ lock_get(&c->write_lock); switch (c->state) { case S_CONN_ACCEPT: ret = tls_update_fd(c, c->fd); if (!ret) ret = tls_accept(c, NULL); break; case S_CONN_CONNECT: ret = tls_update_fd(c, c->fd); if (!ret) ret = tls_connect(c, NULL); break; default: /* fall through */ break; } lock_release(&c->write_lock); return ret; }
/* * fixme: probably does not work correctly */ size_t tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, size_t len) { #define MAX_SSL_RETRIES 32 int written, n; int timeout, retries; struct pollfd pf; pf.fd = fd; written = 0; retries = 0; if (c->state!=S_CONN_OK) { LM_ERR("TLS broken connection\n"); goto error; } lock_get(&c->write_lock); if (tls_update_fd(c, fd) < 0) goto error; timeout = tls_send_timeout; again: n = 0; pf.events = 0; if ( c->proto_flags & F_TLS_DO_ACCEPT ) { if (tls_accept(c, &(pf.events)) < 0) goto error; timeout = tls_handshake_timeout; } else if ( c->proto_flags & F_TLS_DO_CONNECT ) { if (tls_connect(c, &(pf.events)) < 0) goto error; timeout = tls_handshake_timeout; } else { n = tls_write(c, fd, buf, len, &(pf.events)); timeout = tls_send_timeout; } if (n < 0) { LM_ERR("TLS failed to send data\n"); goto error; } /* nothing happens */ if (n==0) { retries++; /* avoid looping */ if (retries==MAX_SSL_RETRIES) { LM_ERR("too many retries with no operation\n"); goto error; } } else { /* reset the retries if we succeded in doing something*/ retries = 0; } written += n; if (n < len) { /* * partial write */ buf += n; len -= n; } else { /* * successful full write */ lock_release(&c->write_lock); return written; } if (pf.events == 0) pf.events = POLLOUT; poll_loop: while (1) { n = poll(&pf, 1, timeout); if (n < 0) { if (errno == EINTR) continue; /* signal, ignore */ else if (errno != EAGAIN && errno != EWOULDBLOCK) { LM_ERR("TLS poll failed: %s [%d]\n",strerror(errno), errno); goto error; } else goto poll_loop; } else if (n == 0) { /* * timeout */ LM_ERR("TLS send timeout (%d)\n", timeout); goto error; } if (pf.revents & POLLOUT || pf.revents & POLLIN) { /* * we can read or write again */ goto again; } else if (pf.revents & (POLLERR | POLLHUP | POLLNVAL)) { LM_ERR("TLS bad poll flags %x\n",pf.revents); goto error; } /* * if POLLPRI or other non-harmful events happened, continue ( * although poll should never signal them since we're not * interested in them => we should never reach this point) */ } error: lock_release(&c->write_lock); return -1; }
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) { rdpTsg* tsg; int tls_status; freerdp* instance; rdpContext* context; rdpSettings *settings = transport->settings; instance = (freerdp*) transport->settings->instance; context = instance->context; tsg = tsg_new(transport); if (!tsg) return FALSE; tsg->transport = transport; transport->tsg = tsg; transport->SplitInputOutput = TRUE; if (!transport->TlsIn) { transport->TlsIn = tls_new(settings); if (!transport->TlsIn) return FALSE; } if (!transport->TlsOut) { transport->TlsOut = tls_new(settings); if (!transport->TlsOut) return FALSE; } /* put a decent default value for gateway port */ if (!settings->GatewayPort) settings->GatewayPort = 443; transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname; transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort; transport->TlsIn->isGatewayTransport = TRUE; tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio); if (tls_status < 1) { if (tls_status < 0) { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); } else { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); } return FALSE; } transport->TlsOut->isGatewayTransport = TRUE; tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio); if (tls_status < 1) { if (tls_status < 0) { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); } else { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); } return FALSE; } if (!tsg_connect(tsg, hostname, port)) return FALSE; transport->frontBio = BIO_new(BIO_s_tsg()); transport->frontBio->ptr = tsg; return TRUE; }
BOOL transport_connect_tls(rdpTransport* transport) { rdpSettings *settings = transport->settings; rdpTls *targetTls; BIO *targetBio; int tls_status; freerdp* instance; rdpContext* context; instance = (freerdp*) transport->settings->instance; context = instance->context; if (transport->layer == TRANSPORT_LAYER_TSG) { transport->TsgTls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TSG_TLS; targetTls = transport->TsgTls; targetBio = transport->frontBio; } else { if (!transport->TlsIn) transport->TlsIn = tls_new(settings); if (!transport->TlsOut) transport->TlsOut = transport->TlsIn; targetTls = transport->TlsIn; targetBio = transport->TcpIn->bufferedBio; transport->layer = TRANSPORT_LAYER_TLS; } targetTls->hostname = settings->ServerHostname; targetTls->port = settings->ServerPort; if (targetTls->port == 0) targetTls->port = 3389; targetTls->isGatewayTransport = FALSE; tls_status = tls_connect(targetTls, targetBio); if (tls_status < 1) { if (tls_status < 0) { if (!connectErrorCode) connectErrorCode = TLSCONNECTERROR; if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); } else { if (!freerdp_get_last_error(context)) freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); } return FALSE; } transport->frontBio = targetTls->bio; if (!transport->frontBio) { fprintf(stderr, "%s: unable to prepend a filtering TLS bio", __FUNCTION__); return FALSE; } return TRUE; }
int main(int argc, char *argv[]) { struct tls_config *conf; struct tls *ctx, *ocsp; struct tls_cert *cert; int res; const char *host; char buf[256]; if (argc < 2) errx(1, "give host as arg\n"); host = argv[1]; #ifdef USUAL_LIBSSL_FOR_TLS printf("libssl: %s\n", SSLeay_version(SSLEAY_VERSION)); #endif res = tls_init(); if (res < 0) errx(1, "tls_init"); conf = tls_config_new(); if (!conf) errx(1, "tls_config_new"); tls_config_set_protocols(conf, TLS_PROTOCOLS_ALL); tls_config_set_ciphers(conf, "fast"); ctx = tls_client(); if (!ctx) errx(1, "tls_client"); res = tls_configure(ctx, conf); if (res < 0) errx(1, "tls_configure: %s", tls_error(ctx)); res = tls_connect(ctx, host, "443"); if (res < 0) errx(1, "tls_connect: %s", tls_error(ctx)); res = tls_handshake(ctx); if (res < 0) errx(1, "tls_handshake: %s", tls_error(ctx)); res = tls_get_peer_cert(ctx, &cert, NULL); if (res < 0) errx(1, "tls_get_peer_cert: %s", tls_error(ctx)); tls_get_connection_info(ctx, buf, sizeof buf); printf("Connection: '%s'\n", buf); printf(" CN='%s'\n", cert->subject.common_name); printf(" C='%s'\n", cert->subject.country_name); printf(" ST='%s'\n", cert->subject.state_or_province_name); printf(" L='%s'\n", cert->subject.locality_name); printf(" S='%s'\n", cert->subject.street_address); printf(" O='%s'\n", cert->subject.organization_name); printf(" OU='%s'\n", cert->subject.organizational_unit_name); show_ocsp_info("OCSP stapling", ctx); ocsp = NULL; res = tls_ocsp_check_peer(&ocsp, NULL, ctx); if (ocsp) { show_ocsp_info("OCSP responder", ocsp); tls_free(ocsp); } else if (res == TLS_NO_OCSP) { printf("OCSP responder: No OCSP support in libtls\n"); } if (0) test_context(ctx); tls_close(ctx); tls_free(ctx); tls_config_free(conf); tls_cert_free(cert); return 0; }
/** tls read. * Each modification of ssl data structures has to be protected, another process * might ask for the same connection and attempt write to it which would * result in updating the ssl structures. * WARNING: must be called whic c->write_lock _unlocked_. * @param c - tcp connection pointer. The following flags might be set: * @param flags - value/result: * input: RD_CONN_FORCE_EOF - force EOF after the first * successful read (bytes_read >=0 ) * output: RD_CONN_SHORT_READ if the read exhausted * all the bytes in the socket read buffer. * RD_CONN_EOF if EOF detected (0 bytes read) * or forced via RD_CONN_FORCE_EOF. * RD_CONN_REPEAT_READ if this function should * be called again (e.g. has some data * buffered internally that didn't fit in * tcp_req). * Note: RD_CONN_SHORT_READ & RD_CONN_EOF should be cleared * before calling this function when there is new * data (e.g. POLLIN), but not if the called is * retried because of RD_CONN_REPEAT_READ and there * is no information about the socket having more * read data available. * @return bytes decrypted on success, -1 on error (it also sets some * tcp connection flags and might set c->state and r->error on * EOF or error). */ int tls_read_f(struct tcp_connection* c, int* flags) { struct tcp_req* r; int bytes_free, bytes_read, read_size, ssl_error, ssl_read; SSL* ssl; unsigned char rd_buf[TLS_RD_MBUF_SZ]; unsigned char wr_buf[TLS_WR_MBUF_SZ]; struct tls_mbuf rd, wr; struct tls_extra_data* tls_c; struct tls_rd_buf* enc_rd_buf; int n, flush_flags; char* err_src; int x; int tls_dbg; TLS_RD_TRACE("(%p, %p (%d)) start (%s -> %s:%d*)\n", c, flags, *flags, su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)), ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port); ssl_read = 0; r = &c->req; enc_rd_buf = 0; *flags &= ~RD_CONN_REPEAT_READ; if (unlikely(tls_fix_connection(c) < 0)) { TLS_RD_TRACE("(%p, %p) end: tls_fix_connection failed =>" " immediate error exit\n", c, flags); return -1; } /* here it's safe to use c->extra_data in read-only mode. If it's != 0 is changed only on destroy. It's not possible to have parallel reads.*/ tls_c = c->extra_data; bytes_free = c->req.b_size - (int)(r->pos - r->buf); if (unlikely(bytes_free == 0)) { ERR("Buffer overrun, dropping\n"); r->error = TCP_REQ_OVERRUN; return -1; } redo_read: /* if data queued from a previous read(), use it (don't perform * a real read()). */ if (unlikely(tls_c->enc_rd_buf)) { /* use queued data */ /* safe to use without locks, because only read changes it and there can't be parallel reads on the same connection */ enc_rd_buf = tls_c->enc_rd_buf; tls_c->enc_rd_buf = 0; TLS_RD_TRACE("(%p, %p) using queued data (%p: %p %d bytes)\n", c, flags, enc_rd_buf, enc_rd_buf->buf + enc_rd_buf->pos, enc_rd_buf->size - enc_rd_buf->pos); tls_mbuf_init(&rd, enc_rd_buf->buf + enc_rd_buf->pos, enc_rd_buf->size - enc_rd_buf->pos); rd.used = enc_rd_buf->size - enc_rd_buf->pos; } else { /* if we were using using queued data before, free & reset the the queued read data before performing the real read() */ if (unlikely(enc_rd_buf)) { TLS_RD_TRACE("(%p, %p) reset prev. used enc_rd_buf (%p)\n", c, flags, enc_rd_buf); shm_free(enc_rd_buf); enc_rd_buf = 0; } /* real read() */ tls_mbuf_init(&rd, rd_buf, sizeof(rd_buf)); /* read() only if no previously detected EOF, or previous short read (which means the socket buffer was emptied) */ if (likely(!(*flags & (RD_CONN_EOF|RD_CONN_SHORT_READ)))) { /* don't read more then the free bytes in the tcp req buffer */ read_size = MIN_unsigned(rd.size, bytes_free); bytes_read = tcp_read_data(c->fd, c, (char*)rd.buf, read_size, flags); TLS_RD_TRACE("(%p, %p) tcp_read_data(..., %d, *%d) => %d bytes\n", c, flags, read_size, *flags, bytes_read); /* try SSL_read even on 0 bytes read, it might have internally buffered data */ if (unlikely(bytes_read < 0)) { goto error; } rd.used = bytes_read; } } continue_ssl_read: tls_mbuf_init(&wr, wr_buf, sizeof(wr_buf)); ssl_error = SSL_ERROR_NONE; err_src = "TLS read:"; /* we have to avoid to run in the same time * with a tls_write because of the * update bio stuff (we don't want a write * stealing the wbio or rbio under us or vice versa) * => lock on con->write_lock (ugly hack) */ lock_get(&c->write_lock); tls_set_mbufs(c, &rd, &wr); ssl = tls_c->ssl; n = 0; if (unlikely(tls_write_wants_read(tls_c) && !(*flags & RD_CONN_EOF))) { n = tls_ct_wq_flush(c, &tls_c->ct_wq, &flush_flags, &ssl_error); TLS_RD_TRACE("(%p, %p) tls write on read (WRITE_WANTS_READ):" " ct_wq_flush()=> %d (ff=%d ssl_error=%d))\n", c, flags, n, flush_flags, ssl_error); if (unlikely(n < 0 )) { tls_set_mbufs(c, 0, 0); lock_release(&c->write_lock); ERR("write flush error (%d)\n", n); goto error; } if (likely(flush_flags & F_BUFQ_EMPTY)) tls_c->flags &= ~F_TLS_CON_WR_WANTS_RD; if (unlikely(flush_flags & F_BUFQ_ERROR_FLUSH)) err_src = "TLS write:"; } if (likely(ssl_error == SSL_ERROR_NONE)) { if (unlikely(tls_c->state == S_TLS_CONNECTING)) { n = tls_connect(c, &ssl_error); TLS_RD_TRACE("(%p, %p) tls_connect() => %d (err=%d)\n", c, flags, n, ssl_error); if (unlikely(n>=1)) { n = SSL_read(ssl, r->pos, bytes_free); } else { /* tls_connect failed/needs more IO */ if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) { lock_release(&c->write_lock); goto error; } err_src = "TLS connect:"; goto ssl_read_skipped; } } else if (unlikely(tls_c->state == S_TLS_ACCEPTING)) { n = tls_accept(c, &ssl_error); TLS_RD_TRACE("(%p, %p) tls_accept() => %d (err=%d)\n", c, flags, n, ssl_error); if (unlikely(n>=1)) { n = SSL_read(ssl, r->pos, bytes_free); } else { /* tls_accept failed/needs more IO */ if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) { lock_release(&c->write_lock); goto error; } err_src = "TLS accept:"; goto ssl_read_skipped; } } else { /* if bytes in then decrypt read buffer into tcpconn req. buffer */ n = SSL_read(ssl, r->pos, bytes_free); } /** handle SSL_read() return. * There are 3 main cases, each with several sub-cases, depending * on whether or not the output buffer was filled, if there * is still unconsumed input data in the input buffer (rd) * and if there is "cached" data in the internal openssl * buffers. * 0. error (n<=0): * SSL_ERROR_WANT_READ - input data fully * consumed, no more returnable cached data inside openssl * => exit. * SSL_ERROR_WANT_WRITE - should never happen (the write * buffer is big enough to handle any re-negociation). * SSL_ERROR_ZERO_RETURN - ssl level shutdown => exit. * other errors are unexpected. * 1. output buffer filled (n == bytes_free): * 1i. - still unconsumed input, nothing buffered by openssl * 1ip. - unconsumed input + buffered data by openssl (pending on the next SSL_read). * 1p. - completely consumed input, buffered data internally * by openssl (pending). * Likely to happen, about the only case when * SSL_pending() could be used (but only if readahead=0). * 1f. - consumed input, no buffered data. * 2. output buffer not fully filled (n < bytes_free): * 2i. - still unconsumed input, nothing buffered by openssl. * This can appear if SSL readahead is 0 (SSL_read() * tries to get only 1 record from the input). * 2ip. - unconsumed input and buffered data by openssl. * Unlikely to happen (e.g. readahead is 1, more * records are buffered internally by openssl, but * there was not enough space for buffering the whole * input). * 2p - consumed input, but buffered data by openssl. * It happens especially when readahead is 1. * 2f. - consumed input, no buffered data. * * One should repeat SSL_read() until and error is detected * (0*) or the input and internal ssl buffers are fully consumed * (1f or 2f). However in general is not possible to see if * SSL_read() could return more data. SSL_pending() has very * limited usability (basically it would return !=0 only if there * was no enough space in the output buffer and only if this did * not happen at a record boundary). * The solution is to repeat SSL_read() until error or until * the output buffer is filled (0* or 1*). * In the later case, this whole function should be called again * once there is more output space (set RD_CONN_REPEAT_READ). */ if (unlikely(tls_c->flags & F_TLS_CON_RENEGOTIATION)) { /* Fix CVE-2009-3555 - disable renegotiation if started by client * - simulate SSL EOF to force close connection*/ tls_dbg = cfg_get(tls, tls_cfg, debug); LOG(tls_dbg, "Reading on a renegotiation of connection (n:%d) (%d)\n", n, SSL_get_error(ssl, n)); err_src = "TLS R-N read:"; ssl_error = SSL_ERROR_ZERO_RETURN; } else { if (unlikely(n <= 0)) { ssl_error = SSL_get_error(ssl, n); err_src = "TLS read:"; /* errors handled below, outside the lock */ } else { ssl_error = SSL_ERROR_NONE; r->pos += n; ssl_read += n; bytes_free -=n; } } TLS_RD_TRACE("(%p, %p) SSL_read() => %d (err=%d) ssl_read=%d" " *flags=%d tls_c->flags=%d\n", c, flags, n, ssl_error, ssl_read, *flags, tls_c->flags); ssl_read_skipped: ; } if (unlikely(wr.used != 0 && ssl_error != SSL_ERROR_ZERO_RETURN)) { TLS_RD_TRACE("(%p, %p) tcpconn_send_unsafe %d bytes\n", c, flags, wr.used); /* something was written and it's not ssl EOF*/ if (unlikely(tcpconn_send_unsafe(c->fd, c, (char*)wr.buf, wr.used, c->send_flags) < 0)) { tls_set_mbufs(c, 0, 0); lock_release(&c->write_lock); TLS_RD_TRACE("(%p, %p) tcpconn_send_unsafe error\n", c, flags); goto error_send; } } /* quickly catch bugs: segfault if accessed and not set */ tls_set_mbufs(c, 0, 0); lock_release(&c->write_lock); switch(ssl_error) { case SSL_ERROR_NONE: if (unlikely(n < 0)) { BUG("unexpected SSL_ERROR_NONE for n=%d\n", n); goto error; } break; case SSL_ERROR_ZERO_RETURN: /* SSL EOF */ TLS_RD_TRACE("(%p, %p) SSL EOF (fd=%d)\n", c, flags, c->fd); goto ssl_eof; case SSL_ERROR_WANT_READ: TLS_RD_TRACE("(%p, %p) SSL_ERROR_WANT_READ *flags=%d\n", c, flags, *flags); /* needs to read more data */ if (unlikely(rd.pos != rd.used)) { /* data still in the read buffer */ BUG("SSL_ERROR_WANT_READ but data still in" " the rbio (%p, %d bytes at %d)\n", rd.buf, rd.used - rd.pos, rd.pos); goto bug; } if (unlikely((*flags & (RD_CONN_EOF | RD_CONN_SHORT_READ)) == 0) && bytes_free){ /* there might still be data to read and there is space to decrypt it in tcp_req (no byte has been written into tcp_req in this case) */ TLS_RD_TRACE("(%p, %p) redo read *flags=%d bytes_free=%d\n", c, flags, *flags, bytes_free); goto redo_read; } goto end; /* no more data to read */ case SSL_ERROR_WANT_WRITE: if (wr.used) { /* something was written => buffer not big enough to hold everything => reset buffer & retry (the tcp_write already happened if we are here) */ TLS_RD_TRACE("(%p) SSL_ERROR_WANT_WRITE partial write" " (written %d), retrying\n", c, wr.used); goto continue_ssl_read; } /* else write buffer too small, nothing written */ BUG("write buffer too small (%d/%d bytes)\n", wr.used, wr.size); goto bug; case SSL_ERROR_SSL: /* protocol level error */ TLS_ERR(err_src); goto error; #if OPENSSL_VERSION_NUMBER >= 0x00907000L /*0.9.7*/ case SSL_ERROR_WANT_CONNECT: /* only if the underlying BIO is not yet connected and the call would block in connect(). (not possible in our case) */ BUG("unexpected SSL_ERROR_WANT_CONNECT\n"); goto bug; case SSL_ERROR_WANT_ACCEPT: /* only if the underlying BIO is not yet connected and call would block in accept() (not possible in our case) */ BUG("unexpected SSL_ERROR_WANT_ACCEPT\n"); goto bug; #endif case SSL_ERROR_WANT_X509_LOOKUP: /* can only appear on client application and it indicates that an installed client cert. callback should be called again (it returned < 0 indicated that it wants to be called later). Not possible in our case */ BUG("unsupported SSL_ERROR_WANT_X509_LOOKUP"); goto bug; case SSL_ERROR_SYSCALL: TLS_ERR_RET(x, err_src); if (!x) { if (n == 0) { WARN("Unexpected EOF\n"); } else /* should never happen */ BUG("IO error (%d) %s\n", errno, strerror(errno)); } goto error; default: TLS_ERR(err_src); BUG("unexpected SSL error %d\n", ssl_error); goto bug; } if (unlikely(n < 0)) { /* here n should always be >= 0 */ BUG("unexpected value (n = %d)\n", n); goto bug; } if (unlikely(rd.pos != rd.used)) { /* encrypted data still in the read buffer (SSL_read() did not consume all of it) */ if (unlikely(n < 0)) /* here n should always be >= 0 */ BUG("unexpected value (n = %d)\n", n); else { if (unlikely(bytes_free != 0)) { /* 2i or 2ip: unconsumed input and output buffer not filled => retry ssl read (SSL_read() will read will stop at record boundaries, unless readahead==1). No tcp_read() is attempted, since that would reset the current no-yet-consumed input data. */ TLS_RD_TRACE("(%p, %p) input not fully consumed =>" " retry SSL_read" " (pos: %d, remaining %d, output free %d)\n", c, flags, rd.pos, rd.used-rd.pos, bytes_free); goto continue_ssl_read; } /* 1i or 1ip: bytes_free == 0 (unconsumed input, but filled output buffer) => queue read data, and exit asking for repeating the call once there is some space in the output buffer. */ if (likely(!enc_rd_buf)) { TLS_RD_TRACE("(%p, %p) creating enc_rd_buf (for %d bytes)\n", c, flags, rd.used - rd.pos); enc_rd_buf = shm_malloc(sizeof(*enc_rd_buf) - sizeof(enc_rd_buf->buf) + rd.used - rd.pos); if (unlikely(enc_rd_buf == 0)) { ERR("memory allocation error (%d bytes requested)\n", (int)(sizeof(*enc_rd_buf) + sizeof(enc_rd_buf->buf) + rd.used - rd.pos)); goto error; } enc_rd_buf->pos = 0; enc_rd_buf->size = rd.used - rd.pos; memcpy(enc_rd_buf->buf, rd.buf + rd.pos, enc_rd_buf->size); } else if ((enc_rd_buf->buf + enc_rd_buf->pos) == rd.buf) { TLS_RD_TRACE("(%p, %p) enc_rd_buf already in use," " updating pos %d\n", c, flags, enc_rd_buf->pos); enc_rd_buf->pos += rd.pos; } else { BUG("enc_rd_buf->buf = %p, pos = %d, rd_buf.buf = %p\n", enc_rd_buf->buf, enc_rd_buf->pos, rd.buf); goto bug; } if (unlikely(tls_c->enc_rd_buf)) BUG("tls_c->enc_rd_buf!=0 (%p)\n", tls_c->enc_rd_buf); /* there can't be 2 reads in parallel, so no locking is needed here */ tls_c->enc_rd_buf = enc_rd_buf; enc_rd_buf = 0; *flags |= RD_CONN_REPEAT_READ; } } else if (bytes_free != 0) { /* 2f or 2p: input fully consumed (rd.pos == rd.used), output buffer not filled, still possible to have pending data buffered by openssl */ if (unlikely((*flags & (RD_CONN_EOF|RD_CONN_SHORT_READ)) == 0)) { /* still space in the tcp unenc. req. buffer, no SSL_read error, not a short read and not an EOF (possible more data in the socket buffer) => try a new tcp read too */ TLS_RD_TRACE("(%p, %p) retry read (still space and no short" " tcp read: %d)\n", c, flags, *flags); goto redo_read; } else { /* don't tcp_read() anymore, but there might still be data buffered internally by openssl (e.g. if readahead==1) => retry SSL_read() with the current full input buffer (if no more internally SSL buffered data => WANT_READ => exit). */ TLS_RD_TRACE("(%p, %p) retry SSL_read only (*flags =%d)\n", c, flags, *flags); goto continue_ssl_read; } } else { /* 1p or 1f: rd.pos == rd.used && bytes_free == 0 (input fully consumed && output buffer filled) */ /* ask for a repeat when there is more buffer space (there is no definitive way to know if ssl doesn't still have some internal buffered data until we get WANT_READ, see SSL_read() comment above) */ *flags |= RD_CONN_REPEAT_READ; TLS_RD_TRACE("(%p, %p) output filled, exit asking to be called again" " (*flags =%d)\n", c, flags, *flags); } end: if (enc_rd_buf) shm_free(enc_rd_buf); TLS_RD_TRACE("(%p, %p) end => %d (*flags=%d)\n", c, flags, ssl_read, *flags); return ssl_read; ssl_eof: /* behave as an EOF would have been received at the tcp level */ if (enc_rd_buf) shm_free(enc_rd_buf); c->state = S_CONN_EOF; *flags |= RD_CONN_EOF; TLS_RD_TRACE("(%p, %p) end EOF => %d (*flags=%d)\n", c, flags, ssl_read, *flags); return ssl_read; error_send: error: bug: if (enc_rd_buf) shm_free(enc_rd_buf); r->error=TCP_READ_ERROR; TLS_RD_TRACE("(%p, %p) end error => %d (*flags=%d)\n", c, flags, ssl_read, *flags); return -1; }
/** tls encrypt before sending function. * It is a callback that will be called by the tcp code, before a send * on TLS would be attempted. It should replace the input buffer with a * new static buffer containing the TLS processed data. * If the input buffer could not be fully encoded (e.g. run out of space * in the internal static buffer), it should set rest_buf and rest_len to * the remaining part, so that it could be called again once the output has * been used (sent). The send_flags used are also passed and they can be * changed (e.g. to disallow a close() after a partial encode). * WARNING: it must always be called with c->write_lock held! * @param c - tcp connection * @param pbuf - pointer to buffer (value/result, on success it will be * replaced with a static buffer). * @param plen - pointer to buffer size (value/result, on success it will be * replaced with the size of the replacement buffer. * @param rest_buf - (result) should be filled with a pointer to the * remaining unencoded part of the original buffer if any, * 0 otherwise. * @param rest_len - (result) should be filled with the length of the * remaining unencoded part of the original buffer (0 if * the original buffer was fully encoded). * @param send_flags - pointer to the send_flags that will be used for sending * the message. * @return *plen on success (>=0), < 0 on error. */ int tls_encode_f(struct tcp_connection *c, const char** pbuf, unsigned int* plen, const char** rest_buf, unsigned int* rest_len, snd_flags_t* send_flags) { int n, offs; SSL* ssl; struct tls_extra_data* tls_c; static unsigned char wr_buf[TLS_WR_MBUF_SZ]; struct tls_mbuf rd, wr; int ssl_error; char* err_src; const char* buf; unsigned int len; int x; buf = *pbuf; len = *plen; *rest_buf = 0; *rest_len = 0; TLS_WR_TRACE("(%p, %p, %d, ... 0x%0x) start (%s:%d* -> %s)\n", c, buf, len, send_flags->f, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port, su2a(&c->rcv.src_su, sizeof(c->rcv.src_su))); n = 0; offs = 0; ssl_error = SSL_ERROR_NONE; err_src = "TLS write:"; if (unlikely(tls_fix_connection_unsafe(c) < 0)) { /* c->extra_data might be null => exit immediately */ TLS_WR_TRACE("(%p) end: tls_fix_connection_unsafe failed =>" " immediate error exit\n", c); return -1; } tls_c = (struct tls_extra_data*)c->extra_data; ssl = tls_c->ssl; tls_mbuf_init(&rd, 0, 0); /* no read */ tls_mbuf_init(&wr, wr_buf, sizeof(wr_buf)); /* clear text already queued (WANTS_READ) queue directly*/ if (unlikely(tls_write_wants_read(tls_c))) { TLS_WR_TRACE("(%p) WANTS_READ queue present => queueing" " (%d bytes, %p + %d)\n", c, len - offs, buf, offs); if (unlikely(tls_ct_wq_add(&tls_c->ct_wq, buf+offs, len -offs) < 0)) { ERR("ct write buffer full for %p (%d bytes)\n", c, tls_c->ct_wq?tls_c->ct_wq->queued:0); goto error_wq_full; } /* buffer queued for a future send attempt, after first reading some data (key exchange) => don't allow immediate closing of the connection */ send_flags->f &= ~SND_F_CON_CLOSE; goto end; } if (unlikely(tls_set_mbufs(c, &rd, &wr) < 0)) { ERR("tls_set_mbufs failed\n"); goto error; } redo_wr: if (unlikely(tls_c->state == S_TLS_CONNECTING)) { n = tls_connect(c, &ssl_error); TLS_WR_TRACE("(%p) tls_connect() => %d (err=%d)\n", c, n, ssl_error); if (unlikely(n>=1)) { n = SSL_write(ssl, buf + offs, len - offs); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } else { /* tls_connect failed/needs more IO */ if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) goto error; err_src = "TLS connect:"; } } else if (unlikely(tls_c->state == S_TLS_ACCEPTING)) { n = tls_accept(c, &ssl_error); TLS_WR_TRACE("(%p) tls_accept() => %d (err=%d)\n", c, n, ssl_error); if (unlikely(n>=1)) { n = SSL_write(ssl, buf + offs, len - offs); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } else { /* tls_accept failed/needs more IO */ if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) goto error; err_src = "TLS accept:"; } } else { n = SSL_write(ssl, buf + offs, len - offs); if (unlikely(n <= 0)) ssl_error = SSL_get_error(ssl, n); } TLS_WR_TRACE("(%p) SSL_write(%p + %d, %d) => %d (err=%d)\n", c, buf, offs, len - offs, n, ssl_error); /* check for possible ssl errors */ if (unlikely(n <= 0)){ switch(ssl_error) { case SSL_ERROR_NONE: BUG("unexpected SSL_ERROR_NONE for n=%d\n", n); goto error; break; case SSL_ERROR_ZERO_RETURN: /* SSL EOF */ ERR("ssl level EOF\n"); goto ssl_eof; case SSL_ERROR_WANT_READ: /* queue write buffer */ TLS_WR_TRACE("(%p) SSL_ERROR_WANT_READ => queueing for read" " (%p + %d, %d)\n", c, buf, offs, len -offs); if (unlikely(tls_ct_wq_add(&tls_c->ct_wq, buf+offs, len -offs) < 0)) { ERR("ct write buffer full (%d bytes)\n", tls_c->ct_wq?tls_c->ct_wq->queued:0); goto error_wq_full; } tls_c->flags |= F_TLS_CON_WR_WANTS_RD; /* buffer queued for a future send attempt, after first reading some data (key exchange) => don't allow immediate closing of the connection */ send_flags->f &= ~SND_F_CON_CLOSE; break; /* or goto end */ case SSL_ERROR_WANT_WRITE: if (unlikely(offs == 0)) { /* error, no record fits in the buffer or no partial write enabled and buffer to small to fit all the records */ BUG("write buffer too small (%d/%d bytes)\n", wr.used, wr.size); goto bug; } else { /* offs != 0 => something was "written" */ *rest_buf = buf + offs; *rest_len = len - offs; /* this function should be called again => disallow immediate closing of the connection */ send_flags->f &= ~SND_F_CON_CLOSE; TLS_WR_TRACE("(%p) SSL_ERROR_WANT_WRITE partial write" " (written %p , %d, rest_buf=%p" " rest_len=%d))\n", c, buf, offs, *rest_buf, *rest_len); } break; /* or goto end */ case SSL_ERROR_SSL: /* protocol level error */ TLS_ERR(err_src); goto error; #if OPENSSL_VERSION_NUMBER >= 0x00907000L /*0.9.7*/ case SSL_ERROR_WANT_CONNECT: /* only if the underlying BIO is not yet connected and the call would block in connect(). (not possible in our case) */ BUG("unexpected SSL_ERROR_WANT_CONNECT\n"); break; case SSL_ERROR_WANT_ACCEPT: /* only if the underlying BIO is not yet connected and call would block in accept() (not possible in our case) */ BUG("unexpected SSL_ERROR_WANT_ACCEPT\n"); break; #endif case SSL_ERROR_WANT_X509_LOOKUP: /* can only appear on client application and it indicates that an installed client cert. callback should be called again (it returned < 0 indicated that it wants to be called later). Not possible in our case */ BUG("unsupported SSL_ERROR_WANT_X509_LOOKUP"); goto bug; case SSL_ERROR_SYSCALL: TLS_ERR_RET(x, err_src); if (!x) { if (n == 0) { WARN("Unexpected EOF\n"); } else /* should never happen */ BUG("IO error (%d) %s\n", errno, strerror(errno)); } goto error; default: TLS_ERR(err_src); BUG("unexpected SSL error %d\n", ssl_error); goto bug; } } else if (unlikely(n < (len - offs))) { /* partial ssl write (possible if SSL_MODE_ENABLE_PARTIAL_WRITE) => retry with the rest */ TLS_WR_TRACE("(%p) partial write (%d < %d, offset %d), retry\n", c, n, len - offs, offs); offs += n; goto redo_wr; } tls_set_mbufs(c, 0, 0); end: *pbuf = (const char*)wr.buf; *plen = wr.used; TLS_WR_TRACE("(%p) end (offs %d, rest_buf=%p rest_len=%d 0x%0x) => %d \n", c, offs, *rest_buf, *rest_len, send_flags->f, *plen); return *plen; error: /*error_send:*/ error_wq_full: bug: tls_set_mbufs(c, 0, 0); TLS_WR_TRACE("(%p) end error (offs %d, %d encoded) => -1\n", c, offs, wr.used); return -1; ssl_eof: c->state = S_CONN_EOF; c->flags |= F_CONN_FORCE_EOF; *pbuf = (const char*)wr.buf; *plen = wr.used; DBG("TLS connection has been closed\n"); TLS_WR_TRACE("(%p) end EOF (offs %d) => (%d\n", c, offs, *plen); return *plen; }
static BOOL rdg_tls_connect(rdpRdg* rdg, rdpTls* tls, const char* peerAddress, int timeout) { int sockfd = 0; int status = 0; BIO* socketBio = NULL; BIO* bufferedBio = NULL; rdpSettings* settings = rdg->settings; const char* peerHostname = settings->GatewayHostname; UINT16 peerPort = settings->GatewayPort; const char* proxyUsername, *proxyPassword; BOOL isProxyConnection = proxy_prepare(settings, &peerHostname, &peerPort, &proxyUsername, &proxyPassword); sockfd = freerdp_tcp_connect(rdg->context, settings, peerAddress ? peerAddress : peerHostname, peerPort, timeout); if (sockfd < 0) { return FALSE; } socketBio = BIO_new(BIO_s_simple_socket()); if (!socketBio) { closesocket(sockfd); return FALSE; } BIO_set_fd(socketBio, sockfd, BIO_CLOSE); bufferedBio = BIO_new(BIO_s_buffered_socket()); if (!bufferedBio) { closesocket(sockfd); BIO_free(socketBio); return FALSE; } bufferedBio = BIO_push(bufferedBio, socketBio); status = BIO_set_nonblock(bufferedBio, TRUE); if (isProxyConnection) { if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword, settings->GatewayHostname, settings->GatewayPort)) return FALSE; } if (!status) { BIO_free_all(bufferedBio); return FALSE; } tls->hostname = settings->GatewayHostname; tls->port = settings->GatewayPort; tls->isGatewayTransport = TRUE; status = tls_connect(tls, bufferedBio); return (status >= 1); }
/** * Send an authentication request to NuAuth. May restart TLS session * and/or open TLS connection (if closed). * * Create the thread authsrv() when opening a new session. * * Packet maximum size is 512 bytes, * and it's structure is ::nufw_to_nuauth_auth_message_t. * * \param type Type of request (::AUTH_REQUEST, ::AUTH_CONTROL, ...) * \param pckt_data A pointer to a queued_pckt:: holding packet information * \return If an error occurs returns 0, else return 1. */ int auth_request_send(uint8_t type, struct queued_pckt *pckt_data) { unsigned char data[512]; nuv4_nufw_to_nuauth_auth_message_t *msg_header = (nuv4_nufw_to_nuauth_auth_message_t *) & data; unsigned char *msg_content = data + sizeof(nuv4_nufw_to_nuauth_auth_message_t); int msg_length; /* Drop non-IPv(4|6) packet */ if ((((struct iphdr *) (pckt_data->payload))->version != 4) && (((struct iphdr *) (pckt_data->payload))->version != 6)) { log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG, "Dropping non-IPv4/non-IPv6 packet (version %u)", ((struct iphdr *) (pckt_data->payload))-> version); return 0; } /* Truncate packet content if needed */ if (sizeof(data) < sizeof(nuv4_nufw_to_nuauth_auth_message_t) + pckt_data->payload_len) { debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG, "Very long packet: truncating!"); pckt_data->payload_len = sizeof(data) - sizeof(nuv4_nufw_to_nuauth_auth_message_t); } msg_length = sizeof(nuv4_nufw_to_nuauth_auth_message_t) + pckt_data->payload_len; /* Fill message header */ msg_header->protocol_version = PROTO_NUFW_VERSION; msg_header->msg_type = type; msg_header->msg_length = htons(msg_length); msg_header->packet_id = htonl(pckt_data->packet_id); msg_header->timestamp = htonl(pckt_data->timestamp); /* Add info about interfaces */ msg_header->mark = pckt_data->mark; memcpy(msg_header->indev, pckt_data->indev, IFNAMSIZ * sizeof(char)); memcpy(msg_header->outdev, pckt_data->outdev, IFNAMSIZ * sizeof(char)); memcpy(msg_header->physindev, pckt_data->physindev, IFNAMSIZ * sizeof(char)); memcpy(msg_header->physoutdev, pckt_data->physoutdev, IFNAMSIZ * sizeof(char)); /* Copy (maybe truncated) packet content */ memcpy(msg_content, pckt_data->payload, pckt_data->payload_len); /* Display message */ log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG, "Sending request for %lu", (long)pckt_data->packet_id); /* negotiate TLS connection if needed */ if (!tls.session) { log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_INFO, "Not connected, trying TLS connection"); tls_connect(); if (tls.session) { int fd; char buf[256]; buf[0] = '\0'; nussl_session_get_cipher(tls.session, buf, sizeof(buf)); log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING, "[+] TLS connection to nuauth restored (%s:%d), cipher is %s", authreq_addr, authreq_port, (buf[0] != '\0') ? buf : "none" ); fd = nussl_session_get_fd(tls.session); if (fd >= 0) { ev_io_init(&tls.ev_io, tls_activity_cb, nussl_session_get_fd(tls.session), EV_READ); tls.ev_io.data = &nufw_nfq_watcher; ev_io_start(nufw_loop, &tls.ev_io); } } else { log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING, "[!] TLS connection to nuauth can NOT be restored (%s:%d)", authreq_addr, authreq_port); return 0; } } if (nussl_write(tls.session, (char*)data, msg_length) < 0) { debug_log_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_DEBUG, "Error during nussl_write (auth_request_send)."); shutdown_tls(); log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING, "[!] TLS send failure"); return 0; } return 1; }
int main(int argc, char *argv[]) { struct tls_config *conf; struct tls *ctx; int res; const char *host; if (argc < 2) errx(1, "give host as arg\n"); host = argv[1]; res = tls_init(); if (res < 0) errx(1, "tls_init"); conf = tls_config_new(); if (!conf) errx(1, "tls_config_new"); tls_config_set_protocols(conf, TLS_PROTOCOLS_ALL); tls_config_set_ciphers(conf, "HIGH:+3DES:!aNULL"); tls_config_set_ca_file(conf, "/etc/ssl/certs/ca-certificates.crt"); ctx = tls_client(); if (!ctx) errx(1, "tls_client"); res = tls_configure(ctx, conf); if (res < 0) errx(1, "tls_configure: %s", tls_error(ctx)); res = tls_connect(ctx, host, "443"); if (res < 0) errx(1, "tls_connect: %s", tls_error(ctx)); res = tls_handshake(ctx); if (res < 0) errx(1, "tls_handshake: %s", tls_error(ctx)); printf("connect ok\n"); #if 0 struct tls_cert *cert; //res = tls_get_peer_cert(ctx, &cert, NULL); //if (res < 0) //errx(1, "tls_get_peer_cert: %s", tls_error(ctx)); printf(" CN='%s'\n", cert->subject.common_name); printf(" C='%s'\n", cert->subject.country_name); printf(" ST='%s'\n", cert->subject.state_or_province_name); printf(" L='%s'\n", cert->subject.locality_name); printf(" S='%s'\n", cert->subject.street_address); printf(" O='%s'\n", cert->subject.organization_name); printf(" OU='%s'\n", cert->subject.organizational_unit_name); tls_cert_free(cert); #endif tls_close(ctx); tls_free(ctx); tls_config_free(conf); return 0; }
/** * Simple command-line HTTP client. */ int main( int argc, char *argv[ ] ) { int client_connection; char *host, *path; char *proxy_host, *proxy_user, *proxy_password; int proxy_port; struct hostent *host_name; struct sockaddr_in host_address; int port = HTTPS_PORT; int ind; int master_secret_length; unsigned char *master_secret; int session_id_length; unsigned char *session_id; #ifdef WIN32 WSADATA wsaData; #endif TLSParameters tls_context; if ( argc < 2 ) { fprintf( stderr, "Usage: %s: [-p http://[username:password@]proxy-host:proxy-port] <URL>\n", argv[ 0 ] ); return 1; } proxy_host = proxy_user = proxy_password = host = path = session_id = master_secret = NULL; session_id_length = master_secret_length = 0; for ( ind = 1; ind < ( argc - 1 ); ind++ ) { if ( !strcmp( "-p", argv[ ind ] ) ) { if ( !parse_proxy_param( argv[ ++ind ], &proxy_host, &proxy_port, &proxy_user, &proxy_password ) ) { fprintf( stderr, "Error - malformed proxy parameter '%s'.\n", argv[ 2 ] ); return 2; } } else if ( !strcmp( "-s", argv[ ind ] ) ) { session_id_length = hex_decode( argv[ ++ind ], &session_id ); } else if ( !strcmp( "-m", argv[ ind ] ) ) { master_secret_length = hex_decode( argv[ ++ind ], &master_secret ); } } if ( ( ( master_secret_length > 0 ) && ( session_id_length == 0 ) ) || ( ( master_secret_length == 0 ) && ( session_id_length > 0 ) ) ) { fprintf( stderr, "session id and master secret must both be provided.\n" ); return 3; } if ( parse_url( argv[ ind ], &host, &path ) == -1 ) { fprintf( stderr, "Error - malformed URL '%s'.\n", argv[ 1 ] ); return 1; } printf( "Connecting to host '%s'\n", host ); // Step 1: open a socket connection on http port with the destination host. #ifdef WIN32 if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != NO_ERROR ) { fprintf( stderr, "Error, unable to initialize winsock.\n" ); return 2; } #endif client_connection = socket( PF_INET, SOCK_STREAM, 0 ); if ( !client_connection ) { perror( "Unable to create local socket" ); return 2; } if ( proxy_host ) { printf( "Connecting to host '%s'\n", proxy_host ); host_name = gethostbyname( proxy_host ); } else { host_name = gethostbyname( host ); } if ( !host_name ) { perror( "Error in name resolution" ); return 3; } host_address.sin_family = AF_INET; host_address.sin_port = htons( proxy_host ? proxy_port : HTTPS_PORT ); memcpy( &host_address.sin_addr, host_name->h_addr_list[ 0 ], sizeof( struct in_addr ) ); if ( connect( client_connection, ( struct sockaddr * ) &host_address, sizeof( host_address ) ) == -1 ) { perror( "Unable to connect to host" ); return 4; } printf( "Connection complete; negotiating TLS parameters\n" ); if ( proxy_host ) { if ( !http_connect( client_connection, host, port, proxy_user, proxy_password ) ) { perror( "Unable to establish proxy tunnel" ); if ( close( client_connection ) == -1 ) { perror( "Error closing client connection" ); return 2; } return 3; } } if ( session_id != NULL ) { if ( tls_resume( client_connection, session_id_length, session_id, master_secret, &tls_context ) ) { fprintf( stderr, "Error: unable to negotiate SSL connection.\n" ); if ( close( client_connection ) == -1 ) { perror( "Error closing client connection" ); return 2; } return 3; } } else { if ( tls_connect( client_connection, &tls_context, 0 ) ) { fprintf( stderr, "Error: unable to negotiate TLS connection.\n" ); return 3; } } printf( "Retrieving document: '%s'\n", path ); http_get( client_connection, path, host, &tls_context ); display_result( client_connection, &tls_context ); tls_shutdown( client_connection, &tls_context ); printf( "Session ID was: " ); show_hex( tls_context.session_id, tls_context.session_id_length ); printf( "Master secret was: " ); show_hex( tls_context.master_secret, MASTER_SECRET_LENGTH ); printf( "Shutting down.\n" ); #ifdef WIN32 if ( closesocket( client_connection ) == -1 ) #else if ( close( client_connection ) == -1 ) #endif { perror( "Error closing client connection" ); return 5; } if ( session_id != NULL ) { free( session_id ); } if ( master_secret != NULL ) { free( master_secret ); } #ifdef WIN32 WSACleanup(); #endif return 0; }