Added client support for ECDHE key exchange
This commit is contained in:
+103
-2
@@ -352,6 +352,100 @@ static status_t process_modp_key_exchange(private_tls_peer_t *this,
|
|||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a Key Exchange message using EC Diffie Hellman
|
||||||
|
*/
|
||||||
|
static status_t process_ec_key_exchange(private_tls_peer_t *this,
|
||||||
|
tls_reader_t *reader)
|
||||||
|
{
|
||||||
|
diffie_hellman_group_t group;
|
||||||
|
public_key_t *public;
|
||||||
|
u_int8_t type;
|
||||||
|
u_int16_t curve;
|
||||||
|
chunk_t pub, chunk;
|
||||||
|
|
||||||
|
chunk = reader->peek(reader);
|
||||||
|
if (!reader->read_uint8(reader, &type))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received invalid Server Key Exchange");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (type != TLS_ECC_NAMED_CURVE)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "ECDH curve type %N not supported",
|
||||||
|
tls_ecc_curve_type_names, type);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (!reader->read_uint16(reader, &curve) ||
|
||||||
|
!reader->read_data8(reader, &pub))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received invalid Server Key Exchange");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
switch (curve)
|
||||||
|
{
|
||||||
|
case TLS_SECP256R1:
|
||||||
|
group = ECP_256_BIT;
|
||||||
|
break;
|
||||||
|
case TLS_SECP384R1:
|
||||||
|
group = ECP_384_BIT;
|
||||||
|
break;
|
||||||
|
case TLS_SECP521R1:
|
||||||
|
group = ECP_521_BIT;
|
||||||
|
break;
|
||||||
|
case TLS_SECP192R1:
|
||||||
|
group = ECP_192_BIT;
|
||||||
|
break;
|
||||||
|
case TLS_SECP224R1:
|
||||||
|
group = ECP_224_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG1(DBG_TLS, "ECDH curve %N not supported",
|
||||||
|
tls_named_curve_names, curve);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public = find_public_key(this);
|
||||||
|
if (!public)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.len = 4 + pub.len;
|
||||||
|
chunk = chunk_cat("ccc", chunk_from_thing(this->client_random),
|
||||||
|
chunk_from_thing(this->server_random), chunk);
|
||||||
|
if (!this->crypto->verify(this->crypto, public, reader, chunk))
|
||||||
|
{
|
||||||
|
public->destroy(public);
|
||||||
|
free(chunk.ptr);
|
||||||
|
DBG1(DBG_TLS, "verifying DH parameters failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
public->destroy(public);
|
||||||
|
free(chunk.ptr);
|
||||||
|
|
||||||
|
this->dh = lib->crypto->create_dh(lib->crypto, group);
|
||||||
|
if (!this->dh)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "DH group %N not supported",
|
||||||
|
diffie_hellman_group_names, group);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
this->dh->set_other_public_value(this->dh, pub);
|
||||||
|
|
||||||
|
this->state = STATE_KEY_EXCHANGE_RECEIVED;
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a Server Key Exchange
|
* Process a Server Key Exchange
|
||||||
*/
|
*/
|
||||||
@@ -389,7 +483,7 @@ static status_t process_key_exchange(private_tls_peer_t *this,
|
|||||||
case ECP_521_BIT:
|
case ECP_521_BIT:
|
||||||
case ECP_192_BIT:
|
case ECP_192_BIT:
|
||||||
case ECP_224_BIT:
|
case ECP_224_BIT:
|
||||||
/* TODO */
|
return process_ec_key_exchange(this, reader);
|
||||||
default:
|
default:
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
@@ -797,7 +891,14 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
|
|||||||
chunk_clear(&premaster);
|
chunk_clear(&premaster);
|
||||||
|
|
||||||
this->dh->get_my_public_value(this->dh, &pub);
|
this->dh->get_my_public_value(this->dh, &pub);
|
||||||
writer->write_data16(writer, pub);
|
if (this->dh->get_dh_group(this->dh) == MODP_CUSTOM)
|
||||||
|
{
|
||||||
|
writer->write_data16(writer, pub);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* ECP uses 8bit length header only */
|
||||||
|
writer->write_data8(writer, pub);
|
||||||
|
}
|
||||||
free(pub.ptr);
|
free(pub.ptr);
|
||||||
|
|
||||||
*type = TLS_CLIENT_KEY_EXCHANGE;
|
*type = TLS_CLIENT_KEY_EXCHANGE;
|
||||||
|
|||||||
Reference in New Issue
Block a user