int verify(SSL *ssl, const char *hostname, int port, const neo4j_config_t *config, uint_fast32_t flags, neo4j_logger_t *logger) { X509 *cert = SSL_get_peer_certificate(ssl); if (cert == NULL) { errno = NEO4J_TLS_VERIFICATION_FAILED; return -1; } int result = -1; char fingerprint[SHA512_DIGEST_LENGTH * 2]; if (cert_fingerprint(cert, fingerprint, sizeof(fingerprint), logger)) { goto cleanup; } neo4j_log_debug(logger, "server cert fingerprint: %s", fingerprint); long verification = SSL_get_verify_result(ssl); switch (verification) { case X509_V_OK: // TODO: verify that the certificate matches hostname/port neo4j_log_debug(logger, "certificate verified using CA"); result = 0; goto cleanup; // TODO: check other verification codes for unacceptable certificates default: break; } if (!(config->trust_known)) { errno = NEO4J_TLS_VERIFICATION_FAILED; goto cleanup; } result = neo4j_check_known_hosts(hostname, port, fingerprint, config, flags); if (result > 0) { errno = NEO4J_TLS_VERIFICATION_FAILED; result = -1; } cleanup: X509_free(cert); return result; }
int neo4j_connect_tcp_socket(const char *hostname, const char *servname, const neo4j_config_t *config, neo4j_logger_t *logger) { REQUIRE(hostname != NULL, -1); struct addrinfo hints; struct addrinfo *candidate_addresses = NULL; int err = 0; init_getaddrinfo_hints(&hints); err = getaddrinfo(hostname, servname, &hints, &candidate_addresses); if (err) { errno = NEO4J_UNKNOWN_HOST; return -1; } int fd = -1; struct addrinfo *addr; for (addr = candidate_addresses; addr != NULL; addr = addr->ai_next) { fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (fd < 0) { if (!unsupported_sock_error(errno)) continue; neo4j_log_error_errno(logger, "socket"); freeaddrinfo(candidate_addresses); return -1; } set_socket_options(fd, config, logger); char hostnum[NI_MAXHOST]; char servnum[NI_MAXSERV]; err = getnameinfo(addr->ai_addr, addr->ai_addrlen, hostnum, sizeof(hostnum), servnum, sizeof(servnum), NI_NUMERICHOST | NI_NUMERICSERV); if (err) { neo4j_log_error(logger, "getnameinfo: %s", gai_strerror(err)); freeaddrinfo(candidate_addresses); errno = NEO4J_UNEXPECTED_ERROR; return -1; } neo4j_log_debug(logger, "attempting connection to %s [%s]", hostnum, servnum); err = connect_with_timeout(fd, addr->ai_addr, addr->ai_addrlen, config->connect_timeout, logger); if (err == 0) { break; } else if (err < 0) { return -1; } char ebuf[256]; neo4j_log_info(logger, "connection to %s [%s] failed: %s", hostnum, servnum, neo4j_strerror(errno, ebuf, sizeof(ebuf))); close(fd); fd = -1; } freeaddrinfo(candidate_addresses); return fd; }