Commit message: None
CVE: CVE-2018-5388
CWE: CWE-787
Vulnerability description: In stroke_socket.c in strongSwan before 5.6.3, a missing packet length check could allow a buffer underflow, which may lead to resource exhaustion and denial of service while reading from the socket.

Project: strongswan

static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
{
	pop_string(msg, &end->address);
	pop_string(msg, &end->subnets);
	pop_string(msg, &end->sourceip);
	pop_string(msg, &end->dns);
	pop_string(msg, &end->auth);
	pop_string(msg, &end->auth2);
	pop_string(msg, &end->id);
	pop_string(msg, &end->id2);
	pop_string(msg, &end->rsakey);
	pop_string(msg, &end->cert);
	pop_string(msg, &end->cert2);
	pop_string(msg, &end->ca);
	pop_string(msg, &end->ca2);
	pop_string(msg, &end->groups);
	pop_string(msg, &end->groups2);
	pop_string(msg, &end->cert_policy);
	pop_string(msg, &end->updown);

	DBG_OPT("  %s=%s", label, end->address);
	DBG_OPT("  %ssubnet=%s", label, end->subnets);
	DBG_OPT("  %ssourceip=%s", label, end->sourceip);
	DBG_OPT("  %sdns=%s", label, end->dns);
	DBG_OPT("  %sauth=%s", label, end->auth);
	DBG_OPT("  %sauth2=%s", label, end->auth2);
	DBG_OPT("  %sid=%s", label, end->id);
	DBG_OPT("  %sid2=%s", label, end->id2);
	DBG_OPT("  %srsakey=%s", label, end->rsakey);
	DBG_OPT("  %scert=%s", label, end->cert);
	DBG_OPT("  %scert2=%s", label, end->cert2);
	DBG_OPT("  %sca=%s", label, end->ca);
	DBG_OPT("  %sca2=%s", label, end->ca2);
	DBG_OPT("  %sgroups=%s", label, end->groups);
	DBG_OPT("  %sgroups2=%s", label, end->groups2);
	DBG_OPT("  %supdown=%s", label, end->updown);
}

Project: strongswan

static void pop_string(stroke_msg_t *msg, char **string)
{
	if (*string == NULL)
	{
		return;
	}

	/* check for sanity of string pointer and string */
	if (string < (char**)msg ||
		string > (char**)((char*)msg + sizeof(stroke_msg_t)) ||
		(unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) ||
		(unsigned long)*string > msg->length)
	{
		*string = "(invalid pointer in stroke msg)";
	}
	else
	{
		*string = (char*)msg + (unsigned long)*string;
	}
}

Project: strongswan

static void print_pem_cert(FILE *out, certificate_t *cert)
{
	chunk_t encoded;

	if (cert->get_encoding(cert, CERT_PEM, &encoded))
	{
		fprintf(out, "%.*s", (int)encoded.len, encoded.ptr);
		free(encoded.ptr);
	}
}

Project: strongswan

static void stroke_add_ca(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->add_ca.name);
	DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);

	pop_string(msg, &msg->add_ca.cacert);
	pop_string(msg, &msg->add_ca.crluri);
	pop_string(msg, &msg->add_ca.crluri2);
	pop_string(msg, &msg->add_ca.ocspuri);
	pop_string(msg, &msg->add_ca.ocspuri2);
	pop_string(msg, &msg->add_ca.certuribase);
	DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
	DBG_OPT("  cacert=%s", msg->add_ca.cacert);
	DBG_OPT("  crluri=%s", msg->add_ca.crluri);
	DBG_OPT("  crluri2=%s", msg->add_ca.crluri2);
	DBG_OPT("  ocspuri=%s", msg->add_ca.ocspuri);
	DBG_OPT("  ocspuri2=%s", msg->add_ca.ocspuri2);
	DBG_OPT("  certuribase=%s", msg->add_ca.certuribase);

	this->ca->add(this->ca, msg);
}

Project: strongswan

static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
{
	pop_string(msg, &msg->add_conn.name);
	DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);

	DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
	pop_end(msg, "left", &msg->add_conn.me);
	pop_end(msg, "right", &msg->add_conn.other);
	pop_string(msg, &msg->add_conn.eap_identity);
	pop_string(msg, &msg->add_conn.aaa_identity);
	pop_string(msg, &msg->add_conn.xauth_identity);
	pop_string(msg, &msg->add_conn.algorithms.ike);
	pop_string(msg, &msg->add_conn.algorithms.esp);
	pop_string(msg, &msg->add_conn.algorithms.ah);
	pop_string(msg, &msg->add_conn.ikeme.mediated_by);
	pop_string(msg, &msg->add_conn.ikeme.peerid);
	DBG_OPT("  eap_identity=%s", msg->add_conn.eap_identity);
	DBG_OPT("  aaa_identity=%s", msg->add_conn.aaa_identity);
	DBG_OPT("  xauth_identity=%s", msg->add_conn.xauth_identity);
	DBG_OPT("  ike=%s", msg->add_conn.algorithms.ike);
	DBG_OPT("  esp=%s", msg->add_conn.algorithms.esp);
	DBG_OPT("  ah=%s", msg->add_conn.algorithms.ah);
	DBG_OPT("  dpddelay=%d", msg->add_conn.dpd.delay);
	DBG_OPT("  dpdtimeout=%d", msg->add_conn.dpd.timeout);
	DBG_OPT("  dpdaction=%d", msg->add_conn.dpd.action);
	DBG_OPT("  closeaction=%d", msg->add_conn.close_action);
	DBG_OPT("  sha256_96=%s", msg->add_conn.sha256_96 ? "yes" : "no");
	DBG_OPT("  mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
	DBG_OPT("  mediated_by=%s", msg->add_conn.ikeme.mediated_by);
	DBG_OPT("  me_peerid=%s", msg->add_conn.ikeme.peerid);
	DBG_OPT("  keyexchange=ikev%u", msg->add_conn.version);

	this->config->add(this->config, msg);
	this->attribute->add_dns(this->attribute, msg);
	this->handler->add_attributes(this->handler, msg);
}

Project: strongswan

static void stroke_config(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	this->cred->cachecrl(this->cred, msg->config.cachecrl);
}

Project: strongswan

static void stroke_counters(private_stroke_socket_t *this,
							  stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->counters.name);

	if (msg->counters.reset)
	{
		this->counter->reset(this->counter, msg->counters.name);
	}
	else
	{
		this->counter->print(this->counter, out, msg->counters.name);
	}
}

Project: strongswan

static void stroke_del_ca(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->del_ca.name);
	DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);

	this->ca->del(this->ca, msg);
}

Project: strongswan

static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
{
	pop_string(msg, &msg->del_conn.name);
	DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);

	this->config->del(this->config, msg);
	this->attribute->del_dns(this->attribute, msg);
	this->handler->del_attributes(this->handler, msg);
}

Project: strongswan

static void stroke_export(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->export.selector);

	if (msg->export.flags & EXPORT_X509)
	{
		enumerator_t *enumerator;
		identification_t *id;
		certificate_t *cert;

		id = identification_create_from_string(msg->export.selector);
		enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
												CERT_X509, KEY_ANY, id, FALSE);
		while (enumerator->enumerate(enumerator, &cert))
		{
			print_pem_cert(out, cert);
		}
		enumerator->destroy(enumerator);
		id->destroy(id);
	}

	if (msg->export.flags & (EXPORT_CONN_CERT | EXPORT_CONN_CHAIN))
	{
		enumerator_t *sas, *auths, *certs;
		ike_sa_t *ike_sa;
		auth_cfg_t *auth;
		certificate_t *cert;
		auth_rule_t rule;

		sas = charon->ike_sa_manager->create_enumerator(
												charon->ike_sa_manager, TRUE);
		while (sas->enumerate(sas, &ike_sa))
		{
			if (streq(msg->export.selector, ike_sa->get_name(ike_sa)))
			{
				auths = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE);
				while (auths->enumerate(auths, &auth))
				{
					bool got_subject = FALSE;

					certs = auth->create_enumerator(auth);
					while (certs->enumerate(certs, &rule, &cert))
					{
						switch (rule)
						{
							case AUTH_RULE_CA_CERT:
							case AUTH_RULE_IM_CERT:
								if (msg->export.flags & EXPORT_CONN_CHAIN)
								{
									print_pem_cert(out, cert);
								}
								break;
							case AUTH_RULE_SUBJECT_CERT:
								if (!got_subject)
								{
									print_pem_cert(out, cert);
									got_subject = TRUE;
								}
								break;
							default:
								break;
						}
					}
					certs->destroy(certs);
				}
				auths->destroy(auths);
			}
		}
		sas->destroy(sas);
	}
}

Project: strongswan

static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->initiate.name);
	DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);

	this->control->initiate(this->control, msg, out);
}

Project: strongswan

static void stroke_leases(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->leases.pool);
	pop_string(msg, &msg->leases.address);

	this->list->leases(this->list, msg, out);
}

Project: strongswan

static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg,
						FILE *out)
{
	if (msg->list.flags & LIST_CAINFOS)
	{
		this->ca->list(this->ca, msg, out);
	}
	this->list->list(this->list, msg, out);
}

Project: strongswan

static void stroke_loglevel(private_stroke_socket_t *this,
							stroke_msg_t *msg, FILE *out)
{
	debug_t group;

	pop_string(msg, &(msg->loglevel.type));
	DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
		 msg->loglevel.level, msg->loglevel.type);

	if (this->prevent_loglevel_changes)
	{
		DBG1(DBG_CFG, "prevented log level change");
		fprintf(out, "command not allowed!\n");
		return;
	}
	if (!enum_from_name(debug_names, msg->loglevel.type, &group))
	{
		fprintf(out, "unknown type '%s'!\n", msg->loglevel.type);
		return;
	}
	charon->set_level(charon, group, msg->loglevel.level);
}

Project: strongswan

static void stroke_purge(private_stroke_socket_t *this,
						 stroke_msg_t *msg, FILE *out)
{
	if (msg->purge.flags & PURGE_OCSP)
	{
		lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE);
	}
	if (msg->purge.flags & PURGE_CRLS)
	{
		lib->credmgr->flush_cache(lib->credmgr, CERT_X509_CRL);
	}
	if (msg->purge.flags & PURGE_CERTS)
	{
		lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
	}
	if (msg->purge.flags & PURGE_IKE)
	{
		this->control->purge_ike(this->control, msg, out);
	}
}

Project: strongswan

static void stroke_reread(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out)
{
	this->cred->reread(this->cred, msg, out);
}

Project: strongswan

static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->route.name);
	DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);

	this->control->route(this->control, msg, out);
}

Project: strongswan

static void stroke_status(private_stroke_socket_t *this,
						  stroke_msg_t *msg, FILE *out, bool all, bool wait)
{
	pop_string(msg, &(msg->status.name));

	this->list->status(this->list, msg, out, all, wait);
}

Project: strongswan

static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->terminate.name);
	DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);

	this->control->terminate(this->control, msg, out);
}

Project: strongswan

static void stroke_terminate_srcip(private_stroke_socket_t *this,
								   stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->terminate_srcip.start);
	pop_string(msg, &msg->terminate_srcip.end);
	DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s",
		 msg->terminate_srcip.start, msg->terminate_srcip.end);

	this->control->terminate_srcip(this->control, msg, out);
}

Project: strongswan

static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
{
	pop_string(msg, &msg->terminate.name);
	DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name);

	this->control->unroute(this->control, msg, out);
}

Project: strongswan

static void sum_usage(FILE *out, int count, size_t bytes, int whitelisted)
{
	fprintf(out, "Total memory usage: %zu\n", bytes);
}