mini_keyctl_utils.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright (C) 2019 The Android Open Source Project
  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. #include <mini_keyctl_utils.h>
  17. #include <dirent.h>
  18. #include <errno.h>
  19. #include <sys/types.h>
  20. #include <unistd.h>
  21. #include <fstream>
  22. #include <iostream>
  23. #include <iterator>
  24. #include <sstream>
  25. #include <string>
  26. #include <vector>
  27. #include <android-base/file.h>
  28. #include <android-base/logging.h>
  29. #include <android-base/parseint.h>
  30. #include <android-base/properties.h>
  31. #include <android-base/strings.h>
  32. #include <keyutils.h>
  33. static constexpr int kMaxCertSize = 4096;
  34. static std::vector<std::string> SplitBySpace(const std::string& s) {
  35. std::istringstream iss(s);
  36. return std::vector<std::string>{std::istream_iterator<std::string>{iss},
  37. std::istream_iterator<std::string>{}};
  38. }
  39. // Find the keyring id. Because request_key(2) syscall is not available or the key is
  40. // kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
  41. // information in the descritption section depending on the key type, only the first word in the
  42. // keyring description is used for searching.
  43. static bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
  44. if (!keyring_id) {
  45. LOG(ERROR) << "keyring_id is null";
  46. return false;
  47. }
  48. // If the keyring id is already a hex number, directly convert it to keyring id
  49. if (android::base::ParseInt(keyring_desc.c_str(), keyring_id)) {
  50. return true;
  51. }
  52. // Only keys allowed by SELinux rules will be shown here.
  53. std::ifstream proc_keys_file("/proc/keys");
  54. if (!proc_keys_file.is_open()) {
  55. PLOG(ERROR) << "Failed to open /proc/keys";
  56. return false;
  57. }
  58. std::string line;
  59. while (getline(proc_keys_file, line)) {
  60. std::vector<std::string> tokens = SplitBySpace(line);
  61. if (tokens.size() < 9) {
  62. continue;
  63. }
  64. std::string key_id = tokens[0];
  65. std::string key_type = tokens[7];
  66. // The key description may contain space.
  67. std::string key_desc_prefix = tokens[8];
  68. // The prefix has a ":" at the end
  69. std::string key_desc_pattern = keyring_desc + ":";
  70. if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
  71. continue;
  72. }
  73. *keyring_id = std::stoi(key_id, nullptr, 16);
  74. return true;
  75. }
  76. return false;
  77. }
  78. int Unlink(key_serial_t key, const std::string& keyring) {
  79. key_serial_t keyring_id;
  80. if (!GetKeyringId(keyring, &keyring_id)) {
  81. LOG(ERROR) << "Can't find keyring " << keyring;
  82. return 1;
  83. }
  84. if (keyctl_unlink(key, keyring_id) < 0) {
  85. PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id;
  86. return 1;
  87. }
  88. return 0;
  89. }
  90. int Add(const std::string& type, const std::string& desc, const std::string& data,
  91. const std::string& keyring) {
  92. if (data.size() > kMaxCertSize) {
  93. LOG(ERROR) << "Certificate too large";
  94. return 1;
  95. }
  96. key_serial_t keyring_id;
  97. if (!GetKeyringId(keyring, &keyring_id)) {
  98. LOG(ERROR) << "Can not find keyring id";
  99. return 1;
  100. }
  101. key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
  102. if (key < 0) {
  103. PLOG(ERROR) << "Failed to add key";
  104. return 1;
  105. }
  106. LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
  107. return 0;
  108. }
  109. int Padd(const std::string& type, const std::string& desc, const std::string& keyring) {
  110. key_serial_t keyring_id;
  111. if (!GetKeyringId(keyring, &keyring_id)) {
  112. LOG(ERROR) << "Can not find keyring id";
  113. return 1;
  114. }
  115. // read from stdin to get the certificates
  116. std::istreambuf_iterator<char> begin(std::cin), end;
  117. std::string data(begin, end);
  118. if (data.size() > kMaxCertSize) {
  119. LOG(ERROR) << "Certificate too large";
  120. return 1;
  121. }
  122. key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
  123. if (key < 0) {
  124. PLOG(ERROR) << "Failed to add key";
  125. return 1;
  126. }
  127. LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
  128. return 0;
  129. }
  130. int RestrictKeyring(const std::string& keyring) {
  131. key_serial_t keyring_id;
  132. if (!GetKeyringId(keyring, &keyring_id)) {
  133. LOG(ERROR) << "Cannot find keyring id";
  134. return 1;
  135. }
  136. if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
  137. PLOG(ERROR) << "Cannot restrict keyring " << keyring;
  138. return 1;
  139. }
  140. return 0;
  141. }
  142. std::string RetrieveSecurityContext(key_serial_t key) {
  143. // Simply assume this size is enough in practice.
  144. const int kMaxSupportedSize = 256;
  145. std::string context;
  146. context.resize(kMaxSupportedSize);
  147. long retval = keyctl_get_security(key, context.data(), kMaxSupportedSize);
  148. if (retval < 0) {
  149. PLOG(ERROR) << "Cannot get security context of key 0x" << std::hex << key;
  150. return std::string();
  151. }
  152. if (retval > kMaxSupportedSize) {
  153. LOG(ERROR) << "The key has unexpectedly long security context than " << kMaxSupportedSize;
  154. return std::string();
  155. }
  156. context.resize(retval);
  157. return context;
  158. }