load_powerpc.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2019 IBM Corporation
  4. * Author: Nayna Jain
  5. *
  6. * - loads keys and hashes stored and controlled by the firmware.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/cred.h>
  11. #include <linux/err.h>
  12. #include <linux/slab.h>
  13. #include <asm/secure_boot.h>
  14. #include <asm/secvar.h>
  15. #include "keyring_handler.h"
  16. #include "../integrity.h"
  17. #define extract_esl(db, data, size, offset) \
  18. do { db = data + offset; size = size - offset; } while (0)
  19. /*
  20. * Get a certificate list blob from the named secure variable.
  21. *
  22. * Returns:
  23. * - a pointer to a kmalloc'd buffer containing the cert list on success
  24. * - NULL if the key does not exist
  25. * - an ERR_PTR on error
  26. */
  27. static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
  28. {
  29. int rc;
  30. void *db;
  31. rc = secvar_ops->get(key, keylen, NULL, size);
  32. if (rc) {
  33. if (rc == -ENOENT)
  34. return NULL;
  35. return ERR_PTR(rc);
  36. }
  37. db = kmalloc(*size, GFP_KERNEL);
  38. if (!db)
  39. return ERR_PTR(-ENOMEM);
  40. rc = secvar_ops->get(key, keylen, db, size);
  41. if (rc) {
  42. kfree(db);
  43. return ERR_PTR(rc);
  44. }
  45. return db;
  46. }
  47. /*
  48. * Load the certs contained in the keys databases into the platform trusted
  49. * keyring and the blacklisted X.509 cert SHA256 hashes into the blacklist
  50. * keyring.
  51. */
  52. static int __init load_powerpc_certs(void)
  53. {
  54. void *db = NULL, *dbx = NULL, *data = NULL;
  55. void *trustedca;
  56. void *moduledb;
  57. u64 dsize = 0;
  58. u64 offset = 0;
  59. int rc = 0;
  60. ssize_t len;
  61. char buf[32];
  62. if (!secvar_ops)
  63. return -ENODEV;
  64. len = secvar_ops->format(buf, sizeof(buf));
  65. if (len <= 0)
  66. return -ENODEV;
  67. // Check for known secure boot implementations from OPAL or PLPKS
  68. if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf) &&
  69. strcmp("ibm,plpks-sb-v0", buf)) {
  70. pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
  71. return -ENODEV;
  72. }
  73. if (strcmp("ibm,plpks-sb-v1", buf) == 0 || strcmp("ibm,plpks-sb-v0", buf) == 0)
  74. /* PLPKS authenticated variables ESL data is prefixed with 8 bytes of timestamp */
  75. offset = 8;
  76. /*
  77. * Get db, and dbx. They might not exist, so it isn't an error if we
  78. * can't get them.
  79. */
  80. data = get_cert_list("db", 3, &dsize);
  81. if (!data) {
  82. pr_info("Couldn't get db list from firmware\n");
  83. } else if (IS_ERR(data)) {
  84. rc = PTR_ERR(data);
  85. pr_err("Error reading db from firmware: %d\n", rc);
  86. return rc;
  87. } else {
  88. extract_esl(db, data, dsize, offset);
  89. rc = parse_efi_signature_list("powerpc:db", db, dsize,
  90. get_handler_for_db);
  91. if (rc)
  92. pr_err("Couldn't parse db signatures: %d\n", rc);
  93. kfree(data);
  94. }
  95. data = get_cert_list("dbx", 4, &dsize);
  96. if (!data) {
  97. pr_info("Couldn't get dbx list from firmware\n");
  98. } else if (IS_ERR(data)) {
  99. rc = PTR_ERR(data);
  100. pr_err("Error reading dbx from firmware: %d\n", rc);
  101. return rc;
  102. } else {
  103. extract_esl(dbx, data, dsize, offset);
  104. rc = parse_efi_signature_list("powerpc:dbx", dbx, dsize,
  105. get_handler_for_dbx);
  106. if (rc)
  107. pr_err("Couldn't parse dbx signatures: %d\n", rc);
  108. kfree(data);
  109. }
  110. data = get_cert_list("trustedcadb", 12, &dsize);
  111. if (!data) {
  112. pr_info("Couldn't get trustedcadb list from firmware\n");
  113. } else if (IS_ERR(data)) {
  114. rc = PTR_ERR(data);
  115. pr_err("Error reading trustedcadb from firmware: %d\n", rc);
  116. } else {
  117. extract_esl(trustedca, data, dsize, offset);
  118. rc = parse_efi_signature_list("powerpc:trustedca", trustedca, dsize,
  119. get_handler_for_ca_keys);
  120. if (rc)
  121. pr_err("Couldn't parse trustedcadb signatures: %d\n", rc);
  122. kfree(data);
  123. }
  124. data = get_cert_list("moduledb", 9, &dsize);
  125. if (!data) {
  126. pr_info("Couldn't get moduledb list from firmware\n");
  127. } else if (IS_ERR(data)) {
  128. rc = PTR_ERR(data);
  129. pr_err("Error reading moduledb from firmware: %d\n", rc);
  130. } else {
  131. extract_esl(moduledb, data, dsize, offset);
  132. rc = parse_efi_signature_list("powerpc:moduledb", moduledb, dsize,
  133. get_handler_for_code_signing_keys);
  134. if (rc)
  135. pr_err("Couldn't parse moduledb signatures: %d\n", rc);
  136. kfree(data);
  137. }
  138. return rc;
  139. }
  140. late_initcall(load_powerpc_certs);