static int get_version(str* res, sip_msg_t* msg) { str version; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_version\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; version.s = (char*)SSL_get_version(ssl); version.len = version.s ? strlen(version.s) : 0; if (version.len >= 1024) { ERR("Version string too long\n"); goto err; } memcpy(buf, version.s, version.len); res->s = buf; res->len = version.len; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
int tlsops_cipher(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { str cipher; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LM_INFO("TLS connection not found in select_cipher\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; cipher.s = (char*)SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); cipher.len = cipher.s ? strlen(cipher.s) : 0; if (cipher.len >= 1024) { LM_ERR("cipher name too long\n"); goto err; } memcpy(buf, cipher.s, cipher.len); res->rs.s = buf; res->rs.len = cipher.len; res->flags = PV_VAL_STR; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
static int get_cipher(str* res, sip_msg_t* msg) { str cipher; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_cipher\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; cipher.s = (char*)SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); cipher.len = cipher.s ? strlen(cipher.s) : 0; if (cipher.len >= 1024) { ERR("Cipher name too long\n"); goto err; } memcpy(buf, cipher.s, cipher.len); res->s = buf; res->len = cipher.len; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
static int get_bits(str* res, int* i, sip_msg_t* msg) { str bits; int b; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_bits\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0); bits.s = int2str(b, &bits.len); if (bits.len >= 1024) { ERR("Bits string too long\n"); goto err; } memcpy(buf, bits.s, bits.len); res->s = buf; res->len = bits.len; if (i) *i = b; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
int _write(SSL_CTX *ctx, int sockfd) { int res = 0; #ifdef WITH_DTLS SSL *ssl; int err; ssl = get_ssl(ctx, sockfd, NULL, 1); if (!ssl) { fprintf(stderr, "no SSL object for writing"); return 0; } res = SSL_write(ssl, NULL, 0); if (res < 0) { /* if (SSL_want_write(ssl)) return 0; */ /* FIXME: check SSL_want_read(ssl) */ err = SSL_get_error(ssl,res); fprintf(stderr,"SSL_write returned %d (%s)\n", err, ERR_error_string(err, NULL)); } else { printf("SSL_write successful\n"); } #else #endif return res; }
static int get_cert(X509** cert, struct tcp_connection** c, struct sip_msg* msg, int my) { SSL* ssl; *cert = 0; *c = get_cur_connection(msg); if (!(*c)) { INFO("TLS connection not found\n"); return -1; } ssl = get_ssl(*c); if (!ssl) goto err; *cert = my ? SSL_get_certificate(ssl) : SSL_get_peer_certificate(ssl); if (!*cert) { if (my) { ERR("Unable to retrieve my TLS certificate from SSL structure\n"); } else { ERR("Unable to retrieve peer TLS certificate from SSL structure\n"); } goto err; } return 0; err: tcpconn_put(*c); return -1; }
int tlsops_desc(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[128]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LM_INFO("TLS connection not found in select_desc\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; buf[0] = '\0'; SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, 128); res->rs.s = buf; res->rs.len = strlen(buf); res->flags = PV_VAL_STR; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
static int get_desc(str* res, sip_msg_t* msg) { static char buf[128]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_desc\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; buf[0] = '\0'; SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, 128); res->s = buf; res->len = strlen(buf); tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return -1; }
static int ssl_session_init(struct vsf_session* p_sess) { SSL* p_ssl = get_ssl(p_sess, VSFTP_COMMAND_FD); if (p_ssl == NULL) { return 0; } p_sess->p_control_ssl = p_ssl; return 1; }
int ssl_accept(struct vsf_session* p_sess, int fd) { SSL* p_ssl = get_ssl(p_sess, fd); if (p_ssl == NULL) { return 0; } p_sess->p_data_ssl = p_ssl; return 1; }
int ssl_handshake(struct vsf_session* p_sess, int fd) { /* SECURITY: data SSL connections don't have any auth on them as part of the * protocol. If a client sends an unfortunately optional client cert then * we can check for a match between the control and data connections. */ SSL* p_ssl; int reused; if (p_sess->p_data_ssl != NULL) { die("p_data_ssl should be NULL."); } /* Initiate the SSL connection by either calling accept or connect */ p_ssl = get_ssl(p_sess, fd); if (p_ssl == NULL) { return 0; } p_sess->p_data_ssl = p_ssl; setup_bio_callbacks(p_ssl); reused = SSL_session_reused(p_ssl); if (tunable_require_ssl_reuse && !reused) { str_alloc_text(&debug_str, "No SSL session reuse on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ssl_data_close(p_sess); return 0; } if (str_getlen(&p_sess->control_cert_digest) > 0) { static struct mystr data_cert_digest; if (!ssl_cert_digest(p_ssl, p_sess, &data_cert_digest)) { str_alloc_text(&debug_str, "Missing cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ssl_data_close(p_sess); return 0; } if (str_strcmp(&p_sess->control_cert_digest, &data_cert_digest)) { str_alloc_text(&debug_str, "DIFFERENT cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ssl_data_close(p_sess); return 0; } if (tunable_debug_ssl) { str_alloc_text(&debug_str, "Matching cert on data channel."); vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } } return 1; }
static int ssl_session_init(struct vsf_session* p_sess) { SSL* p_ssl = get_ssl(p_sess, VSFTP_COMMAND_FD); if (p_ssl == NULL) { return 0; } p_sess->p_control_ssl = p_ssl; (void) ssl_cert_digest(p_ssl, p_sess, &p_sess->control_cert_digest); setup_bio_callbacks(p_ssl); return 1; }
static int get_tlsext_sn(str* res, sip_msg_t* msg) { static char buf[1024]; struct tcp_connection* c; str server_name; SSL* ssl; c = get_cur_connection(msg); if (!c) { INFO("TLS connection not found in select_desc\n"); goto error; } ssl = get_ssl(c); if (!ssl) goto error; buf[0] = '\0'; server_name.s = (char*)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (server_name.s) { server_name.len = strlen(server_name.s); DBG("received server_name (TLS extension): '%.*s'\n", STR_FMT(&server_name)); } else { DBG("SSL_get_servername returned NULL\n"); goto error; } /* copy server_name into the buffer. If the buffer is too small copy only * the last bytes as these are the more important ones and prefix with * '+' */ if (server_name.len > sizeof(buf)) { ERR("server_name to big for buffer\n"); buf[0] = '+'; memcpy(buf + 1, server_name.s + 1 + server_name.len - sizeof(buf), sizeof(buf) - 1); res->len = sizeof(buf); } else { memcpy(buf, server_name.s, server_name.len); res->len = server_name.len; } res->s = buf; tcpconn_put(c); return 0; error: if (c) tcpconn_put(c); return -1; }
/* * Check whether peer certificate exists and verify the result * of certificate verification */ int tlsops_check_cert(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static str succ = str_init("1"); static str fail = str_init("0"); int err; struct tcp_connection* c; SSL* ssl; X509* cert = 0; switch (param->pvn.u.isname.name.n) { case CERT_VERIFIED: err = X509_V_OK; break; case CERT_REVOKED: err = X509_V_ERR_CERT_REVOKED; break; case CERT_EXPIRED: err = X509_V_ERR_CERT_HAS_EXPIRED; break; case CERT_SELFSIGNED: err = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; break; default: LM_CRIT("unexpected parameter value \"%d\"\n", param->pvn.u.isname.name.n); return pv_get_null(msg, param, res); } c = get_cur_connection(msg); if (!c) return -1; ssl = get_ssl(c); if (!ssl) goto err; if ((cert = SSL_get_peer_certificate(ssl)) && SSL_get_verify_result(ssl) == err) { res->rs.s = succ.s; res->rs.len = succ.len; res->ri = 1; } else { res->rs.s = fail.s; res->rs.len = fail.len; res->ri = 0; } res->flags = PV_VAL_STR | PV_VAL_INT; if (cert) X509_free(cert); tcpconn_put(c); return 0; err: if (cert) X509_free(cert); if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
DLLLOCAL int set_url_unlocked(const char* str, ExceptionSink* xsink) { QoreURL url(str); if (!url.isValid()) { xsink->raiseException("HTTP-CLIENT-URL-ERROR", "URL '%s' cannot be parsed", str); return -1; } bool port_set = false; if (connection.set_url(url, port_set, xsink)) return -1; const QoreString *tmp = url.getProtocol(); if (tmp) { prot_map_t::const_iterator i = prot_map.find(tmp->getBuffer()); if (i == prot_map.end()) { xsink->raiseException("HTTP-CLIENT-UNKNOWN-PROTOCOL", "protocol '%s' is not supported.", tmp->getBuffer()); return -1; } // set port only if it wasn't overridden in the URL if (!port_set && !connection.is_unix) connection.port = get_port(i->second); // set SSL setting from protocol default connection.ssl = get_ssl(i->second); } else { connection.ssl = false; if (!port_set) connection.port = default_port; } if (!proxy_connection.has_url()) setSocketPath(); return 0; }
DLLLOCAL int set_proxy_url_unlocked(const char* pstr, ExceptionSink* xsink) { QoreURL url(pstr); if (!url.isValid()) { xsink->raiseException("HTTP-CLIENT-URL-ERROR", "proxy URL '%s' cannot be parsed", pstr); return -1; } bool port_set = false; if (proxy_connection.set_url(url, port_set, xsink)) return -1; const QoreString *tmp = url.getProtocol(); if (tmp) { if (strcasecmp(tmp->getBuffer(), "http") && strcasecmp(tmp->getBuffer(), "https")) { xsink->raiseException("HTTP-CLIENT-PROXY-PROTOCOL-ERROR", "protocol '%s' is not supported for proxies, only 'http' and 'https'", tmp->getBuffer()); return -1; } prot_map_t::const_iterator i = prot_map.find(tmp->getBuffer()); assert(i != prot_map.end()); // set port only if it wasn't overridden in the URL if (!port_set && !proxy_connection.is_unix) proxy_connection.port = get_port(i->second); // set SSL setting from protocol default proxy_connection.ssl = get_ssl(i->second); } else { proxy_connection.ssl = false; if (!port_set) proxy_connection.port = default_port; } setSocketPath(); return 0; }
/* * Check whether peer certificate exists and verify the result * of certificate verification */ static int check_cert(str* res, int* ires, int local, int err, sip_msg_t* msg) { static str succ = STR_STATIC_INIT("1"); static str fail = STR_STATIC_INIT("0"); struct tcp_connection* c; SSL* ssl; X509* cert = 0; c = get_cur_connection(msg); if (!c) return -1; ssl = get_ssl(c); if (!ssl) goto error; if (local) { DBG("Verification of local certificates not supported\n"); goto error; } else { if ((cert = SSL_get_peer_certificate(ssl)) && SSL_get_verify_result(ssl) == err) { *res = succ; if (ires) *ires = 1; } else { *res = fail; if (ires) *ires = 0; } } if (cert) X509_free(cert); tcpconn_put(c); return 0; error: if (cert) X509_free(cert); if (c) tcpconn_put(c); return -1; }
static inline int get_cert(X509** cert, struct tcp_connection** c, struct sip_msg* msg, int my) { SSL* ssl; *cert = 0; *c = get_cur_connection(msg); if (!(*c)) { LM_INFO("TLS connection not found\n"); return -1; } ssl = get_ssl(*c); if (!ssl) goto err; *cert = my ? SSL_get_certificate(ssl) : SSL_get_peer_certificate(ssl); if (!*cert) { LM_ERR("failed to get certificate from SSL structure\n"); goto err; } return 0; err: tcpconn_put(*c); return -1; }
int tlsops_version(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { str version; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LM_INFO("TLS connection not found in select_version\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; version.s = (char*)SSL_get_version(ssl); version.len = version.s ? strlen(version.s) : 0; if (version.len >= 1024) { LM_ERR("version string too long\n"); goto err; } memcpy(buf, version.s, version.len); res->rs.s = buf; res->rs.len = version.len; res->flags = PV_VAL_STR; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
int tlsops_bits(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { str bits; int b; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LM_INFO("TLS connection not found in select_bits\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0); bits.s = int2str(b, &bits.len); if (bits.len >= 1024) { LM_ERR("bits string too long\n"); goto err; } memcpy(buf, bits.s, bits.len); res->rs.s = buf; res->rs.len = bits.len; res->ri = b; res->flags = PV_VAL_STR | PV_VAL_INT; tcpconn_put(c); return 0; err: if (c) tcpconn_put(c); return pv_get_null(msg, param, res); }
int _read(SSL_CTX *ctx, int sockfd) { char buf[2000]; struct sockaddr_in6 src; int len, ifindex, i; char addr[INET6_ADDRSTRLEN]; char port[6]; socklen_t sz = sizeof(struct sockaddr_in6); #ifdef WITH_DTLS SSL *ssl; int err; #endif /* Retrieve remote address and interface index as well as the first few bytes of the message to demultiplex protocols. */ memset(&src, 0, sizeof(struct sockaddr_in6)); len = check_connect(sockfd, buf, 4, (struct sockaddr *)&src, &ifindex); if (len < 0) /* error */ return len; #ifndef NDEBUG fprintf(stderr,"received packet"); if (getnameinfo((struct sockaddr *)&src, sizeof(src), addr, sizeof(addr), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) fprintf(stderr," from [%s]:%s", addr, port); fprintf(stderr," on interface %d\n", ifindex); #endif switch (demux_protocol(buf, len)) { #ifdef WITH_DTLS case DTLS : ssl = get_ssl(ctx, sockfd, (struct sockaddr *)&src, ifindex); if (!ssl) { fprintf(stderr, "cannot create new SSL object\n"); /* return recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);*/ len = recvfrom(sockfd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&src, &sz); getnameinfo((struct sockaddr *)&src, sz, addr, sizeof(addr), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); printf("discarded %d bytes from [%s]:%s\n", len, addr, port); return len; } len = SSL_read(ssl, buf, sizeof(buf)); break; #endif case UNKNOWN: default : len = recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT); } if (len > 0) { printf("here is the data:\n"); for (i=0; i<len; i++) printf("%c",buf[i]); } if (len == 0) { /* session closed? */ #ifdef WITH_DTLS if (check_close(ssl) <= 0) { fprintf(stderr, "not closed\n"); } #endif } else { #ifdef WITH_DTLS err = SSL_get_error(ssl,len); switch (err) { case SSL_ERROR_WANT_READ: fprintf(stderr, "SSL_ERROR_WANT_READ\n"); return 0; case SSL_ERROR_WANT_WRITE: fprintf(stderr, "SSL_ERROR_WANT_WRITE\n"); return 0; default: fprintf(stderr, "read: SSL error %d: %s\n", err, ERR_error_string(err, NULL)); return 0; } #else perror("recv"); #endif } return len; }