Branch data Line data Source code
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 : :
16 : : #include "utils/s2n_safety.h"
17 : :
18 : : #include <stdint.h>
19 : : #include <stdio.h>
20 : :
21 : : #include "utils/s2n_annotations.h"
22 : :
23 : : /**
24 : : * Given arrays "a" and "b" of length "len", determine whether they
25 : : * hold equal contents.
26 : : *
27 : : * The execution time of this function is independent of the values
28 : : * stored in the arrays.
29 : : *
30 : : * Timing may depend on the length of the arrays, and on the location
31 : : * of the arrays in memory (e.g. if a buffer has been paged out, this
32 : : * will affect the timing of this function).
33 : : *
34 : : * Returns:
35 : : * Whether all bytes in arrays "a" and "b" are identical
36 : : */
37 : : bool s2n_constant_time_equals(const uint8_t *a, const uint8_t *b, const uint32_t len)
38 : 443452 : {
39 : 443452 : S2N_PUBLIC_INPUT(a);
40 : 443452 : S2N_PUBLIC_INPUT(b);
41 : 443452 : S2N_PUBLIC_INPUT(len);
42 : :
43 : : /* if len is 0, they're always going to be equal */
44 [ + + ]: 443452 : if (len == 0) {
45 : 50354 : return true;
46 : 50354 : }
47 : :
48 : : /* check if a and b are readable - if so, allow them to increment their pointer */
49 [ - + ][ + + ]: 393098 : uint8_t a_inc = S2N_MEM_IS_READABLE(a, len) ? 1 : 0;
50 [ - + ][ + + ]: 393098 : uint8_t b_inc = S2N_MEM_IS_READABLE(b, len) ? 1 : 0;
51 : :
52 : : /* reserve a stand-in pointer to replace NULL pointers */
53 : 393098 : static uint8_t standin = 0;
54 : :
55 : : /* if the pointers can increment their values, then use the
56 : : * original value; otherwise use the stand-in */
57 [ + + ]: 393098 : const uint8_t *a_ptr = a_inc ? a : &standin;
58 [ + + ]: 393098 : const uint8_t *b_ptr = b_inc ? b : &standin;
59 : :
60 : : /* start by assuming they are equal only if both increment their pointer */
61 : 393098 : uint8_t xor = !((a_inc == 1) & (b_inc == 1));
62 : :
63 : : /* iterate over each byte in the slices */
64 [ + + ]: 4134534 : for (size_t i = 0; i < len; i++) {
65 : : /* Invariants must hold for each execution of the loop
66 : : * and at loop exit, hence the <= */
67 : 3741436 : S2N_INVARIANT(i <= len);
68 : :
69 : : /* mix the current cursor values in to the result */
70 : 3741436 : xor |= *a_ptr ^ *b_ptr;
71 : :
72 : : /* increment the pointers by their "inc" values */
73 : 3741436 : a_ptr += a_inc;
74 : 3741436 : b_ptr += b_inc;
75 : 3741436 : }
76 : :
77 : : /* finally check to make sure xor is still 0 */
78 : 393098 : return (xor == 0);
79 : 443452 : }
80 : :
81 : : /**
82 : : * Given arrays "dest" and "src" of length "len", conditionally copy "src" to "dest"
83 : : * The execution time of this function is independent of the values
84 : : * stored in the arrays, and of whether the copy occurs.
85 : : *
86 : : * Timing may depend on the length of the arrays, and on the location
87 : : * of the arrays in memory (e.g. if a buffer has been paged out, this
88 : : * will affect the timing of this function).
89 : : *
90 : : */
91 : : int s2n_constant_time_copy_or_dont(uint8_t *dest, const uint8_t *src, uint32_t len, uint8_t dont)
92 : 1970 : {
93 : 1970 : S2N_PUBLIC_INPUT(dest);
94 : 1970 : S2N_PUBLIC_INPUT(src);
95 : 1970 : S2N_PUBLIC_INPUT(len);
96 : :
97 : 1970 : uint8_t mask = (((0xFFFF & dont) - 1) >> 8) & 0xFF;
98 : :
99 : : /* dont = 0 : mask = 0xff */
100 : : /* dont > 0 : mask = 0x00 */
101 : :
102 [ + + ]: 75670 : for (size_t i = 0; i < len; i++) {
103 : 73700 : uint8_t old = dest[i];
104 : 73700 : uint8_t diff = (old ^ src[i]) & mask;
105 : 73700 : dest[i] = old ^ diff;
106 : 73700 : }
107 : :
108 : 1970 : return 0;
109 : 1970 : }
110 : :
111 : : /* If src contains valid PKCS#1 v1.5 padding of exactly expectlen bytes, decode
112 : : * it into dst, otherwise leave dst alone. Execution time is independent of the
113 : : * content of src, but may depend on srclen/expectlen.
114 : : *
115 : : * Normally, one would fill dst with random bytes before calling this function.
116 : : */
117 : : int s2n_constant_time_pkcs1_unpad_or_dont(uint8_t *dst, const uint8_t *src, uint32_t srclen, uint32_t expectlen)
118 : 1714 : {
119 : 1714 : S2N_PUBLIC_INPUT(dst);
120 : 1714 : S2N_PUBLIC_INPUT(src);
121 : 1714 : S2N_PUBLIC_INPUT(srclen);
122 : 1714 : S2N_PUBLIC_INPUT(expectlen);
123 : :
124 : : /* Before doing anything else, some basic sanity checks on input lengths */
125 [ - + ]: 1714 : if (srclen < expectlen + 3) {
126 : : /* Not enough room for PKCS#1v1.5 padding, so treat it as bad padding */
127 : 0 : return 0;
128 : 0 : }
129 : :
130 : : /* First, determine (in constant time) whether the padding is valid.
131 : : * If the padding is valid we expect that:
132 : : * Bytes 0 and 1 will equal 0x00 and 0x02
133 : : * Bytes (srclen-expectlen-1) will be zero
134 : : * Bytes 2 through (srclen-expectlen-1) will be nonzero
135 : : */
136 : 1714 : uint8_t dont_copy = 0;
137 : 1714 : const uint8_t *start_of_data = src + srclen - expectlen;
138 : :
139 : 1714 : dont_copy |= src[0] ^ 0x00;
140 : 1714 : dont_copy |= src[1] ^ 0x02;
141 : 1714 : dont_copy |= *(start_of_data - 1) ^ 0x00;
142 : :
143 [ + + ]: 360958 : for (size_t i = 2; i < srclen - expectlen - 1; i++) {
144 : : /* Note! We avoid using logical NOT (!) here; while in practice
145 : : * many compilers will use constant-time sequences for this operator,
146 : : * at least on x86 (e.g. cmp -> setcc, or vectorized pcmpeq), this is
147 : : * not guaranteed to hold, and some architectures might not have a
148 : : * convenient mechanism for generating a branchless logical not. */
149 : 359244 : uint8_t mask = (((0xFFFF & src[i]) - 1) >> 8) & 0xFF;
150 : : /* src[i] = 0 : mask = 0xff */
151 : : /* src[i] > 0 : mask = 0x00 */
152 : 359244 : dont_copy |= mask;
153 : 359244 : }
154 : :
155 : 1714 : s2n_constant_time_copy_or_dont(dst, start_of_data, expectlen, dont_copy);
156 : :
157 : 1714 : return 0;
158 : 1714 : }
159 : :
160 : : static bool s2n_in_unit_test_value = false;
161 : : static bool s2n_in_integ_test_value = false;
162 : :
163 : : int s2n_in_unit_test_set(bool is_unit)
164 : 801 : {
165 : 801 : s2n_in_unit_test_value = is_unit;
166 : 801 : return S2N_SUCCESS;
167 : 801 : }
168 : :
169 : : int s2n_in_integ_test_set(bool is_integ)
170 : 0 : {
171 : 0 : s2n_in_integ_test_value = is_integ;
172 : 0 : return S2N_SUCCESS;
173 : 0 : }
174 : :
175 : : bool s2n_in_unit_test()
176 : 579837 : {
177 : 579837 : return s2n_in_unit_test_value;
178 : 579837 : }
179 : :
180 : : bool s2n_in_test()
181 : 115836 : {
182 [ + + ][ - + ]: 115836 : return s2n_in_unit_test_value || s2n_in_integ_test_value;
183 : 115836 : }
184 : :
185 : : int s2n_align_to(uint32_t initial, uint32_t alignment, uint32_t *out)
186 : 10 : {
187 [ - + ][ # # ]: 10 : POSIX_ENSURE_REF(out);
188 [ + + ][ + - ]: 10 : POSIX_ENSURE(alignment != 0, S2N_ERR_SAFETY);
189 [ + + ]: 9 : if (initial == 0) {
190 : 1 : *out = 0;
191 : 1 : return S2N_SUCCESS;
192 : 1 : }
193 : 8 : const uint64_t i = initial;
194 : 8 : const uint64_t a = alignment;
195 : 8 : const uint64_t result = a * (((i - 1) / a) + 1);
196 [ + + ][ + - ]: 8 : POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
197 : 5 : *out = (uint32_t) result;
198 : 5 : return S2N_SUCCESS;
199 : 8 : }
200 : :
201 : : int s2n_mul_overflow(uint32_t a, uint32_t b, uint32_t *out)
202 : 21831120 : {
203 [ - + ][ # # ]: 21831120 : POSIX_ENSURE_REF(out);
204 : 21831120 : const uint64_t result = ((uint64_t) a) * ((uint64_t) b);
205 [ + + ][ + - ]: 21831120 : POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
206 : 21831113 : *out = (uint32_t) result;
207 : 21831113 : return S2N_SUCCESS;
208 : 21831120 : }
209 : :
210 : : int s2n_add_overflow(uint32_t a, uint32_t b, uint32_t *out)
211 : 12304817 : {
212 [ - + ][ # # ]: 12304817 : POSIX_ENSURE_REF(out);
213 : 12304817 : uint64_t result = ((uint64_t) a) + ((uint64_t) b);
214 [ + - ][ + + ]: 12304817 : POSIX_ENSURE(result <= UINT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
215 : 12304803 : *out = (uint32_t) result;
216 : 12304803 : return S2N_SUCCESS;
217 : 12304817 : }
218 : :
219 : : int s2n_sub_overflow(uint32_t a, uint32_t b, uint32_t *out)
220 : 224142 : {
221 [ - + ][ # # ]: 224142 : POSIX_ENSURE_REF(out);
222 [ - + ][ # # ]: 224142 : POSIX_ENSURE(a >= b, S2N_ERR_INTEGER_OVERFLOW);
223 : 224142 : *out = a - b;
224 : 224142 : return S2N_SUCCESS;
225 : 224142 : }
|