Prepend point format to ECDH public key
authorMartin Willi <martin@revosec.ch>
Mon, 6 Sep 2010 13:31:32 +0000 (15:31 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 6 Sep 2010 13:37:51 +0000 (15:37 +0200)
src/libtls/tls_crypto.c
src/libtls/tls_crypto.h
src/libtls/tls_peer.c
src/libtls/tls_server.c

index 49ee88d..12d543e 100644 (file)
@@ -306,6 +306,14 @@ ENUM(tls_named_curve_names, TLS_SECT163K1, TLS_SECP521R1,
        "SECP521R1",
 );
 
+ENUM(tls_ecp_format_names, TLS_ECP_COMPRESSED, TLS_ECP_HYBRID_Y,
+       "compressed",
+       "compressed y",
+       "uncompressed",
+       "uncompressed y",
+       "hybrid",
+       "hybrid y",
+);
 
 typedef struct private_tls_crypto_t private_tls_crypto_t;
 
index cc83df3..b41ae5f 100644 (file)
@@ -359,6 +359,22 @@ enum tls_named_curve_t {
 extern enum_name_t *tls_named_curve_names;
 
 /**
+ * EC Point format, ANSI X9.62.
+ */
+enum tls_ecp_format_t {
+       TLS_ECP_COMPRESSED =    2,
+       TLS_ECP_COMPRESSED_Y =  3,
+       TLS_ECP_UNCOMPRESSED =  4,
+       TLS_ECP_HYBRID =                6,
+       TLS_ECP_HYBRID_Y =              7,
+};
+
+/**
+ * Enum names for tls_ecp_format_t.
+ */
+extern enum_name_t *tls_ecp_format_names;
+
+/**
  * TLS crypto helper functions.
  */
 struct tls_crypto_t {
index d6d6976..ac22bd1 100644 (file)
@@ -402,7 +402,7 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
                return NEED_MORE;
        }
        if (!reader->read_uint16(reader, &curve) ||
-               !reader->read_data8(reader, &pub))
+               !reader->read_data8(reader, &pub) || pub.len == 0)
        {
                DBG1(DBG_TLS, "received invalid Server Key Exchange");
                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
@@ -448,7 +448,15 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
                return NEED_MORE;
        }
-       this->dh->set_other_public_value(this->dh, pub);
+
+       if (pub.ptr[0] != TLS_ECP_UNCOMPRESSED)
+       {
+               DBG1(DBG_TLS, "DH point format '%N' not supported",
+                        tls_ecp_format_names, pub.ptr[0]);
+               this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
+               return NEED_MORE;
+       }
+       this->dh->set_other_public_value(this->dh, chunk_skip(pub, 1));
 
        this->state = STATE_KEY_EXCHANGE_RECEIVED;
        return NEED_MORE;
@@ -908,8 +916,10 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
                writer->write_data16(writer, pub);
        }
        else
-       {       /* ECP uses 8bit length header only */
-               writer->write_data8(writer, pub);
+       {       /* ECP uses 8bit length header only, but a point format */
+               writer->write_uint8(writer, pub.len + 1);
+               writer->write_uint8(writer, TLS_ECP_UNCOMPRESSED);
+               writer->write_data(writer, pub);
        }
        free(pub.ptr);
 
index 409fe83..e48e6c5 100644 (file)
@@ -412,13 +412,21 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
 
        ec = diffie_hellman_group_is_ec(this->dh->get_dh_group(this->dh));
        if ((ec && !reader->read_data8(reader, &pub)) ||
-               (!ec && !reader->read_data16(reader, &pub)))
+               (!ec && (!reader->read_data16(reader, &pub) || pub.len == 0)))
        {
                DBG1(DBG_TLS, "received invalid Client Key Exchange");
                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                return NEED_MORE;
        }
-       this->dh->set_other_public_value(this->dh, pub);
+
+       if (pub.ptr[0] != TLS_ECP_UNCOMPRESSED)
+       {
+               DBG1(DBG_TLS, "DH point format '%N' not supported",
+                        tls_ecp_format_names, pub.ptr[0]);
+               this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
+               return NEED_MORE;
+       }
+       this->dh->set_other_public_value(this->dh, chunk_skip(pub, 1));
        if (this->dh->get_shared_secret(this->dh, &premaster) != SUCCESS)
        {
                DBG1(DBG_TLS, "calculating premaster from DH failed");
@@ -847,8 +855,10 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
                writer->write_data16(writer, chunk);
        }
        else
-       {       /* 8bit header for EC groups */
-               writer->write_data8(writer, chunk);
+       {       /* ECP uses 8bit length header only, but a point format */
+               writer->write_uint8(writer, chunk.len + 1);
+               writer->write_uint8(writer, TLS_ECP_UNCOMPRESSED);
+               writer->write_data(writer, chunk);
        }
        free(chunk.ptr);