0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. From cff138b0747fa39765cbc641b66cfa5d7f1735d1 Mon Sep 17 00:00:00 2001
  2. From: Jouni Malinen <jouni@codeaurora.org>
  3. Date: Sat, 2 Mar 2019 16:05:56 +0200
  4. Subject: [PATCH 09/14] SAE: Use constant time operations in
  5. sae_test_pwd_seed_ffc()
  6. Try to avoid showing externally visible timing or memory access
  7. differences regardless of whether the derived pwd-value is smaller than
  8. the group prime.
  9. This is related to CVE-2019-9494.
  10. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
  11. ---
  12. src/common/sae.c | 75 ++++++++++++++++++++++++++++++++++----------------------
  13. 1 file changed, 46 insertions(+), 29 deletions(-)
  14. diff --git a/src/common/sae.c b/src/common/sae.c
  15. index fa9a145..eaf825d 100644
  16. --- a/src/common/sae.c
  17. +++ b/src/common/sae.c
  18. @@ -334,14 +334,17 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
  19. }
  20. +/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
  21. + * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
  22. static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
  23. struct crypto_bignum *pwe)
  24. {
  25. u8 pwd_value[SAE_MAX_PRIME_LEN];
  26. size_t bits = sae->tmp->prime_len * 8;
  27. u8 exp[1];
  28. - struct crypto_bignum *a, *b;
  29. - int res;
  30. + struct crypto_bignum *a, *b = NULL;
  31. + int res, is_val;
  32. + u8 pwd_value_valid;
  33. wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
  34. @@ -353,16 +356,29 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
  35. wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
  36. sae->tmp->prime_len);
  37. - if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
  38. - {
  39. - wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
  40. - return 0;
  41. - }
  42. + /* Check whether pwd-value < p */
  43. + res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
  44. + sae->tmp->prime_len);
  45. + /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
  46. + * the negative sign can be used to fill the mask for constant time
  47. + * selection */
  48. + pwd_value_valid = const_time_fill_msb(res);
  49. +
  50. + /* If pwd-value >= p, force pwd-value to be < p and perform the
  51. + * calculations anyway to hide timing difference. The derived PWE will
  52. + * be ignored in that case. */
  53. + pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
  54. /* PWE = pwd-value^((p-1)/r) modulo p */
  55. + res = -1;
  56. a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
  57. + if (!a)
  58. + goto fail;
  59. + /* This is an optimization based on the used group that does not depend
  60. + * on the password in any way, so it is fine to use separate branches
  61. + * for this step without constant time operations. */
  62. if (sae->tmp->dh->safe_prime) {
  63. /*
  64. * r = (p-1)/2 for the group used here, so this becomes:
  65. @@ -376,33 +392,34 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
  66. b = crypto_bignum_init_set(exp, sizeof(exp));
  67. if (b == NULL ||
  68. crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
  69. - crypto_bignum_div(b, sae->tmp->order, b) < 0) {
  70. - crypto_bignum_deinit(b, 0);
  71. - b = NULL;
  72. - }
  73. + crypto_bignum_div(b, sae->tmp->order, b) < 0)
  74. + goto fail;
  75. }
  76. - if (a == NULL || b == NULL)
  77. - res = -1;
  78. - else
  79. - res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
  80. -
  81. - crypto_bignum_deinit(a, 0);
  82. - crypto_bignum_deinit(b, 0);
  83. + if (!b)
  84. + goto fail;
  85. - if (res < 0) {
  86. - wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
  87. - return -1;
  88. - }
  89. + res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
  90. + if (res < 0)
  91. + goto fail;
  92. - /* if (PWE > 1) --> found */
  93. - if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
  94. - wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
  95. - return 0;
  96. - }
  97. + /* There were no fatal errors in calculations, so determine the return
  98. + * value using constant time operations. We get here for number of
  99. + * invalid cases which are cleared here after having performed all the
  100. + * computation. PWE is valid if pwd-value was less than prime and
  101. + * PWE > 1. Start with pwd-value check first and then use constant time
  102. + * operations to clear res to 0 if PWE is 0 or 1.
  103. + */
  104. + res = const_time_select_u8(pwd_value_valid, 1, 0);
  105. + is_val = crypto_bignum_is_zero(pwe);
  106. + res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
  107. + is_val = crypto_bignum_is_one(pwe);
  108. + res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
  109. - wpa_printf(MSG_DEBUG, "SAE: PWE found");
  110. - return 1;
  111. +fail:
  112. + crypto_bignum_deinit(a, 1);
  113. + crypto_bignum_deinit(b, 1);
  114. + return res;
  115. }
  116. --
  117. 2.7.4