diffie-hellman: Verify public DH values in backends
authorMartin Willi <martin@revosec.ch>
Mon, 23 Mar 2015 13:32:11 +0000 (14:32 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 23 Mar 2015 16:54:03 +0000 (17:54 +0100)
src/libstrongswan/crypto/diffie_hellman.c
src/libstrongswan/crypto/diffie_hellman.h
src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c
src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
src/libstrongswan/plugins/pkcs11/pkcs11_dh.c

index ac106e9..0d4cd91 100644 (file)
@@ -501,3 +501,75 @@ bool diffie_hellman_group_is_ec(diffie_hellman_group_t group)
                        return FALSE;
        }
 }
+
+/**
+ * See header.
+ */
+bool diffie_hellman_verify_value(diffie_hellman_group_t group, chunk_t value)
+{
+       diffie_hellman_params_t *params;
+       bool valid = FALSE;
+
+       switch (group)
+       {
+               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(group);
+                       if (params)
+                       {
+                               valid = value.len == params->prime.len;
+                       }
+                       break;
+               case ECP_192_BIT:
+                       valid = value.len == 48;
+                       break;
+               case ECP_224_BIT:
+               case ECP_224_BP:
+                       valid = value.len == 56;
+                       break;
+               case ECP_256_BIT:
+               case ECP_256_BP:
+                       valid = value.len == 64;
+                       break;
+               case ECP_384_BIT:
+               case ECP_384_BP:
+                       valid = value.len == 96;
+                       break;
+               case ECP_512_BP:
+                       valid = value.len == 128;
+                       break;
+               case ECP_521_BIT:
+                       valid = value.len == 132;
+                       break;
+               case NTRU_112_BIT:
+               case NTRU_128_BIT:
+               case NTRU_192_BIT:
+               case NTRU_256_BIT:
+                       /* verification currently not supported, do in plugin */
+                       valid = FALSE;
+                       break;
+               case MODP_NULL:
+               case MODP_CUSTOM:
+                       valid = TRUE;
+                       break;
+               case MODP_NONE:
+                       /* fail */
+                       break;
+               /* compile-warn unhandled groups, fail verification */
+       }
+       if (!valid)
+       {
+               DBG1(DBG_ENC, "invalid DH public value size (%zu bytes) for %N",
+                        value.len, diffie_hellman_group_names, group);
+       }
+       return valid;
+}
index 99df3cb..4704cd0 100644 (file)
@@ -175,8 +175,17 @@ diffie_hellman_params_t *diffie_hellman_get_params(diffie_hellman_group_t group)
  * Check if a given DH group is an ECDH group
  *
  * @param group                        group to check
- * @return                             TUE if group is an ECP group
+ * @return                             TRUE if group is an ECP group
  */
 bool diffie_hellman_group_is_ec(diffie_hellman_group_t group);
 
+/**
+ * Check if a diffie hellman public value is valid for given group.
+ *
+ * @param group                        group the value is used in
+ * @param value                        public DH value to check
+ * @return                             TRUE if value looks valid for group
+ */
+bool diffie_hellman_verify_value(diffie_hellman_group_t group, chunk_t value);
+
 #endif /** DIFFIE_HELLMAN_H_ @}*/
index 80bd85d..744ec0b 100644 (file)
@@ -79,6 +79,11 @@ METHOD(diffie_hellman_t, set_other_public_value, bool,
        gcry_mpi_t p_min_1;
        gcry_error_t err;
 
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
        if (this->yb)
        {
                gcry_mpi_release(this->yb);
index 0fbfc24..0ca24d7 100644 (file)
@@ -90,6 +90,11 @@ METHOD(diffie_hellman_t, set_other_public_value, bool,
 {
        mpz_t p_min_1;
 
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
        mpz_init(p_min_1);
        mpz_sub_ui(p_min_1, this->p, 1);
 
index 7a0aa1a..2615d60 100644 (file)
@@ -92,6 +92,11 @@ METHOD(diffie_hellman_t, set_other_public_value, bool,
 {
        int len;
 
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
        BN_bin2bn(value.ptr, value.len, this->pub_key);
        chunk_clear(&this->shared_secret);
        this->shared_secret.ptr = malloc(DH_size(this->dh));
index 9ef15b4..550a543 100644 (file)
@@ -219,6 +219,11 @@ error:
 METHOD(diffie_hellman_t, set_other_public_value, bool,
        private_openssl_ec_diffie_hellman_t *this, chunk_t value)
 {
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
        if (!chunk2ecp(this->ec_group, value, this->pub_key))
        {
                DBG1(DBG_LIB, "ECDH public value is malformed");
index 56102c5..c0033bd 100644 (file)
@@ -116,6 +116,11 @@ static bool derive_secret(private_pkcs11_dh_t *this, chunk_t other)
 METHOD(diffie_hellman_t, set_other_public_value, bool,
        private_pkcs11_dh_t *this, chunk_t value)
 {
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
        switch (this->group)
        {
                case ECP_192_BIT: