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