2
0

var-service-siglist.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * SPDX-License-Identifier: GPL-2.0-or-later
  3. *
  4. * uefi vars device - parse and generate efi signature databases
  5. */
  6. #include "qemu/osdep.h"
  7. #include "qemu/error-report.h"
  8. #include "system/dma.h"
  9. #include "hw/uefi/var-service.h"
  10. /*
  11. * Add x509 certificate to list (with duplicate check).
  12. */
  13. static void uefi_vars_siglist_add_x509(uefi_vars_siglist *siglist,
  14. QemuUUID *owner,
  15. void *data, uint64_t size)
  16. {
  17. uefi_vars_cert *c;
  18. QTAILQ_FOREACH(c, &siglist->x509, next) {
  19. if (c->size != size) {
  20. continue;
  21. }
  22. if (memcmp(c->data, data, size) != 0) {
  23. continue;
  24. }
  25. return;
  26. }
  27. c = g_malloc(sizeof(*c) + size);
  28. c->owner = *owner;
  29. c->size = size;
  30. memcpy(c->data, data, size);
  31. QTAILQ_INSERT_TAIL(&siglist->x509, c, next);
  32. }
  33. /*
  34. * Add sha256 hash to list (with duplicate check).
  35. */
  36. static void uefi_vars_siglist_add_sha256(uefi_vars_siglist *siglist,
  37. QemuUUID *owner,
  38. void *data)
  39. {
  40. uefi_vars_hash *h;
  41. QTAILQ_FOREACH(h, &siglist->sha256, next) {
  42. if (memcmp(h->data, data, 32) != 0) {
  43. continue;
  44. }
  45. return;
  46. }
  47. h = g_malloc(sizeof(*h) + 32);
  48. h->owner = *owner;
  49. memcpy(h->data, data, 32);
  50. QTAILQ_INSERT_TAIL(&siglist->sha256, h, next);
  51. }
  52. void uefi_vars_siglist_init(uefi_vars_siglist *siglist)
  53. {
  54. memset(siglist, 0, sizeof(*siglist));
  55. QTAILQ_INIT(&siglist->x509);
  56. QTAILQ_INIT(&siglist->sha256);
  57. }
  58. void uefi_vars_siglist_free(uefi_vars_siglist *siglist)
  59. {
  60. uefi_vars_cert *c, *cs;
  61. uefi_vars_hash *h, *hs;
  62. QTAILQ_FOREACH_SAFE(c, &siglist->x509, next, cs) {
  63. QTAILQ_REMOVE(&siglist->x509, c, next);
  64. g_free(c);
  65. }
  66. QTAILQ_FOREACH_SAFE(h, &siglist->sha256, next, hs) {
  67. QTAILQ_REMOVE(&siglist->sha256, h, next);
  68. g_free(h);
  69. }
  70. }
  71. /*
  72. * Parse UEFI signature list.
  73. */
  74. void uefi_vars_siglist_parse(uefi_vars_siglist *siglist,
  75. void *data, uint64_t size)
  76. {
  77. efi_siglist *efilist;
  78. uint64_t start;
  79. while (size) {
  80. if (size < sizeof(*efilist)) {
  81. break;
  82. }
  83. efilist = data;
  84. if (size < efilist->siglist_size) {
  85. break;
  86. }
  87. if (uadd64_overflow(sizeof(*efilist), efilist->header_size, &start)) {
  88. break;
  89. }
  90. if (efilist->sig_size <= sizeof(QemuUUID)) {
  91. break;
  92. }
  93. if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertX509Guid)) {
  94. if (start + efilist->sig_size != efilist->siglist_size) {
  95. break;
  96. }
  97. uefi_vars_siglist_add_x509(siglist,
  98. (QemuUUID *)(data + start),
  99. data + start + sizeof(QemuUUID),
  100. efilist->sig_size - sizeof(QemuUUID));
  101. } else if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertSha256Guid)) {
  102. if (efilist->sig_size != sizeof(QemuUUID) + 32) {
  103. break;
  104. }
  105. if (start + efilist->sig_size > efilist->siglist_size) {
  106. break;
  107. }
  108. while (start <= efilist->siglist_size - efilist->sig_size) {
  109. uefi_vars_siglist_add_sha256(siglist,
  110. (QemuUUID *)(data + start),
  111. data + start + sizeof(QemuUUID));
  112. start += efilist->sig_size;
  113. }
  114. } else {
  115. QemuUUID be = qemu_uuid_bswap(efilist->guid_type);
  116. char *str_uuid = qemu_uuid_unparse_strdup(&be);
  117. warn_report("%s: unknown type (%s)", __func__, str_uuid);
  118. g_free(str_uuid);
  119. }
  120. data += efilist->siglist_size;
  121. size -= efilist->siglist_size;
  122. }
  123. }
  124. uint64_t uefi_vars_siglist_blob_size(uefi_vars_siglist *siglist)
  125. {
  126. uefi_vars_cert *c;
  127. uefi_vars_hash *h;
  128. uint64_t size = 0;
  129. QTAILQ_FOREACH(c, &siglist->x509, next) {
  130. size += sizeof(efi_siglist) + sizeof(QemuUUID) + c->size;
  131. }
  132. if (!QTAILQ_EMPTY(&siglist->sha256)) {
  133. size += sizeof(efi_siglist);
  134. QTAILQ_FOREACH(h, &siglist->sha256, next) {
  135. size += sizeof(QemuUUID) + 32;
  136. }
  137. }
  138. return size;
  139. }
  140. /*
  141. * Generate UEFI signature list.
  142. */
  143. void uefi_vars_siglist_blob_generate(uefi_vars_siglist *siglist,
  144. void *data, uint64_t size)
  145. {
  146. uefi_vars_cert *c;
  147. uefi_vars_hash *h;
  148. efi_siglist *efilist;
  149. uint64_t pos = 0, start;
  150. uint32_t i;
  151. QTAILQ_FOREACH(c, &siglist->x509, next) {
  152. efilist = data + pos;
  153. efilist->guid_type = EfiCertX509Guid;
  154. efilist->sig_size = sizeof(QemuUUID) + c->size;
  155. efilist->header_size = 0;
  156. start = pos + sizeof(efi_siglist);
  157. memcpy(data + start,
  158. &c->owner, sizeof(QemuUUID));
  159. memcpy(data + start + sizeof(QemuUUID),
  160. c->data, c->size);
  161. efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size;
  162. pos += efilist->siglist_size;
  163. }
  164. if (!QTAILQ_EMPTY(&siglist->sha256)) {
  165. efilist = data + pos;
  166. efilist->guid_type = EfiCertSha256Guid;
  167. efilist->sig_size = sizeof(QemuUUID) + 32;
  168. efilist->header_size = 0;
  169. i = 0;
  170. start = pos + sizeof(efi_siglist);
  171. QTAILQ_FOREACH(h, &siglist->sha256, next) {
  172. memcpy(data + start + efilist->sig_size * i,
  173. &h->owner, sizeof(QemuUUID));
  174. memcpy(data + start + efilist->sig_size * i + sizeof(QemuUUID),
  175. h->data, 32);
  176. i++;
  177. }
  178. efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size * i;
  179. pos += efilist->siglist_size;
  180. }
  181. assert(pos == size);
  182. }