Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
keymanager.cc
1 #include "keymanager.h"
2 
3 #include <stdexcept>
4 
5 #include <boost/scoped_array.hpp>
6 #include <utility>
7 
8 #include "storage/invstorage.h"
9 #include "utilities/types.h"
10 
11 #if defined(ANDROID)
12 #include "androidkeystore.h"
13 #endif
14 
15 // by using constexpr the compiler can optimize out method calls when the
16 // feature is disabled. We won't then need to link with the actual p11 engine
17 // implementation
18 #ifdef BUILD_P11
19 static constexpr bool built_with_p11 = true;
20 #else
21 static constexpr bool built_with_p11 = false;
22 #endif
23 
24 KeyManager::KeyManager(std::shared_ptr<INvStorage> backend, KeyManagerConfig config)
25  : backend_(std::move(backend)), config_(std::move(config)) {
26  if (built_with_p11) {
27  p11_ = std_::make_unique<P11EngineGuard>(config_.p11);
28  }
29 }
30 
31 void KeyManager::loadKeys(const std::string *pkey_content, const std::string *cert_content,
32  const std::string *ca_content) {
33  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
34  std::string pkey;
35  if (pkey_content != nullptr) {
36  pkey = *pkey_content;
37  } else {
38  backend_->loadTlsPkey(&pkey);
39  }
40  if (!pkey.empty()) {
41  if (tmp_pkey_file == nullptr) {
42  tmp_pkey_file = std_::make_unique<TemporaryFile>("tls-pkey");
43  }
44  tmp_pkey_file->PutContents(pkey);
45  }
46  }
47  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
48  std::string cert;
49  if (cert_content != nullptr) {
50  cert = *cert_content;
51  } else {
52  backend_->loadTlsCert(&cert);
53  }
54  if (!cert.empty()) {
55  if (tmp_cert_file == nullptr) {
56  tmp_cert_file = std_::make_unique<TemporaryFile>("tls-cert");
57  }
58  tmp_cert_file->PutContents(cert);
59  }
60  }
61  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
62  std::string ca;
63  if (ca_content != nullptr) {
64  ca = *ca_content;
65  } else {
66  backend_->loadTlsCa(&ca);
67  }
68  if (!ca.empty()) {
69  if (tmp_ca_file == nullptr) {
70  tmp_ca_file = std_::make_unique<TemporaryFile>("tls-ca");
71  }
72  tmp_ca_file->PutContents(ca);
73  }
74  }
75 }
76 
77 std::string KeyManager::getPkeyFile() const {
78  std::string pkey_file;
79  if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
80  if (!built_with_p11) {
81  throw std::runtime_error("Aktualizr was built without PKCS#11");
82  }
83  pkey_file = (*p11_)->getTlsPkeyId();
84  }
85  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
86  if (tmp_pkey_file && !boost::filesystem::is_empty(tmp_pkey_file->PathString())) {
87  pkey_file = tmp_pkey_file->PathString();
88  }
89  }
90  return pkey_file;
91 }
92 
93 std::string KeyManager::getCertFile() const {
94  std::string cert_file;
95  if (config_.tls_cert_source == CryptoSource::kPkcs11) {
96  if (!built_with_p11) {
97  throw std::runtime_error("Aktualizr was built without PKCS#11");
98  }
99  cert_file = (*p11_)->getTlsCertId();
100  }
101  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
102  if (tmp_cert_file && !boost::filesystem::is_empty(tmp_cert_file->PathString())) {
103  cert_file = tmp_cert_file->PathString();
104  }
105  }
106  return cert_file;
107 }
108 
109 std::string KeyManager::getCaFile() const {
110  std::string ca_file;
111  if (config_.tls_ca_source == CryptoSource::kPkcs11) {
112  if (!built_with_p11) {
113  throw std::runtime_error("Aktualizr was built without PKCS#11");
114  }
115  ca_file = (*p11_)->getTlsCacertId();
116  }
117  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
118  if (tmp_ca_file && !boost::filesystem::is_empty(tmp_ca_file->PathString())) {
119  ca_file = tmp_ca_file->PathString();
120  }
121  }
122  return ca_file;
123 }
124 
125 std::string KeyManager::getPkey() const {
126  std::string pkey;
127  if (config_.tls_pkey_source == CryptoSource::kPkcs11) {
128  if (!built_with_p11) {
129  throw std::runtime_error("Aktualizr was built without PKCS#11");
130  }
131  pkey = (*p11_)->getTlsPkeyId();
132  }
133  if (config_.tls_pkey_source == CryptoSource::kFile || config_.tls_pkey_source == CryptoSource::kAndroid) {
134  backend_->loadTlsPkey(&pkey);
135  }
136  return pkey;
137 }
138 
139 std::string KeyManager::getCert() const {
140  std::string cert;
141  if (config_.tls_cert_source == CryptoSource::kPkcs11) {
142  if (!built_with_p11) {
143  throw std::runtime_error("Aktualizr was built without PKCS#11");
144  }
145  cert = (*p11_)->getTlsCertId();
146  }
147  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
148  backend_->loadTlsCert(&cert);
149  }
150  return cert;
151 }
152 
153 std::string KeyManager::getCa() const {
154  std::string ca;
155  if (config_.tls_ca_source == CryptoSource::kPkcs11) {
156  if (!built_with_p11) {
157  throw std::runtime_error("Aktualizr was built without PKCS#11");
158  }
159  ca = (*p11_)->getTlsCacertId();
160  }
161  if (config_.tls_ca_source == CryptoSource::kFile || config_.tls_ca_source == CryptoSource::kAndroid) {
162  backend_->loadTlsCa(&ca);
163  }
164  return ca;
165 }
166 
167 std::string KeyManager::getCN() const {
168  std::string not_found_cert_message = "Certificate is not found, can't extract device_id";
169  std::string cert;
170  if (config_.tls_cert_source == CryptoSource::kFile || config_.tls_cert_source == CryptoSource::kAndroid) {
171  if (!backend_->loadTlsCert(&cert)) {
172  throw std::runtime_error(not_found_cert_message);
173  }
174  } else { // CryptoSource::kPkcs11
175  if (!built_with_p11) {
176  throw std::runtime_error("Aktualizr was built without PKCS#11 support, can't extract device_id");
177  }
178  if (!(*p11_)->readTlsCert(&cert)) {
179  throw std::runtime_error(not_found_cert_message);
180  }
181  }
182 
183  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
184  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
185  if (x == nullptr) {
186  throw std::runtime_error("Could not parse certificate");
187  }
188 
189  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, nullptr, 0);
190  if (len < 0) {
191  throw std::runtime_error("Could not get CN from certificate");
192  }
193  boost::scoped_array<char> buf(new char[len + 1]);
194  X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, buf.get(), len + 1);
195  std::string cn(buf.get());
196  return cn;
197 }
198 
199 void KeyManager::copyCertsToCurl(HttpInterface &http) {
200  std::string pkey = getPkey();
201  std::string cert = getCert();
202  std::string ca = getCa();
203 
204  if ((pkey.size() != 0u) && (cert.size() != 0u) && (ca.size() != 0u)) {
205  http.setCerts(ca, config_.tls_ca_source, cert, config_.tls_cert_source, pkey, config_.tls_pkey_source);
206  }
207 }
208 
209 Json::Value KeyManager::signTuf(const Json::Value &in_data) const {
210  ENGINE *crypto_engine = nullptr;
211  std::string private_key;
212  if (config_.uptane_key_source == CryptoSource::kPkcs11) {
213  if (!built_with_p11) {
214  throw std::runtime_error("Aktualizr was built without PKCS#11");
215  }
216  crypto_engine = (*p11_)->getEngine();
217  private_key = config_.p11.uptane_key_id;
218  }
219 
220  std::string b64sig;
221  if (config_.uptane_key_source == CryptoSource::kAndroid) {
222 #if defined(ANDROID)
223  b64sig = AndroidKeyStore::instance().signData(Utils::jsonToCanonicalStr(in_data));
224 #else
225  throw std::runtime_error("Aktualizr was built without Android support");
226 #endif
227  } else {
228  if (config_.uptane_key_source == CryptoSource::kFile) {
229  backend_->loadPrimaryPrivate(&private_key);
230  }
231  b64sig = Utils::toBase64(
232  Crypto::Sign(config_.uptane_key_type, crypto_engine, private_key, Utils::jsonToCanonicalStr(in_data)));
233  }
234 
235  Json::Value signature;
236  signature["method"] = "rsassa-pss";
237  signature["sig"] = b64sig;
238 
239  Json::Value out_data;
240  signature["keyid"] = UptanePublicKey().KeyId();
241  out_data["signed"] = in_data;
242  out_data["signatures"] = Json::Value(Json::arrayValue);
243  out_data["signatures"].append(signature);
244  return out_data;
245 }
246 
247 std::string KeyManager::generateUptaneKeyPair() {
248  std::string primary_public;
249 
250  if (config_.uptane_key_source == CryptoSource::kFile) {
251  std::string primary_private;
252  if (!backend_->loadPrimaryKeys(&primary_public, &primary_private)) {
253  bool result_ = Crypto::generateKeyPair(config_.uptane_key_type, &primary_public, &primary_private);
254  if (result_) {
255  backend_->storePrimaryKeys(primary_public, primary_private);
256  }
257  }
258  if (primary_public.empty() && primary_private.empty()) {
259  throw std::runtime_error("Could not get uptane keys");
260  }
261  } else if (config_.uptane_key_source == CryptoSource::kAndroid) {
262 #if defined(ANDROID)
263  primary_public = AndroidKeyStore::instance().getPublicKey();
264  if (primary_public.empty()) {
265  primary_public = AndroidKeyStore::instance().generateKeyPair();
266  }
267 #else
268  throw std::runtime_error("Aktualizr was built without Android support");
269 #endif
270  if (primary_public.empty()) {
271  throw std::runtime_error("Could not get uptane keys");
272  }
273  } else {
274  if (!built_with_p11) {
275  throw std::runtime_error("Aktualizr was built without pkcs11 support!");
276  }
277  // dummy read to check if the key is present
278  if (!(*p11_)->readUptanePublicKey(&primary_public)) {
279  (*p11_)->generateUptaneKeyPair();
280  }
281  // really read the key
282  if (primary_public.empty() && !(*p11_)->readUptanePublicKey(&primary_public)) {
283  throw std::runtime_error("Could not get uptane keys");
284  }
285  }
286  return primary_public;
287 }
288 
289 PublicKey KeyManager::UptanePublicKey() const {
290  std::string primary_public;
291  if (config_.uptane_key_source == CryptoSource::kFile) {
292  if (!backend_->loadPrimaryPublic(&primary_public)) {
293  throw std::runtime_error("Could not get uptane public key!");
294  }
295  } else if (config_.uptane_key_source == CryptoSource::kAndroid) {
296 #if defined(ANDROID)
297  primary_public = AndroidKeyStore::instance().getPublicKey();
298 #else
299  throw std::runtime_error("Aktualizr was built without Android support");
300 #endif
301  if (primary_public.empty()) {
302  throw std::runtime_error("Could not get uptane public key!");
303  }
304  } else {
305  if (!built_with_p11) {
306  throw std::runtime_error("Aktualizr was built without pkcs11 support!");
307  }
308  // dummy read to check if the key is present
309  if (!(*p11_)->readUptanePublicKey(&primary_public)) {
310  throw std::runtime_error("Could not get uptane public key!");
311  }
312  }
313  return PublicKey(primary_public, config_.uptane_key_type);
314 }
types.h
HttpInterface
Definition: httpinterface.h:38
PublicKey
Definition: crypto.h:26
KeyManagerConfig
Definition: keymanager_config.h:9