示例#1
0
static void
log_verify_details(as_socket* sock)
{
	long vr = SSL_get_verify_result(sock->ssl);
	if (vr != X509_V_OK) {
		as_log_info("TLS verify result: %s", X509_verify_cert_error_string(vr));
	}
}
static void
as_cluster_find_nodes_to_add(as_cluster* cluster, as_vector* /* <as_host> */ friends, as_vector* /* <as_node*> */ nodes_to_add)
{
	as_error err;
	as_error_init(&err);
	as_vector addresses;
	as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5);
	
	as_node_info node_info;

	for (uint32_t i = 0; i < friends->size; i++) {
		as_host* friend = as_vector_get(friends, i);
		as_vector_clear(&addresses);
		
		as_status status = as_lookup(&err, friend->name, friend->port, &addresses);
		
		if (status != AEROSPIKE_OK) {
			as_log_warn("%s %s", as_error_string(status), err.message);
			continue;
		}
		
		for (uint32_t i = 0; i < addresses.size; i++) {
			struct sockaddr_in* addr = as_vector_get(&addresses, i);
			status = as_lookup_node(cluster, &err, addr, &node_info);
			
			if (status == AEROSPIKE_OK) {
				as_node* node = as_cluster_find_node(cluster->nodes, nodes_to_add, node_info.name);
				
				if (node) {
					// Duplicate node name found.  This usually occurs when the server
					// services list contains both internal and external IP addresses
					// for the same node.  Add new host to list of alias filters
					// and do not add new node.
					as_close(node_info.fd);
					as_address* a = as_node_get_address_full(node);
					as_log_info("Node %s:%d already exists with nodeid %s and address %s:%d", 
						friend->name, friend->port, node->name, a->name,
						(int)cf_swap_from_be16(a->addr.sin_port));
					node->friends++;
					as_node_add_address(node, friend, addr);
					continue;
				}
				
				node = as_node_create(cluster, friend, addr, &node_info);
				as_address* a = as_node_get_address_full(node);
				as_log_info("Add node %s %s:%d", node_info.name, a->name, (int)cf_swap_from_be16(a->addr.sin_port));
				as_vector_append(nodes_to_add, &node);
			}
			else {
				as_log_warn("Failed to connect to friend %s:%d. %s %s", friend->name, friend->port, as_error_string(status), err.message);
			}
		}
示例#3
0
static void
log_session_info(as_socket* sock)
{
	if (! sock->ctx->log_session_info)
		return;
	
	SSL_CIPHER const* cipher = SSL_get_current_cipher(sock->ssl);
	if (cipher) {
		char desc[1024];
		SSL_CIPHER_description(cipher, desc, sizeof(desc));
		size_t len = strlen(desc);
		if (len > 0) {
			desc[len-1] = '\0';	// Trim trailing \n
		}
		as_log_info("TLS cipher: %s", desc);
	}
	else {
		as_log_warn("TLS no current cipher");
	}
}
static as_status
as_cluster_seed_nodes(as_cluster* cluster, as_error* err, bool enable_warnings)
{
	// Add all nodes at once to avoid copying entire array multiple times.
	as_vector nodes_to_add;
	as_vector_inita(&nodes_to_add, sizeof(as_node*), 64);
	
	as_vector addresses;
	as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5);
	
	as_node_info node_info;
	as_error error_local;
	as_error_init(&error_local); // AEROSPIKE_ERR_TIMEOUT doesn't come with a message; make sure it's initialized.
	as_status status = AEROSPIKE_OK;
	
	as_seeds* seeds = as_seeds_reserve(cluster);

	for (uint32_t i = 0; i < seeds->size; i++) {
		as_seed* seed = &seeds->array[i];
		as_vector_clear(&addresses);
		
		status = as_lookup(&error_local, seed->name, seed->port, &addresses);
		
		if (status != AEROSPIKE_OK) {
			if (enable_warnings) {
				as_log_warn("Failed to lookup %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message);
			}
			continue;
		}

		for (uint32_t i = 0; i < addresses.size; i++) {
			struct sockaddr_in* addr = as_vector_get(&addresses, i);
			status = as_lookup_node(cluster, &error_local, addr, &node_info);
			
			if (status == AEROSPIKE_OK) {
				as_host host;
				if (as_strncpy(host.name, seed->name, sizeof(host.name))) {
					as_log_warn("Hostname has been truncated: %s", host.name);
				}
				host.port = seed->port;

				as_node* node = as_cluster_find_node_in_vector(&nodes_to_add, node_info.name);
				
				if (node) {
					as_close(node_info.fd);
					as_node_add_address(node, &host, addr);
				}
				else {
					node = as_node_create(cluster, &host, addr, &node_info);
					as_address* a = as_node_get_address_full(node);
					as_log_info("Add node %s %s:%d", node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port));
					as_vector_append(&nodes_to_add, &node);
				}
			}
			else {
				if (enable_warnings) {
					as_log_warn("Failed to connect to seed %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message);
				}
			}
		}
	}
	
	as_seeds_release(seeds);

	if (nodes_to_add.size > 0) {
		as_cluster_add_nodes(cluster, &nodes_to_add);
		status = AEROSPIKE_OK;
	}
	else {
		status = as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to seed cluster");
	}
	
	as_vector_destroy(&nodes_to_add);
	as_vector_destroy(&addresses);
	return status;
}
示例#5
0
as_status
as_tls_context_setup(as_config_tls* tlscfg, as_tls_context* ctx, as_error* errp)
{
	// Clear the destination, in case we don't make it.
	ctx->ssl_ctx = NULL;
	ctx->pkey = NULL;
	ctx->cert_blacklist = NULL;
	ctx->log_session_info = tlscfg->log_session_info;
	ctx->for_login_only = tlscfg->for_login_only;

	as_tls_check_init();
	pthread_mutex_init(&ctx->lock, NULL);

	if (tlscfg->cert_blacklist) {
		ctx->cert_blacklist = cert_blacklist_read(tlscfg->cert_blacklist);

		if (! ctx->cert_blacklist) {
			as_tls_context_destroy(ctx);
			return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								   "Failed to read certificate blacklist: %s",
								   tlscfg->cert_blacklist);
		}
	}
	
	uint16_t protocols = AS_TLS_PROTOCOL_NONE;
	as_status status = protocols_parse(tlscfg, &protocols, errp);

	if (status != AEROSPIKE_OK) {
		as_tls_context_destroy(ctx);
		return status;
	}

	const SSL_METHOD* method = NULL;

	// If the selected protocol set is a single protocol we can use a specific method.
	if (protocols == AS_TLS_PROTOCOL_TLSV1) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_client_method();
#endif
	}
	else if (protocols == AS_TLS_PROTOCOL_TLSV1_1) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_1_client_method();
#endif
	}
	else if (protocols == AS_TLS_PROTOCOL_TLSV1_2) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_2_client_method();
#endif
	}
	else {
		// Multiple protocols are enabled, use a flexible method.
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = SSLv23_client_method();
#endif
	}

	ctx->ssl_ctx = SSL_CTX_new(method);

	if (ctx->ssl_ctx == NULL) {
		as_tls_context_destroy(ctx);

		unsigned long errcode = ERR_get_error();
		char errbuf[1024];
		ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
		return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							   "Failed to create new TLS context: %s", errbuf);
	}

	/* always disable SSLv2, as per RFC 6176 */
    SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);

	// Turn off non-enabled protocols.
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
    }
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1_1)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
    }
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1_2)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);
    }
	
	if (tlscfg->cafile || tlscfg->capath) {
		int rv = SSL_CTX_load_verify_locations(ctx->ssl_ctx, tlscfg->cafile, tlscfg->capath);

		if (rv != 1) {
			as_tls_context_destroy(ctx);

			char errbuf[1024];
			unsigned long errcode = ERR_get_error();

			if (errcode != 0) {
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
									   "Failed to load CAFile: %s", errbuf);
			}
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"Unknown failure loading CAFile");
		}
	}

	if (tlscfg->certfile) {
		int rv = SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, tlscfg->certfile);

		if (rv != 1) {
			// We seem to be seeing this bug:
			// https://groups.google.com/
			//          forum/#!topic/mailing.openssl.users/nRvRzmKnEQA
			// If the rv is not 1 check the error stack; if it doesn't have an
			// error assume we are OK.
			//
			unsigned long errcode = ERR_peek_error();

			if (errcode != SSL_ERROR_NONE) {
				// There *was* an error after all.
				as_tls_context_destroy(ctx);

				unsigned long errcode = ERR_get_error();
				char errbuf[1024];
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
									   "SSL_CTX_use_certificate_chain_file failed: %s",
									   errbuf);
			}
		}
	}

	if (tlscfg->keyfile) {
		bool ok = false;
		FILE *fh = fopen(tlscfg->keyfile, "r");

		if (fh == NULL) {
			as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
					"failed to open key file %s: %s", tlscfg->keyfile,
					strerror(errno));
		}
		else {
			EVP_PKEY *pkey = PEM_read_PrivateKey(fh, NULL, password_cb,
					tlscfg->keyfile_pw);

			if (pkey == NULL) {
				unsigned long errcode = ERR_get_error();

				if (ERR_GET_REASON(errcode) == PEM_R_BAD_PASSWORD_READ) {
					if (tlscfg->keyfile_pw == NULL) {
						as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								"key file %s requires a password",
								tlscfg->keyfile);
					}
					else {
						as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								"password for key file %s too long",
								tlscfg->keyfile);
					}
				}
				else if (ERR_GET_REASON(errcode) == EVP_R_BAD_DECRYPT) {
					as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							"invalid password for key file %s",
							tlscfg->keyfile);
				}
				else {
					char errbuf[1024];
					ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
					as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							"PEM_read_PrivateKey failed: %s", errbuf);
				}
			}
			else {
				ctx->pkey = pkey;
				SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey);
				ok = true;
			}

			fclose(fh);
		}

		if (!ok) {
			as_tls_context_destroy(ctx);
			return AEROSPIKE_ERR_TLS_ERROR;
		}
	}

	if (tlscfg->cipher_suite) {
		int rv = SSL_CTX_set_cipher_list(ctx->ssl_ctx, tlscfg->cipher_suite);

		if (rv != 1) {
			as_tls_context_destroy(ctx);
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"no compatible cipher found");
		}
		// It's bogus that we have to create an SSL just to get the
		// cipher list, but SSL_CTX_get_ciphers doesn't appear to
		// exist ...
		SSL* ssl = SSL_new(ctx->ssl_ctx);

		for (int prio = 0; true; ++prio) {
			char const * cipherstr = SSL_get_cipher_list(ssl, prio);
			if (!cipherstr) {
				break;
			}
			as_log_info("cipher %d: %s", prio+1, cipherstr);
		}
		SSL_free(ssl);
	}

	if (tlscfg->crl_check || tlscfg->crl_check_all) {
		X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
		unsigned long flags = X509_V_FLAG_CRL_CHECK;

		if (tlscfg->crl_check_all) {
			flags |= X509_V_FLAG_CRL_CHECK_ALL;
		}

		X509_VERIFY_PARAM_set_flags(param, flags);
		SSL_CTX_set1_param(ctx->ssl_ctx, param);
		X509_VERIFY_PARAM_free(param);
	}

	SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, verify_callback);
	manage_sigpipe();
	return AEROSPIKE_OK;
}
示例#6
0
static int verify_callback(int preverify_ok, X509_STORE_CTX* ctx)
{
	// If the cert has already failed we're done.
	if (! preverify_ok) {
		return preverify_ok;
	}

    SSL* ssl = X509_STORE_CTX_get_ex_data(
					ctx, SSL_get_ex_data_X509_STORE_CTX_idx());

	// The verify callback is called for each cert in the chain.
	
    X509* current_cert = X509_STORE_CTX_get_current_cert(ctx);

	as_tls_context* asctxt = SSL_get_ex_data(ssl, s_ex_ctxt_index);
	if (! asctxt) {
		as_log_warn("Missing as_tls_context in TLS verify callback");
		return 0;
	}

	pthread_mutex_lock(&asctxt->lock);

	if (asctxt->cert_blacklist) {
		// Is this cert blacklisted?
		char name[256];
		X509_NAME* iname = X509_get_issuer_name(current_cert);
		X509_NAME_oneline(iname, name, sizeof(name));
		
		ASN1_INTEGER* sn = X509_get_serialNumber(current_cert);
		BIGNUM* snbn = ASN1_INTEGER_to_BN(sn, NULL);
		char* snhex = BN_bn2hex(snbn);

		as_log_info("CERT: %s %s", snhex, name);

		bool blacklisted =
			cert_blacklist_check(asctxt->cert_blacklist, snhex, name);

		OPENSSL_free(snhex);
		BN_free(snbn);

		if (blacklisted) {
			as_log_warn("CERT: BLACKLISTED");
			pthread_mutex_unlock(&asctxt->lock);
			return 0;
		}
	}

	pthread_mutex_unlock(&asctxt->lock);

	// If this is the peer cert, check the name
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
	X509* cert = X509_STORE_CTX_get0_cert(ctx);
#else
	X509* cert = ctx->cert;
#endif

	if (current_cert == cert) {
		char * hostname = SSL_get_ex_data(ssl, s_ex_name_index);

		if (! hostname) {
			as_log_warn("Missing hostname in TLS verify callback");
			return 0;
		}

		bool allow_wildcard = true;
		bool matched = as_tls_match_name(cert, hostname, allow_wildcard);

		if (matched) {
			as_log_debug("TLS name '%s' matches", hostname);
		}
		else {
			as_log_warn("TLS name '%s' mismatch", hostname);
		}

		return matched ? 1 : 0;
	}

	// If we make it here we are a root or chain cert and are not
	// blacklisted.
	return 1;
}