2 * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
7 #include "KeyStoreServer.h"
9 #include "AppAccessRequestWindow.h"
10 #include "KeyRequestWindow.h"
13 #include <KeyStoreDefs.h>
15 #include <Directory.h>
17 #include <FindDirectory.h>
27 using namespace BPrivate
;
30 static const char* kMasterKeyringName
= "Master";
31 static const char* kKeyringKeysIdentifier
= "Keyrings";
33 static const uint32 kKeyStoreFormatVersion
= 1;
35 static const uint32 kFlagGetKey
= 0x0001;
36 static const uint32 kFlagEnumerateKeys
= 0x0002;
37 static const uint32 kFlagAddKey
= 0x0004;
38 static const uint32 kFlagRemoveKey
= 0x0008;
39 static const uint32 kFlagAddKeyring
= 0x0010;
40 static const uint32 kFlagRemoveKeyring
= 0x0020;
41 static const uint32 kFlagEnumerateKeyrings
= 0x0040;
42 static const uint32 kFlagSetUnlockKey
= 0x0080;
43 static const uint32 kFlagRemoveUnlockKey
= 0x0100;
44 static const uint32 kFlagAddKeyringsToMaster
= 0x0200;
45 static const uint32 kFlagRemoveKeyringsFromMaster
= 0x0400;
46 static const uint32 kFlagEnumerateMasterKeyrings
= 0x0800;
47 static const uint32 kFlagQueryLockState
= 0x1000;
48 static const uint32 kFlagLockKeyring
= 0x2000;
49 static const uint32 kFlagEnumerateApplications
= 0x4000;
50 static const uint32 kFlagRemoveApplications
= 0x8000;
52 static const uint32 kDefaultAppFlags
= kFlagGetKey
| kFlagEnumerateKeys
53 | kFlagAddKey
| kFlagRemoveKey
| kFlagAddKeyring
| kFlagRemoveKeyring
54 | kFlagEnumerateKeyrings
| kFlagSetUnlockKey
| kFlagRemoveUnlockKey
55 | kFlagAddKeyringsToMaster
| kFlagRemoveKeyringsFromMaster
56 | kFlagEnumerateMasterKeyrings
| kFlagQueryLockState
| kFlagLockKeyring
57 | kFlagEnumerateApplications
| kFlagRemoveApplications
;
60 KeyStoreServer::KeyStoreServer()
62 BApplication(kKeyStoreServerSignature
),
67 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) != B_OK
)
70 BDirectory
settingsDir(path
.Path());
71 path
.Append("system");
72 if (!settingsDir
.Contains(path
.Path()))
73 settingsDir
.CreateDirectory(path
.Path(), NULL
);
75 settingsDir
.SetTo(path
.Path());
76 path
.Append("keystore");
77 if (!settingsDir
.Contains(path
.Path()))
78 settingsDir
.CreateDirectory(path
.Path(), NULL
);
80 settingsDir
.SetTo(path
.Path());
81 path
.Append("keystore_database");
83 fKeyStoreFile
.SetTo(path
.Path(), B_READ_WRITE
84 | (settingsDir
.Contains(path
.Path()) ? 0 : B_CREATE_FILE
));
86 _ReadKeyStoreDatabase();
88 if (fMasterKeyring
== NULL
) {
89 fMasterKeyring
= new(std::nothrow
) Keyring(kMasterKeyringName
);
90 fKeyrings
.BinaryInsert(fMasterKeyring
, &Keyring::Compare
);
95 KeyStoreServer::~KeyStoreServer()
101 KeyStoreServer::MessageReceived(BMessage
* message
)
104 status_t result
= B_UNSUPPORTED
;
105 app_info callingAppInfo
;
107 uint32 accessFlags
= _AccessFlagsFor(message
->what
);
108 if (accessFlags
== 0)
111 if (message
->what
!= 0) {
112 result
= _ResolveCallingApp(*message
, callingAppInfo
);
117 // Resolve the keyring for the relevant messages.
118 Keyring
* keyring
= NULL
;
119 switch (message
->what
) {
120 case KEY_STORE_GET_KEY
:
121 case KEY_STORE_GET_NEXT_KEY
:
122 case KEY_STORE_ADD_KEY
:
123 case KEY_STORE_REMOVE_KEY
:
124 case KEY_STORE_IS_KEYRING_UNLOCKED
:
125 case KEY_STORE_LOCK_KEYRING
:
126 case KEY_STORE_SET_UNLOCK_KEY
:
127 case KEY_STORE_REMOVE_UNLOCK_KEY
:
128 case KEY_STORE_ADD_KEYRING_TO_MASTER
:
129 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER
:
130 case KEY_STORE_GET_NEXT_APPLICATION
:
131 case KEY_STORE_REMOVE_APPLICATION
:
134 if (message
->FindString("keyring", &keyringName
) != B_OK
)
137 keyring
= _FindKeyring(keyringName
);
138 if (keyring
== NULL
) {
139 result
= B_BAD_VALUE
;
141 // So that we don't do anything in the second switch.
145 switch (message
->what
) {
146 case KEY_STORE_GET_KEY
:
147 case KEY_STORE_GET_NEXT_KEY
:
148 case KEY_STORE_ADD_KEY
:
149 case KEY_STORE_REMOVE_KEY
:
150 case KEY_STORE_SET_UNLOCK_KEY
:
151 case KEY_STORE_REMOVE_UNLOCK_KEY
:
152 case KEY_STORE_ADD_KEYRING_TO_MASTER
:
153 case KEY_STORE_GET_NEXT_APPLICATION
:
154 case KEY_STORE_REMOVE_APPLICATION
:
156 // These need keyring access to do anything.
157 while (!keyring
->IsUnlocked()) {
158 status_t unlockResult
= _UnlockKeyring(*keyring
);
159 if (unlockResult
!= B_OK
) {
160 result
= unlockResult
;
166 status_t validateResult
= _ValidateAppAccess(*keyring
,
167 callingAppInfo
, accessFlags
);
168 if (validateResult
!= B_OK
) {
169 result
= validateResult
;
182 switch (message
->what
) {
183 case KEY_STORE_GET_KEY
:
186 if (message
->FindString("identifier", &identifier
) != B_OK
) {
187 result
= B_BAD_VALUE
;
191 bool secondaryIdentifierOptional
;
192 if (message
->FindBool("secondaryIdentifierOptional",
193 &secondaryIdentifierOptional
) != B_OK
) {
194 secondaryIdentifierOptional
= false;
197 BString secondaryIdentifier
;
198 if (message
->FindString("secondaryIdentifier",
199 &secondaryIdentifier
) != B_OK
) {
200 secondaryIdentifier
= "";
201 secondaryIdentifierOptional
= true;
205 result
= keyring
->FindKey(identifier
, secondaryIdentifier
,
206 secondaryIdentifierOptional
, &keyMessage
);
208 reply
.AddMessage("key", &keyMessage
);
213 case KEY_STORE_GET_NEXT_KEY
:
218 if (message
->FindUInt32("type", (uint32
*)&type
) != B_OK
219 || message
->FindUInt32("purpose", (uint32
*)&purpose
) != B_OK
220 || message
->FindUInt32("cookie", &cookie
) != B_OK
) {
221 result
= B_BAD_VALUE
;
226 result
= keyring
->FindKey(type
, purpose
, cookie
, keyMessage
);
227 if (result
== B_OK
) {
229 reply
.AddUInt32("cookie", cookie
);
230 reply
.AddMessage("key", &keyMessage
);
236 case KEY_STORE_ADD_KEY
:
240 if (message
->FindMessage("key", &keyMessage
) != B_OK
241 || keyMessage
.FindString("identifier", &identifier
) != B_OK
) {
242 result
= B_BAD_VALUE
;
246 BString secondaryIdentifier
;
247 if (keyMessage
.FindString("secondaryIdentifier",
248 &secondaryIdentifier
) != B_OK
) {
249 secondaryIdentifier
= "";
252 result
= keyring
->AddKey(identifier
, secondaryIdentifier
, keyMessage
);
254 _WriteKeyStoreDatabase();
259 case KEY_STORE_REMOVE_KEY
:
263 if (message
->FindMessage("key", &keyMessage
) != B_OK
264 || keyMessage
.FindString("identifier", &identifier
) != B_OK
) {
265 result
= B_BAD_VALUE
;
269 result
= keyring
->RemoveKey(identifier
, keyMessage
);
271 _WriteKeyStoreDatabase();
276 case KEY_STORE_ADD_KEYRING
:
280 if (message
->FindString("keyring", &keyring
) != B_OK
) {
281 result
= B_BAD_VALUE
;
285 result
= _AddKeyring(keyring
);
287 _WriteKeyStoreDatabase();
292 case KEY_STORE_REMOVE_KEYRING
:
295 if (message
->FindString("keyring", &keyringName
) != B_OK
)
298 result
= _RemoveKeyring(keyringName
);
300 _WriteKeyStoreDatabase();
305 case KEY_STORE_GET_NEXT_KEYRING
:
308 if (message
->FindUInt32("cookie", &cookie
) != B_OK
) {
309 result
= B_BAD_VALUE
;
313 keyring
= fKeyrings
.ItemAt(cookie
);
314 if (keyring
== NULL
) {
315 result
= B_ENTRY_NOT_FOUND
;
320 reply
.AddUInt32("cookie", cookie
);
321 reply
.AddString("keyring", keyring
->Name());
326 case KEY_STORE_IS_KEYRING_UNLOCKED
:
328 reply
.AddBool("unlocked", keyring
->IsUnlocked());
333 case KEY_STORE_LOCK_KEYRING
:
340 case KEY_STORE_SET_UNLOCK_KEY
:
343 if (message
->FindMessage("key", &keyMessage
) != B_OK
) {
344 result
= B_BAD_VALUE
;
348 result
= keyring
->SetUnlockKey(keyMessage
);
350 _WriteKeyStoreDatabase();
352 // TODO: Update the key in the master if this keyring was added.
356 case KEY_STORE_REMOVE_UNLOCK_KEY
:
358 result
= keyring
->RemoveUnlockKey();
360 _WriteKeyStoreDatabase();
365 case KEY_STORE_ADD_KEYRING_TO_MASTER
:
366 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER
:
368 // We also need access to the master keyring.
369 while (!fMasterKeyring
->IsUnlocked()) {
370 status_t unlockResult
= _UnlockKeyring(*fMasterKeyring
);
371 if (unlockResult
!= B_OK
) {
372 result
= unlockResult
;
378 if (message
->what
== 0)
381 BString secondaryIdentifier
= keyring
->Name();
382 BMessage keyMessage
= keyring
->UnlockKey();
383 keyMessage
.RemoveName("identifier");
384 keyMessage
.AddString("identifier", kKeyringKeysIdentifier
);
385 keyMessage
.RemoveName("secondaryIdentifier");
386 keyMessage
.AddString("secondaryIdentifier", secondaryIdentifier
);
388 switch (message
->what
) {
389 case KEY_STORE_ADD_KEYRING_TO_MASTER
:
390 result
= fMasterKeyring
->AddKey(kKeyringKeysIdentifier
,
391 secondaryIdentifier
, keyMessage
);
394 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER
:
395 result
= fMasterKeyring
->RemoveKey(kKeyringKeysIdentifier
,
401 _WriteKeyStoreDatabase();
406 case KEY_STORE_GET_NEXT_APPLICATION
:
409 if (message
->FindUInt32("cookie", &cookie
) != B_OK
) {
410 result
= B_BAD_VALUE
;
416 result
= keyring
->GetNextApplication(cookie
, signature
, path
);
420 reply
.AddUInt32("cookie", cookie
);
421 reply
.AddString("signature", signature
);
422 reply
.AddString("path", path
);
427 case KEY_STORE_REMOVE_APPLICATION
:
429 const char* signature
= NULL
;
430 const char* path
= NULL
;
432 if (message
->FindString("signature", &signature
) != B_OK
) {
433 result
= B_BAD_VALUE
;
437 if (message
->FindString("path", &path
) != B_OK
)
440 result
= keyring
->RemoveApplication(signature
, path
);
442 _WriteKeyStoreDatabase();
449 // Just the error case from above.
455 printf("unknown message received: %" B_PRIu32
" \"%.4s\"\n",
456 message
->what
, (const char*)&message
->what
);
461 if (message
->IsSourceWaiting()) {
463 reply
.what
= KEY_STORE_SUCCESS
;
465 reply
.what
= KEY_STORE_RESULT
;
466 reply
.AddInt32("result", result
);
469 message
->SendReply(&reply
);
475 KeyStoreServer::_ReadKeyStoreDatabase()
478 status_t result
= keystore
.Unflatten(&fKeyStoreFile
);
479 if (result
!= B_OK
) {
480 printf("failed to read keystore database\n");
481 _WriteKeyStoreDatabase();
482 // Reinitializes the database.
487 BMessage keyringData
;
488 while (keystore
.FindMessage("keyrings", index
++, &keyringData
) == B_OK
) {
489 Keyring
* keyring
= new(std::nothrow
) Keyring();
490 if (keyring
== NULL
) {
491 printf("no memory for allocating keyring\n");
495 status_t result
= keyring
->ReadFromMessage(keyringData
);
496 if (result
!= B_OK
) {
497 printf("failed to read keyring from data\n");
502 if (strcmp(keyring
->Name(), kMasterKeyringName
) == 0)
503 fMasterKeyring
= keyring
;
505 fKeyrings
.BinaryInsert(keyring
, &Keyring::Compare
);
513 KeyStoreServer::_WriteKeyStoreDatabase()
516 keystore
.AddUInt32("format", kKeyStoreFormatVersion
);
518 for (int32 i
= 0; i
< fKeyrings
.CountItems(); i
++) {
519 Keyring
* keyring
= fKeyrings
.ItemAt(i
);
523 BMessage keyringData
;
524 status_t result
= keyring
->WriteToMessage(keyringData
);
528 keystore
.AddMessage("keyrings", &keyringData
);
531 fKeyStoreFile
.SetSize(0);
532 fKeyStoreFile
.Seek(0, SEEK_SET
);
533 return keystore
.Flatten(&fKeyStoreFile
);
538 KeyStoreServer::_AccessFlagsFor(uint32 command
) const
541 case KEY_STORE_GET_KEY
:
543 case KEY_STORE_GET_NEXT_KEY
:
544 return kFlagEnumerateKeys
;
545 case KEY_STORE_ADD_KEY
:
547 case KEY_STORE_REMOVE_KEY
:
548 return kFlagRemoveKey
;
549 case KEY_STORE_ADD_KEYRING
:
550 return kFlagAddKeyring
;
551 case KEY_STORE_REMOVE_KEYRING
:
552 return kFlagRemoveKeyring
;
553 case KEY_STORE_GET_NEXT_KEYRING
:
554 return kFlagEnumerateKeyrings
;
555 case KEY_STORE_SET_UNLOCK_KEY
:
556 return kFlagSetUnlockKey
;
557 case KEY_STORE_REMOVE_UNLOCK_KEY
:
558 return kFlagRemoveUnlockKey
;
559 case KEY_STORE_ADD_KEYRING_TO_MASTER
:
560 return kFlagAddKeyringsToMaster
;
561 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER
:
562 return kFlagRemoveKeyringsFromMaster
;
563 case KEY_STORE_GET_NEXT_MASTER_KEYRING
:
564 return kFlagEnumerateMasterKeyrings
;
565 case KEY_STORE_IS_KEYRING_UNLOCKED
:
566 return kFlagQueryLockState
;
567 case KEY_STORE_LOCK_KEYRING
:
568 return kFlagLockKeyring
;
569 case KEY_STORE_GET_NEXT_APPLICATION
:
570 return kFlagEnumerateApplications
;
571 case KEY_STORE_REMOVE_APPLICATION
:
572 return kFlagRemoveApplications
;
580 KeyStoreServer::_AccessStringFor(uint32 accessFlag
) const
582 switch (accessFlag
) {
584 return "Get keys from the keyring.";
585 case kFlagEnumerateKeys
:
586 return "Enumerate and get keys from the keyring.";
588 return "Add keys to the keyring.";
590 return "Remove keys from the keyring.";
591 case kFlagAddKeyring
:
592 return "Add new keyrings.";
593 case kFlagRemoveKeyring
:
594 return "Remove keyrings.";
595 case kFlagEnumerateKeyrings
:
596 return "Enumerate the available keyrings.";
597 case kFlagSetUnlockKey
:
598 return "Set the unlock key of the keyring.";
599 case kFlagRemoveUnlockKey
:
600 return "Remove the unlock key of the keyring.";
601 case kFlagAddKeyringsToMaster
:
602 return "Add the keyring key to the master keyring.";
603 case kFlagRemoveKeyringsFromMaster
:
604 return "Remove the keyring key from the master keyring.";
605 case kFlagEnumerateMasterKeyrings
:
606 return "Enumerate keyrings added to the master keyring.";
607 case kFlagQueryLockState
:
608 return "Query the lock state of the keyring.";
609 case kFlagLockKeyring
:
610 return "Lock the keyring.";
611 case kFlagEnumerateApplications
:
612 return "Enumerate the applications of the keyring.";
613 case kFlagRemoveApplications
:
614 return "Remove applications from the keyring.";
622 KeyStoreServer::_ResolveCallingApp(const BMessage
& message
,
623 app_info
& callingAppInfo
) const
625 team_id callingTeam
= message
.ReturnAddress().Team();
626 status_t result
= be_roster
->GetRunningAppInfo(callingTeam
,
631 // Do some sanity checks.
632 if (callingAppInfo
.team
!= callingTeam
)
640 KeyStoreServer::_ValidateAppAccess(Keyring
& keyring
, const app_info
& appInfo
,
644 BPath
path(&appInfo
.ref
);
645 status_t result
= keyring
.FindApplication(appInfo
.signature
,
646 path
.Path(), appMessage
);
647 if (result
!= B_OK
&& result
!= B_ENTRY_NOT_FOUND
)
650 // TODO: Implement running image checksum mechanism.
651 BString checksum
= path
.Path();
653 bool appIsNew
= false;
654 bool appWasUpdated
= false;
657 if (result
== B_OK
) {
658 if (appMessage
.FindUInt32("flags", &appFlags
) != B_OK
659 || appMessage
.FindString("checksum", &appSum
) != B_OK
) {
662 } else if (appSum
!= checksum
) {
663 appWasUpdated
= true;
669 if ((accessFlags
& appFlags
) == accessFlags
)
672 const char* accessString
= _AccessStringFor(accessFlags
);
673 bool allowAlways
= false;
674 result
= _RequestAppAccess(keyring
.Name(), appInfo
.signature
, path
.Path(),
675 accessString
, appIsNew
, appWasUpdated
, accessFlags
, allowAlways
);
676 if (result
!= B_OK
|| !allowAlways
)
679 appMessage
.MakeEmpty();
680 appMessage
.AddString("path", path
.Path());
681 appMessage
.AddUInt32("flags", appFlags
| accessFlags
);
682 appMessage
.AddString("checksum", checksum
);
684 keyring
.RemoveApplication(appInfo
.signature
, path
.Path());
685 if (keyring
.AddApplication(appInfo
.signature
, appMessage
) == B_OK
)
686 _WriteKeyStoreDatabase();
693 KeyStoreServer::_RequestAppAccess(const BString
& keyringName
,
694 const char* signature
, const char* path
, const char* accessString
,
695 bool appIsNew
, bool appWasUpdated
, uint32 accessFlags
, bool& allowAlways
)
697 AppAccessRequestWindow
* requestWindow
698 = new(std::nothrow
) AppAccessRequestWindow(keyringName
, signature
, path
,
699 accessString
, appIsNew
, appWasUpdated
);
700 if (requestWindow
== NULL
)
703 return requestWindow
->RequestAppAccess(allowAlways
);
708 KeyStoreServer::_FindKeyring(const BString
& name
)
710 if (name
.IsEmpty() || name
== kMasterKeyringName
)
711 return fMasterKeyring
;
713 return fKeyrings
.BinarySearchByKey(name
, &Keyring::Compare
);
718 KeyStoreServer::_AddKeyring(const BString
& name
)
720 if (_FindKeyring(name
) != NULL
)
721 return B_NAME_IN_USE
;
723 Keyring
* keyring
= new(std::nothrow
) Keyring(name
);
727 if (!fKeyrings
.BinaryInsert(keyring
, &Keyring::Compare
)) {
737 KeyStoreServer::_RemoveKeyring(const BString
& name
)
739 Keyring
* keyring
= _FindKeyring(name
);
741 return B_ENTRY_NOT_FOUND
;
743 if (keyring
== fMasterKeyring
) {
744 // The master keyring can't be removed.
745 return B_NOT_ALLOWED
;
748 return fKeyrings
.RemoveItem(keyring
) ? B_OK
: B_ERROR
;
753 KeyStoreServer::_UnlockKeyring(Keyring
& keyring
)
755 if (!keyring
.HasUnlockKey())
756 return keyring
.Unlock(NULL
);
758 // If we are accessing a keyring that has been added to master access we
759 // get the key from the master keyring and unlock with that.
761 if (&keyring
!= fMasterKeyring
&& fMasterKeyring
->IsUnlocked()) {
762 if (fMasterKeyring
->FindKey(kKeyringKeysIdentifier
, keyring
.Name(),
763 false, &keyMessage
) == B_OK
) {
764 // We found a key for this keyring, try to unlock with it.
765 if (keyring
.Unlock(&keyMessage
) == B_OK
)
770 // No key, we need to request one from the user.
771 status_t result
= _RequestKey(keyring
.Name(), keyMessage
);
775 return keyring
.Unlock(&keyMessage
);
780 KeyStoreServer::_RequestKey(const BString
& keyringName
, BMessage
& keyMessage
)
782 KeyRequestWindow
* requestWindow
= new(std::nothrow
) KeyRequestWindow();
783 if (requestWindow
== NULL
)
786 return requestWindow
->RequestKey(keyringName
, keyMessage
);
791 main(int argc
, char* argv
[])
793 KeyStoreServer
* app
= new(std::nothrow
) KeyStoreServer();