btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / keystore / Keyring.cpp
blobfbf11b4a0b4a3ec292058a1d1e408d4967083f48
1 /*
2 * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "Keyring.h"
10 Keyring::Keyring()
12 fHasUnlockKey(false),
13 fUnlocked(false),
14 fModified(false)
19 Keyring::Keyring(const char* name)
21 fName(name),
22 fHasUnlockKey(false),
23 fUnlocked(false),
24 fModified(false)
29 Keyring::~Keyring()
34 status_t
35 Keyring::ReadFromMessage(const BMessage& message)
37 status_t result = message.FindString("name", &fName);
38 if (result != B_OK)
39 return result;
41 result = message.FindBool("hasUnlockKey", &fHasUnlockKey);
42 if (result != B_OK)
43 return result;
45 if (message.GetBool("noData", false)) {
46 fFlatBuffer.SetSize(0);
47 return B_OK;
50 ssize_t size;
51 const void* data;
52 result = message.FindData("data", B_RAW_TYPE, &data, &size);
53 if (result != B_OK)
54 return result;
56 if (size < 0)
57 return B_ERROR;
59 fFlatBuffer.SetSize(0);
60 ssize_t written = fFlatBuffer.WriteAt(0, data, size);
61 if (written != size) {
62 fFlatBuffer.SetSize(0);
63 return written < 0 ? written : B_ERROR;
66 return B_OK;
70 status_t
71 Keyring::WriteToMessage(BMessage& message)
73 status_t result = _EncryptToFlatBuffer();
74 if (result != B_OK)
75 return result;
77 if (fFlatBuffer.BufferLength() == 0)
78 result = message.AddBool("noData", true);
79 else {
80 result = message.AddData("data", B_RAW_TYPE, fFlatBuffer.Buffer(),
81 fFlatBuffer.BufferLength());
83 if (result != B_OK)
84 return result;
86 result = message.AddBool("hasUnlockKey", fHasUnlockKey);
87 if (result != B_OK)
88 return result;
90 return message.AddString("name", fName);
94 status_t
95 Keyring::Unlock(const BMessage* keyMessage)
97 if (fUnlocked)
98 return B_OK;
100 if (fHasUnlockKey == (keyMessage == NULL))
101 return B_BAD_VALUE;
103 if (keyMessage != NULL)
104 fUnlockKey = *keyMessage;
106 status_t result = _DecryptFromFlatBuffer();
107 if (result != B_OK) {
108 fUnlockKey.MakeEmpty();
109 return result;
112 fUnlocked = true;
113 return B_OK;
117 void
118 Keyring::Lock()
120 if (!fUnlocked)
121 return;
123 _EncryptToFlatBuffer();
125 fUnlockKey.MakeEmpty();
126 fData.MakeEmpty();
127 fApplications.MakeEmpty();
128 fUnlocked = false;
132 bool
133 Keyring::IsUnlocked() const
135 return fUnlocked;
139 bool
140 Keyring::HasUnlockKey() const
142 return fHasUnlockKey;
146 const BMessage&
147 Keyring::UnlockKey() const
149 return fUnlockKey;
153 status_t
154 Keyring::SetUnlockKey(const BMessage& keyMessage)
156 if (!fUnlocked)
157 return B_NOT_ALLOWED;
159 fHasUnlockKey = true;
160 fUnlockKey = keyMessage;
161 fModified = true;
162 return B_OK;
166 status_t
167 Keyring::RemoveUnlockKey()
169 if (!fUnlocked)
170 return B_NOT_ALLOWED;
172 fUnlockKey.MakeEmpty();
173 fHasUnlockKey = false;
174 fModified = true;
175 return B_OK;
179 status_t
180 Keyring::GetNextApplication(uint32& cookie, BString& signature,
181 BString& path)
183 if (!fUnlocked)
184 return B_NOT_ALLOWED;
186 char* nameFound = NULL;
187 status_t result = fApplications.GetInfo(B_MESSAGE_TYPE, cookie++,
188 &nameFound, NULL);
189 if (result != B_OK)
190 return B_ENTRY_NOT_FOUND;
192 BMessage appMessage;
193 result = fApplications.FindMessage(nameFound, &appMessage);
194 if (result != B_OK)
195 return B_ENTRY_NOT_FOUND;
197 result = appMessage.FindString("path", &path);
198 if (result != B_OK)
199 return B_ERROR;
201 signature = nameFound;
202 return B_OK;
206 status_t
207 Keyring::FindApplication(const char* signature, const char* path,
208 BMessage& appMessage)
210 if (!fUnlocked)
211 return B_NOT_ALLOWED;
213 int32 count;
214 type_code type;
215 if (fApplications.GetInfo(signature, &type, &count) != B_OK)
216 return B_ENTRY_NOT_FOUND;
218 for (int32 i = 0; i < count; i++) {
219 if (fApplications.FindMessage(signature, i, &appMessage) != B_OK)
220 continue;
222 BString appPath;
223 if (appMessage.FindString("path", &appPath) != B_OK)
224 continue;
226 if (appPath == path)
227 return B_OK;
230 appMessage.MakeEmpty();
231 return B_ENTRY_NOT_FOUND;
235 status_t
236 Keyring::AddApplication(const char* signature, const BMessage& appMessage)
238 if (!fUnlocked)
239 return B_NOT_ALLOWED;
241 status_t result = fApplications.AddMessage(signature, &appMessage);
242 if (result != B_OK)
243 return result;
245 fModified = true;
246 return B_OK;
250 status_t
251 Keyring::RemoveApplication(const char* signature, const char* path)
253 if (!fUnlocked)
254 return B_NOT_ALLOWED;
256 if (path == NULL) {
257 // We want all of the entries for this signature removed.
258 status_t result = fApplications.RemoveName(signature);
259 if (result != B_OK)
260 return B_ENTRY_NOT_FOUND;
262 fModified = true;
263 return B_OK;
266 int32 count;
267 type_code type;
268 if (fApplications.GetInfo(signature, &type, &count) != B_OK)
269 return B_ENTRY_NOT_FOUND;
271 for (int32 i = 0; i < count; i++) {
272 BMessage appMessage;
273 if (fApplications.FindMessage(signature, i, &appMessage) != B_OK)
274 return B_ERROR;
276 BString appPath;
277 if (appMessage.FindString("path", &appPath) != B_OK)
278 continue;
280 if (appPath == path) {
281 fApplications.RemoveData(signature, i);
282 fModified = true;
283 return B_OK;
287 return B_ENTRY_NOT_FOUND;
291 status_t
292 Keyring::FindKey(const BString& identifier, const BString& secondaryIdentifier,
293 bool secondaryIdentifierOptional, BMessage* _foundKeyMessage) const
295 if (!fUnlocked)
296 return B_NOT_ALLOWED;
298 int32 count;
299 type_code type;
300 if (fData.GetInfo(identifier, &type, &count) != B_OK)
301 return B_ENTRY_NOT_FOUND;
303 // We have a matching primary identifier, need to check for the secondary
304 // identifier.
305 for (int32 i = 0; i < count; i++) {
306 BMessage candidate;
307 if (fData.FindMessage(identifier, i, &candidate) != B_OK)
308 return B_ERROR;
310 BString candidateIdentifier;
311 if (candidate.FindString("secondaryIdentifier",
312 &candidateIdentifier) != B_OK) {
313 candidateIdentifier = "";
316 if (candidateIdentifier == secondaryIdentifier) {
317 if (_foundKeyMessage != NULL)
318 *_foundKeyMessage = candidate;
319 return B_OK;
323 // We didn't find an exact match.
324 if (secondaryIdentifierOptional) {
325 if (_foundKeyMessage == NULL)
326 return B_OK;
328 // The secondary identifier is optional, so we just return the
329 // first entry.
330 return fData.FindMessage(identifier, 0, _foundKeyMessage);
333 return B_ENTRY_NOT_FOUND;
337 status_t
338 Keyring::FindKey(BKeyType type, BKeyPurpose purpose, uint32 index,
339 BMessage& _foundKeyMessage) const
341 if (!fUnlocked)
342 return B_NOT_ALLOWED;
344 for (int32 keyIndex = 0;; keyIndex++) {
345 int32 count = 0;
346 char* identifier = NULL;
347 if (fData.GetInfo(B_MESSAGE_TYPE, keyIndex, &identifier, NULL,
348 &count) != B_OK) {
349 break;
352 if (type == B_KEY_TYPE_ANY && purpose == B_KEY_PURPOSE_ANY) {
353 // No need to inspect the actual keys.
354 if ((int32)index >= count) {
355 index -= count;
356 continue;
359 return fData.FindMessage(identifier, index, &_foundKeyMessage);
362 // Go through the keys to check their type and purpose.
363 for (int32 subkeyIndex = 0; subkeyIndex < count; subkeyIndex++) {
364 BMessage subkey;
365 if (fData.FindMessage(identifier, subkeyIndex, &subkey) != B_OK)
366 return B_ERROR;
368 bool match = true;
369 if (type != B_KEY_TYPE_ANY) {
370 BKeyType subkeyType;
371 if (subkey.FindUInt32("type", (uint32*)&subkeyType) != B_OK)
372 return B_ERROR;
374 match = subkeyType == type;
377 if (match && purpose != B_KEY_PURPOSE_ANY) {
378 BKeyPurpose subkeyPurpose;
379 if (subkey.FindUInt32("purpose", (uint32*)&subkeyPurpose)
380 != B_OK) {
381 return B_ERROR;
384 match = subkeyPurpose == purpose;
387 if (match) {
388 if (index == 0) {
389 _foundKeyMessage = subkey;
390 return B_OK;
393 index--;
398 return B_ENTRY_NOT_FOUND;
402 status_t
403 Keyring::AddKey(const BString& identifier, const BString& secondaryIdentifier,
404 const BMessage& keyMessage)
406 if (!fUnlocked)
407 return B_NOT_ALLOWED;
409 // Check for collisions.
410 if (FindKey(identifier, secondaryIdentifier, false, NULL) == B_OK)
411 return B_NAME_IN_USE;
413 // We're fine, just add the new key.
414 status_t result = fData.AddMessage(identifier, &keyMessage);
415 if (result != B_OK)
416 return result;
418 fModified = true;
419 return B_OK;
423 status_t
424 Keyring::RemoveKey(const BString& identifier,
425 const BMessage& keyMessage)
427 if (!fUnlocked)
428 return B_NOT_ALLOWED;
430 int32 count;
431 type_code type;
432 if (fData.GetInfo(identifier, &type, &count) != B_OK)
433 return B_ENTRY_NOT_FOUND;
435 for (int32 i = 0; i < count; i++) {
436 BMessage candidate;
437 if (fData.FindMessage(identifier, i, &candidate) != B_OK)
438 return B_ERROR;
440 // We require an exact match.
441 if (!candidate.HasSameData(keyMessage))
442 continue;
444 status_t result = fData.RemoveData(identifier, i);
445 if (result != B_OK)
446 return result;
448 fModified = true;
449 return B_OK;
452 return B_ENTRY_NOT_FOUND;
457 Keyring::Compare(const Keyring* one, const Keyring* two)
459 return strcmp(one->Name(), two->Name());
464 Keyring::Compare(const BString* name, const Keyring* keyring)
466 return strcmp(name->String(), keyring->Name());
470 status_t
471 Keyring::_EncryptToFlatBuffer()
473 if (!fModified)
474 return B_OK;
476 if (!fUnlocked)
477 return B_NOT_ALLOWED;
479 BMessage container;
480 status_t result = container.AddMessage("data", &fData);
481 if (result != B_OK)
482 return result;
484 result = container.AddMessage("applications", &fApplications);
485 if (result != B_OK)
486 return result;
488 fFlatBuffer.SetSize(0);
489 fFlatBuffer.Seek(0, SEEK_SET);
491 result = container.Flatten(&fFlatBuffer);
492 if (result != B_OK)
493 return result;
495 if (fHasUnlockKey) {
496 // TODO: Actually encrypt the flat buffer...
499 fModified = false;
500 return B_OK;
504 status_t
505 Keyring::_DecryptFromFlatBuffer()
507 if (fFlatBuffer.BufferLength() == 0)
508 return B_OK;
510 if (fHasUnlockKey) {
511 // TODO: Actually decrypt the flat buffer...
514 BMessage container;
515 fFlatBuffer.Seek(0, SEEK_SET);
516 status_t result = container.Unflatten(&fFlatBuffer);
517 if (result != B_OK)
518 return result;
520 result = container.FindMessage("data", &fData);
521 if (result != B_OK)
522 return result;
524 result = container.FindMessage("applications", &fApplications);
525 if (result != B_OK) {
526 fData.MakeEmpty();
527 return result;
530 return B_OK;