/src/openvswitch/lib/uuid.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2008, 2009, 2010, 2011, 2013, 2016, 2017 Nicira, Inc. |
2 | | * |
3 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | * you may not use this file except in compliance with the License. |
5 | | * You may obtain a copy of the License at: |
6 | | * |
7 | | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | | * |
9 | | * Unless required by applicable law or agreed to in writing, software |
10 | | * distributed under the License is distributed on an "AS IS" BASIS, |
11 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | * See the License for the specific language governing permissions and |
13 | | * limitations under the License. |
14 | | */ |
15 | | |
16 | | #include <config.h> |
17 | | |
18 | | #include "uuid.h" |
19 | | |
20 | | #include <ctype.h> |
21 | | #include <errno.h> |
22 | | #include <fcntl.h> |
23 | | #include <sys/time.h> |
24 | | #include <sys/types.h> |
25 | | #include <unistd.h> |
26 | | |
27 | | #include "aes128.h" |
28 | | #include "entropy.h" |
29 | | #include "fatal-signal.h" |
30 | | #include "openvswitch/vlog.h" |
31 | | #include "ovs-replay.h" |
32 | | #include "ovs-thread.h" |
33 | | #include "sha1.h" |
34 | | #include "timeval.h" |
35 | | #include "util.h" |
36 | | |
37 | | VLOG_DEFINE_THIS_MODULE(uuid); |
38 | | |
39 | | static struct aes128 key; |
40 | | static uint64_t counter[2]; |
41 | | BUILD_ASSERT_DECL(sizeof counter == 16); |
42 | | |
43 | | static void do_init(void); |
44 | | |
45 | | /* |
46 | | * Initialize the UUID module. Aborts the program with an error message if |
47 | | * initialization fails (which should never happen on a properly configured |
48 | | * machine.) |
49 | | * |
50 | | * Currently initialization is only needed by uuid_generate(). uuid_generate() |
51 | | * will automatically call uuid_init() itself, so it's only necessary to call |
52 | | * this function explicitly if you want to abort the program earlier than the |
53 | | * first UUID generation in case of failure. |
54 | | */ |
55 | | void |
56 | | uuid_init(void) |
57 | 0 | { |
58 | 0 | static pthread_once_t once = PTHREAD_ONCE_INIT; |
59 | 0 | pthread_once(&once, do_init); |
60 | 0 | } |
61 | | |
62 | | /* Record/replay of uuid generation. */ |
63 | | static replay_file_t uuid_replay_file; |
64 | | static int uuid_replay_seqno; |
65 | | |
66 | | static void |
67 | | uuid_replay_file_close(void *aux OVS_UNUSED) |
68 | 0 | { |
69 | 0 | ovs_replay_file_close(uuid_replay_file); |
70 | 0 | } |
71 | | |
72 | | static void |
73 | | uuid_replay_file_open(void) |
74 | 0 | { |
75 | 0 | int error; |
76 | |
|
77 | 0 | ovs_replay_lock(); |
78 | 0 | error = ovs_replay_file_open("__uuid_generate", &uuid_replay_file, |
79 | 0 | &uuid_replay_seqno); |
80 | 0 | ovs_replay_unlock(); |
81 | 0 | if (error) { |
82 | 0 | VLOG_FATAL("failed to open uuid replay file: %s.", |
83 | 0 | ovs_strerror(error)); |
84 | 0 | } |
85 | 0 | fatal_signal_add_hook(uuid_replay_file_close, NULL, NULL, true); |
86 | 0 | } |
87 | | |
88 | | static void |
89 | | uuid_replay_file_read(struct uuid *uuid) |
90 | 0 | { |
91 | 0 | int norm_seqno = ovs_replay_normalized_seqno(uuid_replay_seqno); |
92 | 0 | int retval, len; |
93 | |
|
94 | 0 | ovs_replay_lock(); |
95 | 0 | ovs_assert(norm_seqno == ovs_replay_seqno()); |
96 | 0 | ovs_assert(ovs_replay_seqno_is_read(uuid_replay_seqno)); |
97 | |
|
98 | 0 | retval = ovs_replay_read(uuid_replay_file, uuid, sizeof *uuid, |
99 | 0 | &len, &uuid_replay_seqno, true); |
100 | 0 | if (retval || len != sizeof *uuid) { |
101 | 0 | VLOG_FATAL("failed to read from replay file: %s.", |
102 | 0 | ovs_strerror(retval)); |
103 | 0 | } |
104 | 0 | ovs_replay_unlock(); |
105 | 0 | } |
106 | | |
107 | | static void |
108 | | uuid_replay_file_write(struct uuid *uuid) |
109 | 0 | { |
110 | 0 | int retval; |
111 | |
|
112 | 0 | retval = ovs_replay_write(uuid_replay_file, uuid, sizeof *uuid, true); |
113 | 0 | if (retval) { |
114 | 0 | VLOG_FATAL("failed to write uuid to replay file: %s.", |
115 | 0 | ovs_strerror(retval)); |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | /* Generates a new random UUID in 'uuid'. |
120 | | * |
121 | | * We go to some trouble to ensure as best we can that the generated UUID has |
122 | | * these properties: |
123 | | * |
124 | | * - Uniqueness. The random number generator is seeded using both the |
125 | | * system clock and the system random number generator, plus a few |
126 | | * other identifiers, which is about as good as we can get in any kind |
127 | | * of simple way. |
128 | | * |
129 | | * - Unpredictability. In some situations it could be bad for an |
130 | | * adversary to be able to guess the next UUID to be generated with some |
131 | | * probability of success. This property may or may not be important |
132 | | * for our purposes, but it is better if we can get it. |
133 | | * |
134 | | * To ensure both of these, we start by taking our seed data and passing it |
135 | | * through SHA-1. We use the result as an AES-128 key. We also generate a |
136 | | * random 16-byte value[*] which we then use as the counter for CTR mode. To |
137 | | * generate a UUID in a manner compliant with the above goals, we merely |
138 | | * increment the counter and encrypt it. |
139 | | * |
140 | | * [*] It is not actually important that the initial value of the counter be |
141 | | * random. AES-128 in counter mode is secure either way. |
142 | | */ |
143 | | void |
144 | | uuid_generate(struct uuid *uuid) |
145 | 0 | { |
146 | 0 | static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; |
147 | 0 | enum ovs_replay_state replay_state = ovs_replay_get_state(); |
148 | 0 | uint64_t copy[2]; |
149 | |
|
150 | 0 | uuid_init(); |
151 | |
|
152 | 0 | if (replay_state == OVS_REPLAY_READ) { |
153 | 0 | uuid_replay_file_read(uuid); |
154 | 0 | return; |
155 | 0 | } |
156 | | |
157 | | /* Copy out the counter's current value, then increment it. */ |
158 | 0 | ovs_mutex_lock(&mutex); |
159 | 0 | copy[0] = counter[0]; |
160 | 0 | copy[1] = counter[1]; |
161 | 0 | if (++counter[1] == 0) { |
162 | 0 | counter[0]++; |
163 | 0 | } |
164 | 0 | ovs_mutex_unlock(&mutex); |
165 | | |
166 | | /* AES output is exactly 16 bytes, so we encrypt directly into 'uuid'. */ |
167 | 0 | aes128_encrypt(&key, copy, uuid); |
168 | |
|
169 | 0 | uuid_set_bits_v4(uuid); |
170 | |
|
171 | 0 | if (replay_state == OVS_REPLAY_WRITE) { |
172 | 0 | uuid_replay_file_write(uuid); |
173 | 0 | } |
174 | 0 | } |
175 | | |
176 | | struct uuid |
177 | | uuid_random(void) |
178 | 0 | { |
179 | 0 | struct uuid uuid; |
180 | 0 | uuid_generate(&uuid); |
181 | 0 | return uuid; |
182 | 0 | } |
183 | | |
184 | | void |
185 | | uuid_set_bits_v4(struct uuid *uuid) |
186 | 0 | { |
187 | | /* Set bits to indicate a random UUID. See RFC 4122 section 4.4. */ |
188 | 0 | uuid->parts[2] &= ~0xc0000000; |
189 | 0 | uuid->parts[2] |= 0x80000000; |
190 | 0 | uuid->parts[1] &= ~0x0000f000; |
191 | 0 | uuid->parts[1] |= 0x00004000; |
192 | 0 | } |
193 | | |
194 | | /* Sets 'uuid' to all-zero-bits. */ |
195 | | void |
196 | | uuid_zero(struct uuid *uuid) |
197 | 0 | { |
198 | 0 | *uuid = UUID_ZERO; |
199 | 0 | } |
200 | | |
201 | | /* Returns true if 'uuid' is all zero, otherwise false. */ |
202 | | bool |
203 | | uuid_is_zero(const struct uuid *uuid) |
204 | 85.7k | { |
205 | 85.7k | return (!uuid->parts[0] && !uuid->parts[1] |
206 | 85.7k | && !uuid->parts[2] && !uuid->parts[3]); |
207 | 85.7k | } |
208 | | |
209 | | /* Compares 'a' and 'b'. Returns a negative value if 'a < b', zero if 'a == |
210 | | * b', or positive if 'a > b'. The ordering is lexicographical order of the |
211 | | * conventional way of writing out UUIDs as strings. */ |
212 | | int |
213 | | uuid_compare_3way(const struct uuid *a, const struct uuid *b) |
214 | 0 | { |
215 | 0 | if (a->parts[0] != b->parts[0]) { |
216 | 0 | return a->parts[0] > b->parts[0] ? 1 : -1; |
217 | 0 | } else if (a->parts[1] != b->parts[1]) { |
218 | 0 | return a->parts[1] > b->parts[1] ? 1 : -1; |
219 | 0 | } else if (a->parts[2] != b->parts[2]) { |
220 | 0 | return a->parts[2] > b->parts[2] ? 1 : -1; |
221 | 0 | } else if (a->parts[3] != b->parts[3]) { |
222 | 0 | return a->parts[3] > b->parts[3] ? 1 : -1; |
223 | 0 | } else { |
224 | 0 | return 0; |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | /* Attempts to convert string 's' into a UUID in 'uuid'. Returns true if |
229 | | * successful, which will be the case only if 's' has the exact format |
230 | | * specified by RFC 4122. Returns false on failure. On failure, 'uuid' will |
231 | | * be set to all-zero-bits. */ |
232 | | bool |
233 | | uuid_from_string(struct uuid *uuid, const char *s) |
234 | 0 | { |
235 | 0 | if (!uuid_from_string_prefix(uuid, s)) { |
236 | 0 | return false; |
237 | 0 | } else if (s[UUID_LEN] != '\0') { |
238 | 0 | uuid_zero(uuid); |
239 | 0 | return false; |
240 | 0 | } else { |
241 | 0 | return true; |
242 | 0 | } |
243 | 0 | } |
244 | | |
245 | | /* Same as uuid_from_string() but s[UUID_LEN] is not required to be a null byte |
246 | | * to succeed; that is, 's' need only begin with UUID syntax, not consist |
247 | | * entirely of it. */ |
248 | | bool |
249 | | uuid_from_string_prefix(struct uuid *uuid, const char *s) |
250 | 0 | { |
251 | | /* 0 1 2 3 */ |
252 | | /* 012345678901234567890123456789012345 */ |
253 | | /* ------------------------------------ */ |
254 | | /* 00000000-1111-1111-2222-222233333333 */ |
255 | |
|
256 | 0 | bool ok; |
257 | |
|
258 | 0 | uuid->parts[0] = hexits_value(s, 8, &ok); |
259 | 0 | if (!ok || s[8] != '-') { |
260 | 0 | goto error; |
261 | 0 | } |
262 | | |
263 | 0 | uuid->parts[1] = hexits_value(s + 9, 4, &ok) << 16; |
264 | 0 | if (!ok || s[13] != '-') { |
265 | 0 | goto error; |
266 | 0 | } |
267 | | |
268 | 0 | uuid->parts[1] += hexits_value(s + 14, 4, &ok); |
269 | 0 | if (!ok || s[18] != '-') { |
270 | 0 | goto error; |
271 | 0 | } |
272 | | |
273 | 0 | uuid->parts[2] = hexits_value(s + 19, 4, &ok) << 16; |
274 | 0 | if (!ok || s[23] != '-') { |
275 | 0 | goto error; |
276 | 0 | } |
277 | | |
278 | 0 | uuid->parts[2] += hexits_value(s + 24, 4, &ok); |
279 | 0 | if (!ok) { |
280 | 0 | goto error; |
281 | 0 | } |
282 | | |
283 | 0 | uuid->parts[3] = hexits_value(s + 28, 8, &ok); |
284 | 0 | if (!ok) { |
285 | 0 | goto error; |
286 | 0 | } |
287 | 0 | return true; |
288 | | |
289 | 0 | error: |
290 | 0 | uuid_zero(uuid); |
291 | 0 | return false; |
292 | 0 | } |
293 | | |
294 | | /* If 's' is a string representation of a UUID, or the beginning of one, |
295 | | * returns strlen(s), otherwise 0. |
296 | | * |
297 | | * For example: |
298 | | * |
299 | | * "123" yields 3 |
300 | | * "xyzzy" yields 0 |
301 | | * "123xyzzy" yields 0 |
302 | | * "e66250bb-9531-491b-b9c3-5385cabb0080" yields 36 |
303 | | * "e66250bb-9531-491b-b9c3-5385cabb0080xyzzy" yields 0 |
304 | | */ |
305 | | int |
306 | | uuid_is_partial_string(const char *s) |
307 | 0 | { |
308 | 0 | const char *tmpl = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; |
309 | 0 | size_t i; |
310 | 0 | for (i = 0; i < UUID_LEN; i++) { |
311 | 0 | if (s[i] == '\0') { |
312 | 0 | return i; |
313 | 0 | } else if (tmpl[i] == 'x' |
314 | 0 | ? hexit_value(s[i]) < 0 |
315 | 0 | : s[i] != '-') { |
316 | 0 | return 0; |
317 | 0 | } |
318 | 0 | } |
319 | 0 | if (s[i] != '\0') { |
320 | 0 | return 0; |
321 | 0 | } |
322 | 0 | return i; |
323 | 0 | } |
324 | | |
325 | | /* Compares 'match' to the string representation of 'uuid'. If 'match' equals |
326 | | * or is a prefix of this string representation, returns strlen(match); |
327 | | * otherwise, returns 0. */ |
328 | | int |
329 | | uuid_is_partial_match(const struct uuid *uuid, const char *match) |
330 | 0 | { |
331 | 0 | char uuid_s[UUID_LEN + 1]; |
332 | 0 | snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(uuid)); |
333 | 0 | size_t match_len = strlen(match); |
334 | 0 | return !strncmp(uuid_s, match, match_len) ? match_len : 0; |
335 | 0 | } |
336 | | |
337 | | static void |
338 | | sha1_update_int(struct sha1_ctx *sha1_ctx, uintmax_t x) |
339 | 0 | { |
340 | 0 | sha1_update(sha1_ctx, &x, sizeof x); |
341 | 0 | } |
342 | | |
343 | | static void |
344 | | do_init(void) |
345 | 0 | { |
346 | 0 | uint8_t sha1[SHA1_DIGEST_SIZE]; |
347 | 0 | struct sha1_ctx sha1_ctx; |
348 | 0 | uint8_t random_seed[16]; |
349 | 0 | struct timeval now; |
350 | |
|
351 | 0 | if (ovs_replay_is_active()) { |
352 | 0 | uuid_replay_file_open(); |
353 | 0 | } |
354 | | |
355 | | /* Get seed data. */ |
356 | 0 | get_entropy_or_die(random_seed, sizeof random_seed); |
357 | 0 | xgettimeofday(&now); |
358 | | |
359 | | /* Convert seed into key. */ |
360 | 0 | sha1_init(&sha1_ctx); |
361 | 0 | sha1_update(&sha1_ctx, random_seed, sizeof random_seed); |
362 | 0 | sha1_update(&sha1_ctx, &now, sizeof now); |
363 | 0 | sha1_update_int(&sha1_ctx, getpid()); |
364 | 0 | #ifndef _WIN32 |
365 | 0 | sha1_update_int(&sha1_ctx, getppid()); |
366 | 0 | sha1_update_int(&sha1_ctx, getuid()); |
367 | 0 | sha1_update_int(&sha1_ctx, getgid()); |
368 | 0 | #endif |
369 | 0 | sha1_final(&sha1_ctx, sha1); |
370 | | |
371 | | /* Generate key. */ |
372 | 0 | BUILD_ASSERT(sizeof sha1 >= 16); |
373 | 0 | aes128_schedule(&key, sha1); |
374 | | |
375 | | /* Generate initial counter. */ |
376 | 0 | get_entropy_or_die(counter, sizeof counter); |
377 | 0 | } |