Esempio n. 1
0
bool send_metakey(connection_t *c) {
	if(!myself->connection->rsa) {
		logger(DEBUG_CONNECTIONS, LOG_ERR, "Peer %s (%s) uses legacy protocol which we don't support", c->name, c->hostname);
		return false;
	}

	if(!read_rsa_public_key(c))
		return false;

	if(!(c->outcipher = cipher_open_blowfish_ofb()))
		return false;

	if(!(c->outdigest = digest_open_sha1(-1)))
		return false;

	const size_t len = rsa_size(c->rsa);
	char key[len];
	char enckey[len];
	char hexkey[2 * len + 1];

	/* Create a random key */

	randomize(key, len);

	/* The message we send must be smaller than the modulus of the RSA key.
	   By definition, for a key of k bits, the following formula holds:

	   2^(k-1) <= modulus < 2^(k)

	   Where ^ means "to the power of", not "xor".
	   This means that to be sure, we must choose our message < 2^(k-1).
	   This can be done by setting the most significant bit to zero.
	 */

	key[0] &= 0x7F;

	if(!cipher_set_key_from_rsa(c->outcipher, key, len, true))
		return false;

	if(debug_level >= DEBUG_SCARY_THINGS) {
		bin2hex(key, hexkey, len);
		logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Generated random meta key (unencrypted): %s", hexkey);
	}

	/* Encrypt the random data

	   We do not use one of the PKCS padding schemes here.
	   This is allowed, because we encrypt a totally random string
	   with a length equal to that of the modulus of the RSA key.
	 */

	if(!rsa_public_encrypt(c->rsa, key, len, enckey)) {
		logger(DEBUG_ALWAYS, LOG_ERR, "Error during encryption of meta key for %s (%s)", c->name, c->hostname);
		return false;
	}

	/* Convert the encrypted random data to a hexadecimal formatted string */

	bin2hex(enckey, hexkey, len);

	/* Send the meta key */

	bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
			 cipher_get_nid(c->outcipher),
			 digest_get_nid(c->outdigest), c->outmaclength,
			 c->outcompression, hexkey);

	c->status.encryptout = true;
	return result;
}
Esempio n. 2
0
bool id_h(connection_t *c) {
	char name[MAX_STRING_SIZE];

	if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
		logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name,
		       c->hostname);
		return false;
	}

	/* Check if identity is a valid name */

	if(!check_id(name) || !strcmp(name, myself->name)) {
		logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name,
		       c->hostname, "invalid name");
		return false;
	}

	/* If this is an outgoing connection, make sure we are connected to the right host */

	if(c->outgoing) {
		if(strcmp(c->name, name)) {
			logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name,
			       c->name);
			return false;
		}
	} else {
		if(c->name) {
			free(c->name);
		}

		c->name = xstrdup(name);
	}

	/* Check if version matches */

	if(c->protocol_version != myself->connection->protocol_version) {
		logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d",
		       c->name, c->hostname, c->protocol_version);
		return false;
	}

	if(bypass_security) {
		if(!c->config_tree) {
			init_configuration(&c->config_tree);
		}

		c->allow_request = ACK;

		if(!c->outgoing) {
			send_id(c);
		}

		return send_ack(c);
	}

	if(!c->config_tree) {
		init_configuration(&c->config_tree);

		if(!read_connection_config(c)) {
			logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname,
			       c->name);
			return false;
		}
	}

	if(!read_rsa_public_key(c)) {
		return false;
	}

	c->allow_request = METAKEY;

	if(!c->outgoing) {
		send_id(c);
	}

	return send_metakey(c);
}