encoding: Verify the length of KE payload data for known groups
authorMartin Willi <martin@revosec.ch>
Tue, 3 Feb 2015 15:40:14 +0000 (16:40 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 18 Mar 2015 12:33:25 +0000 (13:33 +0100)
IKE is very strict in the length of KE payloads, and it should be safe to
strictly verify their length. Not doing so is no direct threat, but allows DDoS
amplification by sending short KE payloads for large groups using the target
as the source address.

src/libcharon/encoding/payloads/ke_payload.c

index 4f552d6..644b5b6 100644 (file)
@@ -142,6 +142,73 @@ static encoding_rule_t encodings_v1[] = {
 METHOD(payload_t, verify, status_t,
        private_ke_payload_t *this)
 {
+       diffie_hellman_params_t *params;
+       diffie_hellman_group_t g = this->dh_group_number;
+       bool valid = TRUE;
+
+       switch (g)
+       {
+               case MODP_NONE:
+                       valid = FALSE;
+                       break;
+               case MODP_768_BIT:
+               case MODP_1024_BIT:
+               case MODP_1536_BIT:
+               case MODP_2048_BIT:
+               case MODP_3072_BIT:
+               case MODP_4096_BIT:
+               case MODP_6144_BIT:
+               case MODP_8192_BIT:
+               case MODP_1024_160:
+               case MODP_2048_224:
+               case MODP_2048_256:
+                       params = diffie_hellman_get_params(g);
+                       if (params)
+                       {
+                               valid = this->key_exchange_data.len == params->prime.len;
+                       }
+                       break;
+               case ECP_192_BIT:
+                       valid = this->key_exchange_data.len == 48;
+                       break;
+               case ECP_224_BIT:
+               case ECP_224_BP:
+                       valid = this->key_exchange_data.len == 56;
+                       break;
+               case ECP_256_BIT:
+               case ECP_256_BP:
+                       valid = this->key_exchange_data.len == 64;
+                       break;
+               case ECP_384_BIT:
+               case ECP_384_BP:
+                       valid = this->key_exchange_data.len == 96;
+                       break;
+               case ECP_512_BP:
+                       valid = this->key_exchange_data.len == 128;
+                       break;
+               case ECP_521_BIT:
+                       valid = this->key_exchange_data.len == 132;
+                       break;
+               case NTRU_112_BIT:
+               case NTRU_128_BIT:
+               case NTRU_192_BIT:
+               case NTRU_256_BIT:
+                       /* NTRU public key size depends on the parameter set, but is
+                        * at least 512 bytes */
+                       valid = this->key_exchange_data.len > 512;
+                       break;
+               case MODP_NULL:
+               case MODP_CUSTOM:
+                       break;
+               /* compile-warn unhandled groups, but accept them so we can negotiate
+                * a different group that we support. */
+       }
+       if (!valid)
+       {
+               DBG1(DBG_ENC, "invalid KE data size (%zu bytes) for %N",
+                        this->key_exchange_data.len, diffie_hellman_group_names, g);
+               return FAILED;
+       }
        return SUCCESS;
 }