load_powerpc.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
  70. return -ENODEV;
  71. }
  72. if (strcmp("ibm,plpks-sb-v1", buf) == 0)
  73. /* PLPKS authenticated variables ESL data is prefixed with 8 bytes of timestamp */
  74. offset = 8;
  75. /*
  76. * Get db, and dbx. They might not exist, so it isn't an error if we
  77. * can't get them.
  78. */
  79. data = get_cert_list("db", 3, &dsize);
  80. if (!data) {
  81. pr_info("Couldn't get db list from firmware\n");
  82. } else if (IS_ERR(data)) {
  83. rc = PTR_ERR(data);
  84. pr_err("Error reading db from firmware: %d\n", rc);
  85. return rc;
  86. } else {
  87. extract_esl(db, data, dsize, offset);
  88. rc = parse_efi_signature_list("powerpc:db", db, dsize,
  89. get_handler_for_db);
  90. if (rc)
  91. pr_err("Couldn't parse db signatures: %d\n", rc);
  92. kfree(data);
  93. }
  94. data = get_cert_list("dbx", 4, &dsize);
  95. if (!data) {
  96. pr_info("Couldn't get dbx list from firmware\n");
  97. } else if (IS_ERR(data)) {
  98. rc = PTR_ERR(data);
  99. pr_err("Error reading dbx from firmware: %d\n", rc);
  100. return rc;
  101. } else {
  102. extract_esl(dbx, data, dsize, offset);
  103. rc = parse_efi_signature_list("powerpc:dbx", dbx, dsize,
  104. get_handler_for_dbx);
  105. if (rc)
  106. pr_err("Couldn't parse dbx signatures: %d\n", rc);
  107. kfree(data);
  108. }
  109. data = get_cert_list("trustedcadb", 12, &dsize);
  110. if (!data) {
  111. pr_info("Couldn't get trustedcadb list from firmware\n");
  112. } else if (IS_ERR(data)) {
  113. rc = PTR_ERR(data);
  114. pr_err("Error reading trustedcadb from firmware: %d\n", rc);
  115. } else {
  116. extract_esl(trustedca, data, dsize, offset);
  117. rc = parse_efi_signature_list("powerpc:trustedca", trustedca, dsize,
  118. get_handler_for_ca_keys);
  119. if (rc)
  120. pr_err("Couldn't parse trustedcadb signatures: %d\n", rc);
  121. kfree(data);
  122. }
  123. data = get_cert_list("moduledb", 9, &dsize);
  124. if (!data) {
  125. pr_info("Couldn't get moduledb list from firmware\n");
  126. } else if (IS_ERR(data)) {
  127. rc = PTR_ERR(data);
  128. pr_err("Error reading moduledb from firmware: %d\n", rc);
  129. } else {
  130. extract_esl(moduledb, data, dsize, offset);
  131. rc = parse_efi_signature_list("powerpc:moduledb", moduledb, dsize,
  132. get_handler_for_code_signing_keys);
  133. if (rc)
  134. pr_err("Couldn't parse moduledb signatures: %d\n", rc);
  135. kfree(data);
  136. }
  137. return rc;
  138. }
  139. late_initcall(load_powerpc_certs);