/* * wrapper around SSL_shutdown, returns -1 on error, 0 on success */ static int tls_shutdown(struct tcp_connection *c) { int ret, err; SSL *ssl; /* * we do not implement full ssl shutdown */ ssl = (SSL *) c->extra_data; if (ssl == 0) { LM_ERR("no ssl data\n"); return -1; } ret = SSL_shutdown(ssl); if (ret == 1) { LM_DBG("shutdown successful\n"); return 0; } else if (ret == 0) { LM_DBG("first phase of 2-way handshake completed succesfuly\n"); return 0; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: c->state = S_CONN_EOF; return 0; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: c->state = S_CONN_EOF; return 0; default: LM_ERR("something wrong in SSL:\n"); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_ERR("bug\n"); return -1; }
/* * Wrapper around SSL_write, returns number of bytes written on success, * * -1 on error, 0 when it would block */ static int tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short *poll_events) { int ret, err; /* * runs within write lock, no need to lock here */ SSL *ssl; ssl = (SSL *) c->extra_data; ret = SSL_write(ssl, buf, len); if (ret > 0) { LM_DBG("write was successful (%d bytes)\n", ret); return ret; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_DBG("connection closed cleanly\n"); c->state = S_CONN_EOF; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; default: LM_ERR("TLS connection to %s:%d write failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS write error:\n"); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_ERR("bug\n"); return -1; }
/* * Wrapper around SSL_read * * returns number of bytes read, 0 on eof and transits into S_CONN_EOF, -1 * on error */ static int _tls_read(struct tcp_connection *c, void *buf, size_t len) { int ret, err; SSL *ssl; ssl = c->extra_data; ret = SSL_read(ssl, buf, len); if (ret > 0) { LM_DBG("%d bytes read\n", ret); return ret; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_DBG("TLS connection to %s:%d closed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); /* * mark end of file */ c->state = S_CONN_EOF; return 0; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return 0; case SSL_ERROR_SYSCALL: LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno)); default: LM_ERR("TLS connection to %s:%d read failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS read error: %d\n",err); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_BUG("bug\n"); return -1; }
/* * wrapper around SSL_connect, returns 0 on success, -1 on error */ static int tls_connect(struct tcp_connection *c, short *poll_events) { int ret, err; SSL *ssl; X509* cert; if ( (c->proto_flags&F_TLS_DO_CONNECT)==0 ) { LM_BUG("invalid connection state (bug in TLS code)\n"); return -1; } ssl = (SSL *) c->extra_data; ret = SSL_connect(ssl); if (ret > 0) { LM_INFO("New TLS connection to %s:%d established\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->proto_flags &= ~F_TLS_DO_CONNECT; LM_DBG("new TLS connection to %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LM_DBG("sending socket: %s:%d \n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_connect: server TLS certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LM_WARN("TLS server certificate verification failed\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { /* this should not happen, servers always present a cert */ LM_ERR("server did not present a TLS certificate\n"); } cert = SSL_get_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_connect: local TLS client certificate", cert); } else { LM_INFO("local TLS client domain does not have a certificate\n"); } return 0; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_INFO("New TLS connection to %s:%d failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; case SSL_ERROR_SYSCALL: LM_ERR("SSL_ERROR_SYSCALL err=%s(%d)\n", strerror(errno), errno); default: LM_ERR("New TLS connection to %s:%d failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS error: %d (ret=%d) err=%s(%d)\n", err,ret,strerror(errno), errno); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_BUG("bug\n"); return -1; }
/* * Wrapper around SSL_accept, returns -1 on error, 0 on success */ static int tls_accept(struct tcp_connection *c, short *poll_events) { int ret, err; SSL *ssl; X509* cert; if ( (c->proto_flags&F_TLS_DO_ACCEPT)==0 ) { LM_BUG("invalid connection state (bug in TLS code)\n"); return -1; } ssl = (SSL *) c->extra_data; #ifndef OPENSSL_NO_KRB5 if ( ssl->kssl_ctx==NULL ) ssl->kssl_ctx = kssl_ctx_new( ); #endif ret = SSL_accept(ssl); #ifndef OPENSSL_NO_KRB5 if ( ssl->kssl_ctx ) { kssl_ctx_free( ssl->kssl_ctx ); ssl->kssl_ctx = 0; } #endif if (ret > 0) { LM_INFO("New TLS connection from %s:%d accepted\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); /* TLS accept done, reset the flag */ c->proto_flags &= ~F_TLS_DO_ACCEPT; LM_DBG("new TLS connection from %s:%d using %s %s %d\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port, SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, 0) ); LM_DBG("local socket: %s:%d\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port ); cert = SSL_get_peer_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_accept: client TLS certificate", cert); if (SSL_get_verify_result(ssl) != X509_V_OK) { LM_WARN("TLS client certificate verification failed\n"); tls_dump_verification_failure(SSL_get_verify_result(ssl)); } X509_free(cert); } else { LM_INFO("Client did not present a TLS certificate\n"); } cert = SSL_get_certificate(ssl); if (cert != 0) { tls_dump_cert_info("tls_accept: local TLS server certificate", cert); } else { /* this should not happen, servers always present a cert */ LM_ERR("local TLS server domain has no certificate\n"); } return 0; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_INFO("TLS connection from %s:%d accept failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; default: c->state = S_CONN_BAD; if (errno == 0) { LM_ERR("New TLS connection from %s:%d failed to accept:" " rejected by client\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); } else { LM_ERR("New TLS connection from %s:%d failed to accept\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS error: (ret=%d, err=%d, errno=%d/%s):\n", ret, err, errno, strerror(errno)); tls_print_errstack(); } return -1; } } LM_BUG("bug\n"); return -1; }