1 /*
2 * Copyright 2014-2017 Frank Hunleth
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 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define _GNU_SOURCE // for vasprintf
17 #include "util.h"
18 #include "simple_string.h"
19 #include "progress.h"
20
21 #include <errno.h>
22 #include <libgen.h>
23 #include "monocypher.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30
31 #include <sys/stat.h>
32
33 char *strptime(const char *s, const char *format, struct tm *tm);
34
35 static char *last_error_message = NULL;
36 static char time_string[200] = {0};
37 static time_t now_time = 0;
38 static const char *timestamp_format = "%Y-%m-%dT%H:%M:%SZ";
39
get_creation_timestamp()40 const char *get_creation_timestamp()
41 {
42 // Ensure that if the creation timestamp is queried more than
43 // once that the same string gets returned.
44 if (*time_string != '\0')
45 return time_string;
46
47 // Rules for determining archive timestamps
48 //
49 // 1. Use $SOURCE_DATE_EPOCH if specifed. See
50 // https://reproducible-builds.org/specs/source-date-epoch/
51 // 2. Use $NOW if specified. This is the original fwup way of forcing
52 // reproducible builds so we can't break it.
53 // 3. Don't try to be deterministic and use the current time.
54
55 const char *source_date_epoch = get_environment("SOURCE_DATE_EPOCH");
56 if (source_date_epoch != NULL) {
57 now_time = strtoul(source_date_epoch, NULL, 0);
58 time_t_to_string(now_time, time_string, sizeof(time_string));
59 set_environment("NOW", time_string);
60 return time_string;
61 }
62
63 const char *now = get_environment("NOW");
64 if (now != NULL) {
65 // The user specified NOW, so check that it's parsable.
66 struct tm tmp;
67 if (strptime(now, timestamp_format, &tmp) != NULL) {
68 int rc = snprintf(time_string, sizeof(time_string), "%s", now);
69 if (rc >= 0 && rc < (int) sizeof(time_string)) {
70 #ifdef HAVE_TIMEGM
71 now_time = timegm(&tmp);
72 #else
73 #ifdef _WIN32
74 now_time = _mkgmtime(&tmp);
75 #else
76 // mktime is influenced by the local timezone, so this will
77 // be wrong, but close.
78 now_time = mktime(&tmp);
79 #endif
80 #endif
81 return time_string;
82 }
83 }
84
85 INFO("NOW environment variable set, but not in YYYY-MM-DDTHH:MM:SSZ format so ignoring");
86 }
87
88 now_time = time(NULL);
89 time_t_to_string(now_time, time_string, sizeof(time_string));
90 set_environment("NOW", time_string);
91
92 return time_string;
93 }
94
get_creation_time_t()95 time_t get_creation_time_t()
96 {
97 if (now_time == 0)
98 get_creation_timestamp();
99
100 return now_time;
101 }
102
time_t_to_string(time_t t,char * str,size_t len)103 void time_t_to_string(time_t t, char *str, size_t len)
104 {
105 struct tm *tm_now = gmtime(&t);
106 if (tm_now == NULL)
107 fwup_err(EXIT_FAILURE, "gmtime");
108
109 strftime(str, len, timestamp_format, tm_now);
110 }
111
timestamp_to_tm(const char * timestamp,struct tm * tmp)112 int timestamp_to_tm(const char *timestamp, struct tm *tmp)
113 {
114 if (strptime(timestamp, timestamp_format, tmp) == NULL)
115 ERR_RETURN("error parsing timestamp");
116 else
117 return 0;
118 }
119
120 /**
121 * @brief Our errno!
122 * @param msg
123 */
set_last_error(const char * fmt,...)124 void set_last_error(const char *fmt, ...)
125 {
126 va_list ap;
127 va_start(ap, fmt);
128
129 if (last_error_message)
130 free(last_error_message);
131
132 // In the completely unlikely case that vasprintf fails, clear
133 // the error message pointer
134 if (vasprintf(&last_error_message, fmt, ap) < 0)
135 last_error_message = NULL;
136
137 va_end(ap);
138 }
139
last_error()140 const char *last_error()
141 {
142 return last_error_message ? last_error_message : "none";
143 }
144
hexchar_to_int(char c)145 static uint8_t hexchar_to_int(char c)
146 {
147 switch (c) {
148 case '0': return 0;
149 case '1': return 1;
150 case '2': return 2;
151 case '3': return 3;
152 case '4': return 4;
153 case '5': return 5;
154 case '6': return 6;
155 case '7': return 7;
156 case '8': return 8;
157 case '9': return 9;
158 case 'a':
159 case 'A': return 10;
160 case 'b':
161 case 'B': return 11;
162 case 'c':
163 case 'C': return 12;
164 case 'd':
165 case 'D': return 13;
166 case 'e':
167 case 'E': return 14;
168 case 'f':
169 case 'F': return 15;
170 default: return 255;
171 }
172 }
173
nibble_to_hexchar(uint8_t nibble)174 static char nibble_to_hexchar(uint8_t nibble)
175 {
176 switch (nibble) {
177 case 0: return '0';
178 case 1: return '1';
179 case 2: return '2';
180 case 3: return '3';
181 case 4: return '4';
182 case 5: return '5';
183 case 6: return '6';
184 case 7: return '7';
185 case 8: return '8';
186 case 9: return '9';
187 case 10: return 'a';
188 case 11: return 'b';
189 case 12: return 'c';
190 case 13: return 'd';
191 case 14: return 'e';
192 case 15: return 'f';
193 default: return '0';
194 }
195 }
196
two_hex_to_byte(const char * str,uint8_t * byte)197 static int two_hex_to_byte(const char *str, uint8_t *byte)
198 {
199 uint8_t sixteens = hexchar_to_int(str[0]);
200 uint8_t ones = hexchar_to_int(str[1]);
201 if (sixteens == 255 || ones == 255)
202 ERR_RETURN("Invalid character in hex string");
203
204 *byte = (uint8_t) (sixteens << 4) | ones;
205 return 0;
206 }
207
hex_to_bytes(const char * str,uint8_t * bytes,size_t numbytes)208 int hex_to_bytes(const char *str, uint8_t *bytes, size_t numbytes)
209 {
210 size_t len = strlen(str);
211 if (len != numbytes * 2)
212 ERR_RETURN("hex string should have length %d, but got %d", numbytes * 2, len);
213
214 while (len) {
215 if (two_hex_to_byte(str, bytes) < 0)
216 return -1;
217
218 str += 2;
219 len -= 2;
220 bytes++;
221 }
222 return 0;
223 }
224
bytes_to_hex(const uint8_t * bytes,char * str,size_t byte_count)225 int bytes_to_hex(const uint8_t *bytes, char *str, size_t byte_count)
226 {
227 while (byte_count) {
228 *str++ = nibble_to_hexchar(*bytes >> 4);
229 *str++ = nibble_to_hexchar(*bytes & 0xf);
230 bytes++;
231 byte_count--;
232 }
233 *str = '\0';
234 return 0;
235 }
236
archive_filename_to_resource(const char * name,char * result,size_t maxlength)237 int archive_filename_to_resource(const char *name, char *result, size_t maxlength)
238 {
239 int length;
240
241 // As a matter of convention, everything useful in the archive is stored
242 // in the data directory. There are a couple scenarios where it's useful
243 // to stuff a file in the root directory of the archive for compatibility
244 // with other programs. Those are specified as absolute paths.
245 if (memcmp(name, "data/", 5) == 0)
246 length = snprintf(result, maxlength, "%s", &name[5]);
247 else
248 length = snprintf(result, maxlength, "/%s", name);
249
250 if (length < 0 || length >= (int) maxlength)
251 ERR_RETURN("Bad path found in archive");
252
253 return 0;
254 }
255
256 /**
257 * Return true if the file is already a regular
258 * file or it will be one if it is opened without
259 * any special flags.
260 */
will_be_regular_file(const char * path)261 bool will_be_regular_file(const char *path)
262 {
263 bool is_in_dev = false;
264 #if defined(__APPLE__) || defined(__linux__)
265 // Weakly forbid users from creating regular files in /dev, since that's
266 // pretty much never their intention. This will eventually cause
267 // an error since the code that calls this won't create files unless
268 // this function returns true.
269 // See https://github.com/fwup-home/fwup/issues/35.
270
271 if (strncmp(path, "/dev/", 5) == 0)
272 is_in_dev = true;
273 #endif
274
275 #ifdef _WIN32
276 if (strncmp(path, "\\\\.\\", 4) == 0)
277 return false;
278 #endif
279 struct stat st;
280 int rc = stat(path, &st);
281 return (rc == 0 && (st.st_mode & S_IFREG)) || // Existing regular file
282 (rc < 0 && errno == ENOENT && !is_in_dev); // Doesn't exist and not in /dev
283 }
284
285 /**
286 * Return true if the file exists.
287 */
file_exists(const char * path)288 bool file_exists(const char *path)
289 {
290 struct stat st;
291 int rc = stat(path, &st);
292 return rc == 0;
293 }
294
295 /**
296 * Return true if the file exists.
297 */
is_regular_file(const char * path)298 bool is_regular_file(const char *path)
299 {
300 struct stat st;
301 int rc = stat(path, &st);
302 return rc == 0 && (st.st_mode & S_IFREG);
303 }
304
305 /**
306 * Return a string that described the units.
307 */
units_to_string(off_t units)308 const char *units_to_string(off_t units)
309 {
310 switch (units) {
311 case 1: return "bytes";
312 case ONE_KiB: return "KiB";
313 case ONE_MiB: return "MiB";
314 case ONE_GiB: return "GiB";
315 case ONE_TiB: return "TiB";
316 case ONE_KB: return "KB";
317 case ONE_MB: return "MB";
318 case ONE_GB: return "GB";
319 case ONE_TB: return "TB";
320 default: return "?";
321 }
322 }
323
324 /**
325 * Return the units that should be used for printing the specified
326 * amount;
327 */
find_natural_units(off_t amount)328 off_t find_natural_units(off_t amount)
329 {
330 if (amount >= ONE_TB) return ONE_TB;
331 else if (amount >= ONE_GB) return ONE_GB;
332 else if (amount >= ONE_MB) return ONE_MB;
333 else if (amount >= ONE_KB) return ONE_KB;
334 else return 1;
335 }
336
337 /**
338 * Format the specified amount in a human readable way.
339 *
340 * @param amount the numer
341 * @param out an output buffer
342 * @param out_size the size of the output buffer
343 * @return the number of bytes written to out
344 */
format_pretty_auto(off_t amount,char * out,size_t out_size)345 int format_pretty_auto(off_t amount, char *out, size_t out_size)
346 {
347 return format_pretty(amount, find_natural_units(amount), out, out_size);
348 }
349
350 /**
351 * Format the specified amount in a human readable way using the
352 * specified units.
353 *
354 * @param amount the number
355 * @param units the units to use for printing the value
356 * @param out an output buffer
357 * @param out_size the size of the output buffer
358 * @return the number of bytes written to out
359 */
format_pretty(off_t amount,off_t units,char * out,size_t out_size)360 int format_pretty(off_t amount, off_t units, char *out, size_t out_size)
361 {
362 double value = ((double) amount) / units;
363 const char *units_string = units_to_string(units);
364
365 return snprintf(out, out_size, "%.2f %s", value, units_string);
366 }
367
fwup_err(int status,const char * format,...)368 void fwup_err(int status, const char *format, ...)
369 {
370 va_list ap;
371 va_start(ap, format);
372
373 int err = errno;
374 struct simple_string s;
375 simple_string_init(&s);
376 if (fwup_framing) {
377 ssvprintf(&s, format, ap);
378 } else {
379 ssappend(&s, "fwup: ");
380 ssvprintf(&s, format, ap);
381 ssprintf(&s, ": %s\n", strerror(err));
382 }
383 fwup_output(FRAMING_TYPE_ERROR, 0, s.str);
384 free(s.str);
385 fwup_exit(status);
386
387 va_end(ap);
388 }
389
fwup_errx(int status,const char * format,...)390 void fwup_errx(int status, const char *format, ...)
391 {
392 va_list ap;
393 va_start(ap, format);
394
395 struct simple_string s;
396 simple_string_init(&s);
397 if (fwup_framing) {
398 ssvprintf(&s, format, ap);
399 } else {
400 ssappend(&s, "fwup: ");
401 ssvprintf(&s, format, ap);
402 ssappend(&s, "\n");
403 }
404 fwup_output(FRAMING_TYPE_ERROR, 0, s.str);
405 free(s.str);
406 fwup_exit(status);
407
408 va_end(ap);
409 }
410
fwup_warnx(const char * format,...)411 void fwup_warnx(const char *format, ...)
412 {
413 va_list ap;
414 va_start(ap, format);
415
416 struct simple_string s;
417 simple_string_init(&s);
418 if (fwup_framing) {
419 ssvprintf(&s, format, ap);
420 } else {
421 ssappend(&s, "fwup: ");
422 ssvprintf(&s, format, ap);
423 ssappend(&s, "\n");
424 }
425 fwup_output(FRAMING_TYPE_WARNING, 0, s.str);
426 free(s.str);
427
428 va_end(ap);
429 }
430
fwup_output(const char * type,uint16_t code,const char * str)431 void fwup_output(const char *type, uint16_t code, const char *str)
432 {
433 size_t len = strlen(str);
434 if (fwup_framing) {
435 uint32_t be_length = TO_BIGENDIAN32(len + 4);
436 uint16_t be_code = TO_BIGENDIAN16(code);
437 fwrite(&be_length, 4, 1, stdout);
438 fwrite(type, 2, 1, stdout);
439 fwrite(&be_code, 2, 1, stdout);
440 } else if (fwup_progress_mode == PROGRESS_MODE_NORMAL && len > 0) {
441 // Skip a line to avoid the progress bar and then print the message
442 fwrite("\r\033[K", 1, 4, stdout);
443 }
444 if (len)
445 fwrite(str, 1, len, stdout);
446
447 fflush(stdout);
448 }
449
handshake_exit(int status)450 static void handshake_exit(int status)
451 {
452 char buffer[2] = {0x1a, (char) status};
453 if (write(STDOUT_FILENO, buffer, sizeof(buffer)) != sizeof(buffer))
454 fprintf(stderr, "fwup: Error sending Ctrl+Z as part of the exit handshake");
455
456 for (;;) {
457 char throwaway[4096];
458 ssize_t rc = read(STDIN_FILENO, throwaway, sizeof(throwaway));
459 if (rc == 0 || (rc < 0 && errno != EINTR))
460 break;
461 }
462 }
463
464 /*
465 * Capture calls to exit to handle the exit handshake for Erlang port integration.
466 */
fwup_exit(int status)467 void fwup_exit(int status)
468 {
469 if (fwup_handshake_on_exit)
470 handshake_exit(status);
471
472 exit(status);
473 }
474
475 /*
476 * Implementations for simple functions that are missing on
477 * some operating systems (e.g. Windows).
478 */
479 #ifndef HAVE_PREAD
pread(int fd,void * buf,size_t count,off_t offset)480 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
481 {
482 if (lseek(fd, offset, SEEK_SET) >= 0)
483 return read(fd, buf, count);
484 else
485 return -1;
486 }
487 #endif
488
489 #ifndef HAVE_PWRITE
pwrite(int fd,const void * buf,size_t count,off_t offset)490 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
491 {
492 if (lseek(fd, offset, SEEK_SET) >= 0)
493 return write(fd, buf, count);
494 else
495 return -1;
496 }
497 #endif
498
499 #ifndef HAVE_SETENV
set_environment(const char * key,const char * value)500 int set_environment(const char *key, const char *value)
501 {
502 char *str;
503 int len = asprintf(&str, "%s=%s", key, value);
504 if (len < 0)
505 fwup_err(EXIT_FAILURE, "asprintf");
506 return putenv(str);
507 }
508 #endif
509
510 #ifndef HAVE_STRNDUP
strndup(const char * s,size_t n)511 char *strndup(const char *s, size_t n)
512 {
513 size_t len = strlen(s);
514 if (len < n)
515 n = len;
516 char *buf = (char *) malloc(n + 1);
517 if (buf) {
518 memcpy(buf, s, n);
519 buf[n] = '\0';
520 }
521 return buf;
522 }
523 #endif
524
525 #ifndef HAVE_MEMMEM
memmem(const void * haystack,size_t haystacklen,const void * needle,size_t needlelen)526 void *memmem(const void *haystack, size_t haystacklen,
527 const void *needle, size_t needlelen)
528 {
529 const char *p = (const char *) haystack;
530 const char *pend = p + haystacklen - needlelen;
531 for (;p != pend; p++) {
532 if (memcmp(p, needle, needlelen) == 0)
533 return (void *) p;
534 }
535 return NULL;
536 }
537 #endif
538
539 /*
540 * Aligned buffer support
541 */
542 #if HAVE_SYSCONF
543 static size_t cached_pagesize = 0;
544 #else
545 // If no sysconf(), guess the page size
546 static const size_t cached_pagesize = 4096;
547 #endif
548
get_pagesize()549 static inline size_t get_pagesize()
550 {
551 #if HAVE_SYSCONF
552 // If sysconf() exists, then call it to find the system's page size
553 if (cached_pagesize == 0) {
554 long rc = sysconf(_SC_PAGESIZE);
555 if (rc > 0)
556 cached_pagesize = rc;
557 else
558 cached_pagesize = 4096; // Guess
559 }
560 #endif
561 return cached_pagesize;
562 }
563
alloc_page_aligned(void ** memptr,size_t size)564 void alloc_page_aligned(void **memptr, size_t size)
565 {
566 size_t pagesize = get_pagesize();
567
568 #if HAVE_POSIX_MEMALIGN
569 if (posix_memalign(memptr, pagesize, size) < 0)
570 fwup_err(EXIT_FAILURE, "posix_memalign %u bytes", (unsigned int) size);
571 #else
572 // Slightly wasteful implementation of posix_memalign
573 size_t padding = pagesize + pagesize - 1;
574 uint8_t *original = (uint8_t *) malloc(size + padding);
575 if (original == NULL)
576 fwup_err(EXIT_FAILURE, "malloc %d bytes", (int) (size + padding));
577
578 // Store the original pointer right before the aligned pointer
579 uint8_t *aligned = (uint8_t *) (((uint64_t) (original + padding)) & ~(pagesize - 1));
580 void **savelocation = (void**) (aligned - sizeof(void*));
581 *savelocation = original;
582 *memptr = aligned;
583 #endif
584 }
585
free_page_aligned(void * memptr)586 void free_page_aligned(void *memptr)
587 {
588 #if HAVE_POSIX_MEMALIGN
589 free(memptr);
590 #else
591 void **savelocation = ((void **) memptr) - 1;
592 void *original = *savelocation;
593 free(original);
594 #endif
595 }
596
update_relative_path(const char * fromfile,const char * filename,char ** newpath)597 int update_relative_path(const char *fromfile, const char *filename, char **newpath)
598 {
599 if (filename[0] == '/' ||
600 filename[0] == '~') {
601 // If absolute then don't modify the path
602 *newpath = strdup(filename);
603 } else {
604 // If relative, make it relative to the specified file.
605 char *fromfile_copy = strdup(fromfile);
606 char *fromdir = dirname(fromfile_copy);
607 if (asprintf(newpath, "%s/%s", fromdir, filename) < 0)
608 fwup_err(EXIT_FAILURE, "asprintf");
609
610 free(fromfile_copy);
611 }
612 return 0;
613 }
614
615 /**
616 * Convert a UUID to a string in big endian form.
617 *
618 * Historical note: fwup always printed UUIDs in big endian. Then GPT support
619 * came in with the mixed endian UUIDs. That's why this looks weird and it's
620 * hard to change them to be consistent.
621 *
622 * @param uuid the UUID
623 * @param uuid_str a buffer that's UUID_STR_LENGTH long
624 */
uuid_to_string_be(const uint8_t uuid[UUID_LENGTH],char * uuid_str)625 void uuid_to_string_be(const uint8_t uuid[UUID_LENGTH], char *uuid_str)
626 {
627 sprintf(uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
628 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
629 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
630 }
631
632 /**
633 * Convert a string to a mixed endian UUID
634 *
635 * @param uuid_str the string
636 * @param uuid the resulting UUID
637 * @return 0 on success; -1 on error
638 */
string_to_uuid_me(const char * uuid_str,uint8_t uuid[UUID_LENGTH])639 int string_to_uuid_me(const char *uuid_str, uint8_t uuid[UUID_LENGTH])
640 {
641 // sscanf %02hhx doesn't seem to work everywhere (i.e., Windows), so we
642 // have to work harder.
643
644 // 32 digits and 4 hyphens
645 if ((strlen(uuid_str) >= 32 + 4) &&
646 two_hex_to_byte(&uuid_str[0], &uuid[3]) >= 0 &&
647 two_hex_to_byte(&uuid_str[2], &uuid[2]) >= 0 &&
648 two_hex_to_byte(&uuid_str[4], &uuid[1]) >= 0 &&
649 two_hex_to_byte(&uuid_str[6], &uuid[0]) >= 0 &&
650 uuid_str[8] == '-' &&
651 two_hex_to_byte(&uuid_str[9], &uuid[5]) >= 0 &&
652 two_hex_to_byte(&uuid_str[11], &uuid[4]) >= 0 &&
653 uuid_str[13] == '-' &&
654 two_hex_to_byte(&uuid_str[14], &uuid[7]) >= 0 &&
655 two_hex_to_byte(&uuid_str[16], &uuid[6]) >= 0 &&
656 uuid_str[18] == '-' &&
657 two_hex_to_byte(&uuid_str[19], &uuid[8]) >= 0 &&
658 two_hex_to_byte(&uuid_str[21], &uuid[9]) >= 0 &&
659 uuid_str[23] == '-' &&
660 two_hex_to_byte(&uuid_str[24], &uuid[10]) >= 0 &&
661 two_hex_to_byte(&uuid_str[26], &uuid[11]) >= 0 &&
662 two_hex_to_byte(&uuid_str[28], &uuid[12]) >= 0 &&
663 two_hex_to_byte(&uuid_str[30], &uuid[13]) >= 0 &&
664 two_hex_to_byte(&uuid_str[32], &uuid[14]) >= 0 &&
665 two_hex_to_byte(&uuid_str[34], &uuid[15]) >= 0)
666 return 0;
667 else
668 return -1;
669 }
670
671 /**
672 * Create a new UUID by hashing the specified data
673 *
674 * @param data
675 * @param data_size
676 * @param uuid
677 */
calculate_fwup_uuid(const char * data,off_t data_size,char * uuid)678 void calculate_fwup_uuid(const char *data, off_t data_size, char *uuid)
679 {
680 crypto_blake2b_ctx hash_state;
681 crypto_blake2b_general_init(&hash_state, FWUP_BLAKE2b_256_LEN, NULL, 0);
682
683 // fwup's UUID: 2053dffb-d51e-4310-b93b-956da89f9f34
684 unsigned char fwup_uuid[UUID_LENGTH] = {0x20, 0x53, 0xdf, 0xfb, 0xd5, 0x1e, 0x43, 0x10, 0xb9, 0x3b, 0x95, 0x6d, 0xa8, 0x9f, 0x9f, 0x34};
685
686 crypto_blake2b_update(&hash_state, fwup_uuid, sizeof(fwup_uuid));
687 crypto_blake2b_update(&hash_state, (const unsigned char *) data, (unsigned long long) data_size);
688
689 unsigned char hash[64];
690 crypto_blake2b_final(&hash_state, hash);
691
692 // Set version number (RFC 4122) to 5. This really isn't right since we're
693 // not using SHA-1, but monocypher doesn't include SHA-1.
694 hash[6] = (hash[6] & 0x0f) | 0x50;
695
696 uuid_to_string_be(hash, uuid);
697 }
698
699 /**
700 * Convert an ASCII string to UTF16LE
701 *
702 * @param input The input string
703 * @param output Where to store the output
704 * @param len The number of characters to convert
705 */
ascii_to_utf16le(const char * input,char * output,size_t len)706 void ascii_to_utf16le(const char *input, char *output, size_t len)
707 {
708 while (len) {
709 *output++ = *input++;
710 *output++ = 0;
711 len--;
712 }
713 }
714
copy_le64(uint8_t * output,uint64_t v)715 void copy_le64(uint8_t *output, uint64_t v)
716 {
717 output[0] = v & 0xff;
718 output[1] = (v >> 8) & 0xff;
719 output[2] = (v >> 16) & 0xff;
720 output[3] = (v >> 24) & 0xff;
721 output[4] = (v >> 32) & 0xff;
722 output[5] = (v >> 40) & 0xff;
723 output[6] = (v >> 48) & 0xff;
724 output[7] = (v >> 56) & 0xff;
725 }
726
copy_le32(uint8_t * output,uint32_t v)727 void copy_le32(uint8_t *output, uint32_t v)
728 {
729 output[0] = v & 0xff;
730 output[1] = (v >> 8) & 0xff;
731 output[2] = (v >> 16) & 0xff;
732 output[3] = (v >> 24) & 0xff;
733 }
734
copy_le16(uint8_t * output,uint16_t v)735 void copy_le16(uint8_t *output, uint16_t v)
736 {
737 output[0] = v & 0xff;
738 output[1] = (v >> 8) & 0xff;
739 }
740
741 #ifndef FWUP_APPLY_ONLY
742 // Random numbers are only needed for public/private key pair creation. Since
743 // cryptographic random number generation requires scrutiny to ensure
744 // correctness, do not include these on minimal builds so that there's no need
745 // to verify correctness on devices that use them.
746
747 #if defined(__linux__)
748 #if HAVE_SYS_RANDOM_H
749 #include <sys/random.h>
750
get_random(uint8_t * buf,size_t len)751 int get_random(uint8_t *buf, size_t len)
752 {
753 return getrandom(buf, len, 0);
754 }
755 #else
756 #include <sys/types.h>
757 #include <sys/stat.h>
758 #include <fcntl.h>
759
get_random(uint8_t * buf,size_t len)760 int get_random(uint8_t *buf, size_t len)
761 {
762 int fd = open("/dev/urandom", O_RDONLY);
763 if (fd < 0)
764 return -1;
765
766 ssize_t amt = read(fd, buf, len);
767 close(fd);
768
769 if (amt == ((size_t) len))
770 return 0;
771 else
772 return -1;
773 }
774 #endif
775
776 #endif
777
778 #if defined(__FreeBSD__) || defined(__NetBSD__) || \
779 defined(__OpenBSD__) || defined(__DragonFly__) || \
780 defined(__APPLE__)
get_random(uint8_t * buf,size_t len)781 int get_random(uint8_t *buf, size_t len)
782 {
783 arc4random_buf(buf, len);
784 return 0;
785 }
786 #endif
787
788 #if defined(_WIN32) || defined(__CYGWIN__)
789 #include <windows.h>
790
791 #ifdef THIS_FAILS_ON_WINE_AND_I_DONT_KNOW_WHY
792 #include <bcrypt.h>
get_random(uint8_t * buf,size_t len)793 int get_random(uint8_t *buf, size_t len)
794 {
795 BCRYPT_ALG_HANDLE handle;
796
797 if (BCryptOpenAlgorithmProvider(&handle, BCRYPT_RNG_ALGORITHM, NULL, 0) != 0 &&
798 BCryptGenRandom(handle, buf, len, 0) != 0) {
799 BCryptCloseAlgorithmProvider(handle, 0);
800 return 0;
801 } else {
802 return -1;
803 }
804 }
805 #else
806 #include <ntsecapi.h>
get_random(uint8_t * buf,size_t len)807 int get_random(uint8_t *buf, size_t len)
808 {
809 RtlGenRandom(buf, len);
810 return 0;
811 }
812 #endif
813 #endif // _WIN32 || __CYGWIN__
814 #endif // FWUP_APPLY_ONLY
815