s2n_safety.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include "utils/s2n_safety.h"
  16. #include <stdint.h>
  17. #include <stdio.h>
  18. #include "utils/s2n_annotations.h"
  19. /**
  20. * Given arrays "a" and "b" of length "len", determine whether they
  21. * hold equal contents.
  22. *
  23. * The execution time of this function is independent of the values
  24. * stored in the arrays.
  25. *
  26. * Timing may depend on the length of the arrays, and on the location
  27. * of the arrays in memory (e.g. if a buffer has been paged out, this
  28. * will affect the timing of this function).
  29. *
  30. * Returns:
  31. * Whether all bytes in arrays "a" and "b" are identical
  32. */
  33. bool s2n_constant_time_equals(const uint8_t *a, const uint8_t *b, const uint32_t len)
  34. {
  35. S2N_PUBLIC_INPUT(a);
  36. S2N_PUBLIC_INPUT(b);
  37. S2N_PUBLIC_INPUT(len);
  38. /* if len is 0, they're always going to be equal */
  39. if (len == 0) {
  40. return true;
  41. }
  42. /* check if a and b are readable - if so, allow them to increment their pointer */
  43. uint8_t a_inc = S2N_MEM_IS_READABLE(a, len) ? 1 : 0;
  44. uint8_t b_inc = S2N_MEM_IS_READABLE(b, len) ? 1 : 0;
  45. /* reserve a stand-in pointer to replace NULL pointers */
  46. static uint8_t standin = 0;
  47. /* if the pointers can increment their values, then use the
  48. * original value; otherwise use the stand-in */
  49. const uint8_t *a_ptr = a_inc ? a : &standin;
  50. const uint8_t *b_ptr = b_inc ? b : &standin;
  51. /* start by assuming they are equal only if both increment their pointer */
  52. uint8_t xor = !((a_inc == 1) & (b_inc == 1));
  53. /* iterate over each byte in the slices */
  54. for (size_t i = 0; i < len; i++) {
  55. /* Invariants must hold for each execution of the loop
  56. * and at loop exit, hence the <= */
  57. S2N_INVARIANT(i <= len);
  58. /* mix the current cursor values in to the result */
  59. xor |= *a_ptr ^ *b_ptr;
  60. /* increment the pointers by their "inc" values */
  61. a_ptr += a_inc;
  62. b_ptr += b_inc;
  63. }
  64. /* finally check to make sure xor is still 0 */
  65. return (xor == 0);
  66. }
  67. /**
  68. * Given arrays "dest" and "src" of length "len", conditionally copy "src" to "dest"
  69. * The execution time of this function is independent of the values
  70. * stored in the arrays, and of whether the copy occurs.
  71. *
  72. * Timing may depend on the length of the arrays, and on the location
  73. * of the arrays in memory (e.g. if a buffer has been paged out, this
  74. * will affect the timing of this function).
  75. *
  76. */
  77. int s2n_constant_time_copy_or_dont(uint8_t *dest, const uint8_t *src, uint32_t len, uint8_t dont)
  78. {
  79. S2N_PUBLIC_INPUT(dest);
  80. S2N_PUBLIC_INPUT(src);
  81. S2N_PUBLIC_INPUT(len);
  82. uint8_t mask = (((0xFFFF & dont) - 1) >> 8) & 0xFF;
  83. /* dont = 0 : mask = 0xff */
  84. /* dont > 0 : mask = 0x00 */
  85. for (size_t i = 0; i < len; i++) {
  86. uint8_t old = dest[i];
  87. uint8_t diff = (old ^ src[i]) & mask;
  88. dest[i] = old ^ diff;
  89. }
  90. return 0;
  91. }
  92. /* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode
  93. * it into dst, otherwise leave dst alone. Execution time is independent of the
  94. * content of src, but may depend on srclen/expectlen.
  95. *
  96. * Normally, one would fill dst with random bytes before calling this function.
  97. */
  98. int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t *dst, const uint8_t *src, uint32_t srclen, uint32_t expectlen)
  99. {
  100. S2N_PUBLIC_INPUT(dst);
  101. S2N_PUBLIC_INPUT(src);
  102. S2N_PUBLIC_INPUT(srclen);
  103. S2N_PUBLIC_INPUT(expectlen);
  104. /* Before doing anything else, some basic sanity checks on input lengths */
  105. if (srclen < expectlen + 3) {
  106. /* Not enough room for PKCS#1v1.5 padding, so treat it as bad padding */
  107. return 0;
  108. }
  109. /* First, determine (in constant time) whether the padding is valid.
  110. * If the padding is valid we expect that:
  111. * Bytes 0 and 1 will equal 0x00 and 0x02
  112. * Bytes (srclen-expectlen-1) will be zero
  113. * Bytes 2 through (srclen-expectlen-1) will be nonzero
  114. */
  115. uint8_t dont_copy = 0;
  116. const uint8_t *start_of_data = src + srclen - expectlen;
  117. dont_copy |= src[0] ^ 0x00;
  118. dont_copy |= src[1] ^ 0x02;
  119. dont_copy |= *(start_of_data - 1) ^ 0x00;
  120. for (size_t i = 2; i < srclen - expectlen - 1; i++) {
  121. /* Note! We avoid using logical NOT (!) here; while in practice
  122. * many compilers will use constant-time sequences for this operator,
  123. * at least on x86 (e.g. cmp -> setcc, or vectorized pcmpeq), this is
  124. * not guaranteed to hold, and some architectures might not have a
  125. * convenient mechanism for generating a branchless logical not. */
  126. uint8_t mask = (((0xFFFF & src[i]) - 1) >> 8) & 0xFF;
  127. /* src[i] = 0 : mask = 0xff */
  128. /* src[i] > 0 : mask = 0x00 */
  129. dont_copy |= mask;
  130. }
  131. s2n_constant_time_copy_or_dont(dst, start_of_data, expectlen, dont_copy);
  132. return 0;
  133. }
  134. static bool s2n_in_unit_test_value = false;
  135. static bool s2n_in_integ_test_value = false;
  136. int s2n_in_unit_test_set(bool is_unit)
  137. {
  138. s2n_in_unit_test_value = is_unit;
  139. return S2N_SUCCESS;
  140. }
  141. int s2n_in_integ_test_set(bool is_integ)
  142. {
  143. s2n_in_integ_test_value = is_integ;
  144. return S2N_SUCCESS;
  145. }
  146. bool s2n_in_unit_test()
  147. {
  148. return s2n_in_unit_test_value;
  149. }
  150. bool s2n_in_test()
  151. {
  152. return s2n_in_unit_test_value || s2n_in_integ_test_value;
  153. }
  154. int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t *out)
  155. {
  156. POSIX_ENSURE_REF(out);
  157. POSIX_ENSURE(alignment != 0, S2N_ERR_SAFETY);
  158. if (initial == 0) {
  159. *out = 0;
  160. return S2N_SUCCESS;
  161. }
  162. const uint64_t i = initial;
  163. const uint64_t a = alignment;
  164. const uint64_t result = a * (((i - 1) / a) + 1);
  165. POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
  166. *out = (uint32_t) result;
  167. return S2N_SUCCESS;
  168. }
  169. int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t *out)
  170. {
  171. POSIX_ENSURE_REF(out);
  172. const uint64_t result = ((uint64_t) a) * ((uint64_t) b);
  173. POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
  174. *out = (uint32_t) result;
  175. return S2N_SUCCESS;
  176. }
  177. int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t *out)
  178. {
  179. POSIX_ENSURE_REF(out);
  180. uint64_t result = ((uint64_t) a) + ((uint64_t) b);
  181. POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
  182. *out = (uint32_t) result;
  183. return S2N_SUCCESS;
  184. }
  185. int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t *out)
  186. {
  187. POSIX_ENSURE_REF(out);
  188. POSIX_ENSURE(a >= b, S2N_ERR_INTEGER_OVERFLOW);
  189. *out = a - b;
  190. return S2N_SUCCESS;
  191. }