HaikuBook: Add documentation for Password and Key Storage API

The current implementation of the keystore_server is not perfect. While the
source has many seeds for a future of having keyrings encrypted, and having
more fine grained permissions, it is far from complete.

The main arguments for adding documentation about this new but incomplete
functionality is that while it is incomplete, the API is part of the public
headers, and there are some legitimate use cases for developers.

The documentation aims to give the proper amount of caution to any developer
that is considering using this API.

Change-Id: I154a3f8374b22dc6929758cba7ba810833bcfe9d
This commit is contained in:
Niels Sascha Reedijk 2020-03-07 22:46:09 +00:00
parent 6a30d84f3c
commit 0e6f95726d
4 changed files with 860 additions and 201 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 Haiku, Inc. All rights reserved.
* Copyright 2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -16,7 +16,11 @@
\ingroup app
\ingroup libbe
\brief Provides BKey and BPasswordKey classes, as well as BKeyPurpose and
BKeyType enums.
BKeyType enums.
See the \link app_keystore overview to the Password and Key Storage API
\endlink for an introduction to the API.
*/
@ -24,58 +28,79 @@
/*!
\enum BKeyPurpose
\brief Undocumented
\enum BKeyPurpose
\brief Descriptive constant for the purpose of the key
\since Haiku R1
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_ANY
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_ANY
\brief Query the key store for keys with any purpose.
\since Haiku R1
This constant does not represent a key purpose by itself, but rather is
used in querying the key store where you do not know or care about the
purpose of key you are looking for.
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_GENERIC
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_GENERIC
\brief Generic key purpose
\since Haiku R1
This type identifies keys that are not for a specific purpose.
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_KEYRING
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_KEYRING
\brief Keyring key purpose
\since Haiku R1
This is a key purpose that is internal to the \c keystore_server. It
represents the internals of a keyring. You cannot directly access and
manipulate keys with this purpose. Instead you can use the methods on
\ref BKeyStore to access keys within keyrings.
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_WEB
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_WEB
\brief Web key purpose
\since Haiku R1
This type refers to keys that are used on the web, such as username and
passwords for HTTP authentication, as well as for stored usernames and
passwords for form-based authentication.
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_NETWORK
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_NETWORK
\brief Network key purpose
\since Haiku R1
This type refers to keys that are used in the networking stack, such as
WEP/WPA keys.
\since Haiku R1
*/
/*!
\var BKeyPurpose::B_KEY_PURPOSE_VOLUME
\brief Undocumented
\var BKeyPurpose::B_KEY_PURPOSE_VOLUME
\brief Volume key purpose
\since Haiku R1
This type refers to keys that are used to lock volumes, like password for
encryption.
\since Haiku R1
*/
@ -83,42 +108,53 @@
/*!
\enum BKeyType
\brief Undocumented
\enum BKeyType
\brief Descriptive constant for the type of a key.
\since Haiku R1
\since Haiku R1
*/
/*!
\var BKeyType::B_KEY_TYPE_ANY
\brief Undocumented
\var BKeyType::B_KEY_TYPE_ANY
\brief Query the key store for keys of any type
\since Haiku R1
This constant does not represent a key type by itself, but rather is
used in querying the key store where you do not know or care about the
type of key you are looking for.
\since Haiku R1
*/
/*!
\var BKeyType::B_KEY_TYPE_GENERIC
\brief Undocumented
\var BKeyType::B_KEY_TYPE_GENERIC
\brief Generic key type.
\since Haiku R1
This constant describes the type of key that does not have any particular
content or format. They are represented by the \ref BKey class.
\since Haiku R1
*/
/*!
\var BKeyType::B_KEY_TYPE_PASSWORD
\brief Undocumented
\var BKeyType::B_KEY_TYPE_PASSWORD
\brief The key is a password.
\since Haiku R1
This key type is represented by the \ref BPasswordKey class.
\since Haiku R1
*/
/*!
\var BKeyType::B_KEY_TYPE_CERTIFICATE
\brief Undocumented
\var BKeyType::B_KEY_TYPE_CERTIFICATE
\brief The key is a certificate. Not in use.
\since Haiku R1
This key type is for future expansion. It is currently not in use.
\since Haiku R1
*/
@ -126,60 +162,101 @@
/*!
\class BKey
\brief Undocumented
\class BKey
\ingroup app
\ingroup libbe
\brief Class that represents a generic key for or from the Haiku key
store
\since Haiku R1
A key has the following properties:
- A key \b type of \ref BKeyType, which identifies the type. For a generic
key (like this key), it will be set to \ref BKeyType::B_KEY_TYPE_GENERIC.
- A key \b purpose of \ref BKeyPurpose, which identifies the purpose of the
key. This is a hint for your (or other) applications on how and where the
key may be used.
- A \b primary \b identifier that identifies a specific key. As an example,
for WPA passwords, this is set to the network name. This should be a
valid UTF-8 string.
- A \b secondary \b identifier that can be used as additional metadata.
- The \b data, the actual value of the key (such as a password or a
certificate). This should be a valid UTF-8 string.
- Not in use: the \b owner identifies who created and/or owns the key.
This feature is not yet enabled. It will always be set to an empty
string.
- Not in use: the \b creation \b time will indicate when a key was stored
in the central database. This feature is not yet enabled, and the value
will always be 0.
\since Haiku R1
*/
/*!
\fn BKey::BKey();
\brief Undocumented
\brief Constructor for an empty generic key.
\since Haiku R1
An empty key has no data associated with it, other than that it has a
generic purpose and a generic key type.
\since Haiku R1
*/
/*!
\fn BKey::BKey(BKeyPurpose purpose, const char* identifier,
const char* secondaryIdentifier = NULL, const uint8* data = NULL,
const char* secondaryIdentifier = NULL, const uint8* data = NULL,
size_t length = 0)
\brief Undocumented
\brief Constructor for a generic key with the provided data.
\since Haiku R1
See the class introduction for more information about the properties of
a key. As you can see, the only required parameters are the \a purpose
and the \a identifier. Any data you provide will be copied into the BKey
object.
\param purpose The purpose of this key
\param identifier A unique identifier for this key
\param secondaryIdentifier An (optional) secondary identifier for this key
\param data A pointer to a buffer that contains the value of the key, such
as the password or the certificate data.
\param length The length of the data in bytes that should be copied.
\since Haiku R1
*/
/*!
\fn BKey::BKey(BKey& other)
\brief Undocumented
\brief Copy constructor that makes a copy of an \a other BKey.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual BKey::~BKey()
\brief Undocumented
\brief Free all resources associated with this key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual BKeyType BKey::Type() const
\brief Undocumented
\brief Returns the type of key.
\since Haiku R1
For a generic BKey, this will always be \ref BKeyType::B_KEY_TYPE_GENERIC
\since Haiku R1
*/
/*!
\fn void BKey::Unset()
\brief Undocumented
\brief Reset the values of the key.
\since Haiku R1
All properties of the key will be reset, except for the identifying owner.
\since Haiku R1
*/
@ -187,236 +264,316 @@
\fn status_t BKey::SetTo(BKeyPurpose purpose, const char* identifier,
const char* secondaryIdentifier = NULL, const uint8* data = NULL,
size_t length = 0)
\brief Undocumented
\brief Set the key to the specified values.
\since Haiku R1
All properties of the key will be set to the parameters. If the key had a
creation time set, it will be cleared. If there was an owner set, this
piece of information will \em not be cleared.
\param purpose The purpose of this key
\param identifier A unique identifier for this key
\param secondaryIdentifier An (optional) secondary identifier for this key
\param data A pointer to a buffer that contains the value of the key, such
as the password or the certificate data.
\param length The length of the data in bytes that should be copied.
\returns
- \c B_OK if the changes were successful.
- \c B_NO_MEMORY in case it fails to allocate memory.
\since Haiku R1
*/
/*!
\fn void BKey::SetPurpose(BKeyPurpose purpose)
\brief Undocumented
\brief Set the purpose of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn BKeyPurpose BKey::Purpose() const
\brief Undocumented
\brief Get the purpose of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn void BKey::SetIdentifier(const char* identifier)
\brief Undocumented
\brief Set the identifier of the key.
\since Haiku R1
\param identifier A pointer to a valid UTF-8 string.
\since Haiku R1
*/
/*!
\fn const char* BKey::Identifier() const
\brief Undocumented
\brief Get the identifier of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn void BKey::SetSecondaryIdentifier(const char* identifier)
\brief Undocumented
\brief Set the secondary identifier of the key.
\since Haiku R1
\param identifier A pointer to a valid UTF-8 string.
\since Haiku R1
*/
/*!
\fn const char* BKey::SecondaryIdentifier() const
\brief Undocumented
\brief Get the secondary identifier of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn status_t BKey::SetData(const uint8* data, size_t length)
\brief Undocumented
\brief Set the data for the key.
\since Haiku R1
\param data A pointer to the buffer that contains the data of the key.
\param length The length in bytes of the data.
\returns
- \c B_OK if the key data was updated.
- \c B_NO_MEMORY in case it fails to allocate memory.
\since Haiku R1
*/
/*!
\fn size_t BKey::DataLength() const
\brief Undocumented
\brief Get the size of the key in bytes.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn const uint8* BKey::Data() const
\brief Undocumented
\brief Get a pointer to the data of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn status_t BKey::GetData(uint8* buffer, size_t bufferSize) const
\brief Undocumented
\brief Copy the key into the \a buffer.
\since Haiku R1
It is up to you to make sure the size of the buffer is the actual size of
the key's data. If the provided buffer is smaller, only the \a bufferSize
will be copied. If the buffer is larger, the key is copied, but the rest
of the buffer will not be touched.
\param[out] buffer The buffer to copy the key to.
\param[in] bufferSize The size of the provided \a buffer.
\returns
- \c B_OK if the data is sucessfully copied.
- An other error code if there was an issue copying the data.
\since Haiku R1
*/
/*!
\fn const char* BKey::Owner() const
\brief Undocumented
\brief Get the owner of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn bigtime_t BKey::CreationTime() const
\brief Undocumented
\brief Get the creation time of the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual status_t BKey::Flatten(BMessage& message) const
\brief Undocumented
\brief Flatten the key into a \a message.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual status_t BKey::Unflatten(const BMessage& message)
\brief Undocumented
\brief Unflatten the key from a \a message.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn BKey& BKey::operator=(const BKey& other)
\brief Undocumented
\brief Copy the data from the \a other key into this key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn bool BKey::operator==(const BKey& other) const
\brief Undocumented
\brief Compare this key to an \a other key.
\since Haiku R1
\returns \c true if all the properties in both keys are identical.
\since Haiku R1
*/
/*!
\fn bool BKey::operator!=(const BKey& other) const
\brief Undocumented
\brief Compare this key to an \a other key.
\since Haiku R1
\returns \c true if any of the properties in this key differ from \a other.
\since Haiku R1
*/
/*!
\fn virtual void BKey::PrintToStream();
\brief Undocumented
\fn virtual void BKey::PrintToStream()
\brief Dump the contents of the key to standard output.
\since Haiku R1
This is a debug function that helps you read the contents of the key. All
properties, except for the actual \c data of the key, will be printed to
\c stdout.
\since Haiku R1
*/
///// BPasswordKey class /////
/*!
\class BPasswordKey
\brief Undocumented
\class BPasswordKey
\ingroup app
\ingroup libbe
\brief Class that represents a password for or from the Haiku key store.
\since Haiku R1
This is a specialized version of the BKey class, which represents a key of
the \ref BKeyType::B_KEY_TYPE_PASSWORD.
\since Haiku R1
*/
/*!
\fn BPasswordKey::BPasswordKey()
\brief Undocumented
\brief Constructor for an empty password key.
\since Haiku R1
An empty key has no data associated with it, other than that it has a
generic purpose and a password key type.
\since Haiku R1
*/
/*!
\fn BPasswordKey::BPasswordKey(const char* password, BKeyPurpose purpose,
const char* identifier, const char* secondaryIdentifier = NULL)
\brief Undocumented
const char* identifier, const char* secondaryIdentifier = NULL)
\brief Constructor for a password key with the provided data.
\since Haiku R1
See the BKey introduction for more information about the properties of
a key. As you can see, the only required parameters are the \a purpose
and the \a identifier. Any data you provide will be copied into the BKey
object.
\param password A null-terminated string that contains the password
\param purpose The purpose of this key
\param identifier A unique identifier for this key
\param secondaryIdentifier An (optional) secondary identifier for this key
\since Haiku R1
*/
/*!
\fn BPasswordKey::BPasswordKey(BPasswordKey& other)
\brief Undocumented
\brief Copy constructor that makes a copy of an \a other BPasswordKey.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual BPasswordKey::~BPasswordKey()
\brief Undocumented
\brief Free all resources associated with this key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual BKeyType BPasswordKey::Type() const
\brief Undocumented
\brief Returns \ref BKeyType::B_KEY_TYPE_PASSWORD.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn status_t BPasswordKey::SetTo(const char* password, BKeyPurpose purpose,
const char* identifier, const char* secondaryIdentifier = NULL)
\brief Undocumented
\brief Set the key to specific values.
\since Haiku R1
All properties of the key will be set to the parameters. If the key had a
creation time set, it will be cleared. If there was an owner set, this
piece of information will \em not be cleared.
\param password A null-terminated string that contains the password
\param purpose The purpose of this key
\param identifier A unique identifier for this key
\param secondaryIdentifier An (optional) secondary identifier for this key
\returns
- \c B_OK if the changes were successful.
- \c B_NO_MEMORY in case it fails to allocate memory.
\since Haiku R1
*/
/*!
\fn status_t BPasswordKey::SetPassword(const char* password)
\brief Undocumented
\brief Set the \a password for this key.
\since Haiku R1
\param password A null-terminated string that contains the password.
\since Haiku R1
*/
/*!
\fn const char* BPasswordKey::Password() const
\brief Undocumented
\brief Get the password for the key.
\since Haiku R1
\since Haiku R1
*/
/*!
\fn virtual void BPasswordKey::PrintToStream()
\brief Undocumented
\brief Dump the contents of the key to standard output.
\since Haiku R1
This is a debug function that helps you read the contents of the key. All
properties, including the actual \b password, will be printed to \c stdout.
\since Haiku R1
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 Haiku, Inc. All rights reserved.
* Copyright 2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -16,6 +16,9 @@
\ingroup app
\ingroup libbe
\brief Provides BKeyStore class.
See the \link app_keystore overview to the Password and Key Storage API
\endlink for an introduction to the API.
*/
@ -23,25 +26,52 @@
\class BKeyStore
\ingroup app
\ingroup libbe
\brief Undocumented
\brief The BKeyStore lets you query, retrieve and store keys in the
system's key store.
\since Haiku R1
Instances of this object give you an easy API to interact with the system's
\c keystore_server. This is the central service that manages storing and
retrieving keys, as well as managing the authorizations that a user grants
to individual applications.
It is important to note that all calls on this object operate
\b synchronously. This means that it should not be used during the event
loop of a visible \ref BWindow, as this may cause drawing and interaction
issues.
All operations are performed in the context of a keyring. All systems have
at least the \b Master \b keyring. Many of the methods take the name of the
keyring as its first argument. Most of the methods in this class have an
overloaded variant that operate on the Master keyring. If you want to
access this keyring through the normal methods, pass an empty string as the
identifier to the method.
See the \link app_keystore overview to the Password and Key Storage API
\endlink for an introduction to the API.
\since Haiku R1
*/
/*!
\fn BKeyStore::BKeyStore()
\brief undocumented
\fn BKeyStore::BKeyStore()
\brief Create a new BKeyStore object that you can use to query, retrieve
and store keys in the system's key store.
\since Haiku R1
This is a cheap object to make, as it has no data associated with it. The
recommended use is to create an instance on the stack whenever you want to
interact with the API.
\since Haiku R1
*/
/*!
\fn virtual BKeyStore::~BKeyStore()
\brief undocumented
\fn virtual BKeyStore::~BKeyStore()
\brief Free all resources.
\since Haiku R1
\since Haiku R1
*/
/*!
@ -53,20 +83,30 @@
/*!
\fn status_t BKeyStore::GetKey(BKeyType type, const char* identifier,
\fn status_t BKeyStore::GetKey(BKeyType type, const char* identifier,
BKey& key)
\brief Undocumented
\brief Query the Master keyring for for specific key.
\since Haiku R1
This is a convenience method that calls \ref GetKey(const char* keyring, BKeyType type, const char* identifier, const char* secondaryIdentifier, bool secondaryIdentifierOptional, BKey& key).
It works on the Master \a keyring, and assumes an empty
\a secondaryIdentifier, \a secondaryIdentifierOptional set to \c false.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetKey(BKeyType type, const char* identifier,
const char* secondaryIdentifier, BKey& key)
\brief Undocumented
\brief Query the Master keyring for for specific key.
\since Haiku R1
This is a convenience method that calls \ref GetKey(const char* keyring, BKeyType type, const char* identifier, const char* secondaryIdentifier, bool secondaryIdentifierOptional, BKey& key).
It works on the Master \a keyring, it sets \a secondaryIdentifierOptional
to \c false, meaning it both identifiers are required to match.
\since Haiku R1
*/
@ -74,104 +114,232 @@
\fn status_t BKeyStore::GetKey(BKeyType type, const char* identifier,
const char* secondaryIdentifier, bool secondaryIdentifierOptional,
BKey& key)
\brief Undocumented
\brief Query the Master keyring for for specific key.
\since Haiku R1
This is a convenience method that calls \ref GetKey(const char* keyring, BKeyType type, const char* identifier, const char* secondaryIdentifier, bool secondaryIdentifierOptional, BKey& key).
It works on the Master \a keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetKey(const char* keyring, BKeyType type,
const char* identifier, BKey& key)
\brief Undocumented
const char* identifier, BKey& key)
\brief Query a certain \a keyring for for specific key.
\since Haiku R1
This is a convenience method that calls \ref GetKey(const char* keyring, BKeyType type, const char* identifier, const char* secondaryIdentifier, bool secondaryIdentifierOptional, BKey& key).
The call assumes an empty \a secondaryIdentifier, and sets
\a secondaryIdentifierOptional to \c false.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetKey(const char* keyring, BKeyType type,
const char* identifier, const char* secondaryIdentifier, BKey& key)
\brief Undocumented
const char* identifier, const char* secondaryIdentifier, BKey& key)
\brief Query a certain \a keyring for for specific key.
\since Haiku R1
This is a convenience method that calls \ref GetKey(const char* keyring, BKeyType type, const char* identifier, const char* secondaryIdentifier, bool secondaryIdentifierOptional, BKey& key).
It sets \a secondaryIdentifierOptional to \c false, meaning it both
identifiers are required to match.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetKey(const char* keyring, BKeyType type,
const char* identifier, const char* secondaryIdentifier,
const char* identifier, const char* secondaryIdentifier,
bool secondaryIdentifierOptional, BKey& key)
\brief Undocumented
\brief Query a certain \a keyring for for specific key.
\since Haiku R1
This variation of the query function is useful when you know that a key has
a secondary identifier, but you may not know it, or care about what it is.
\param[in] keyring A string that identifies the keyring get the key from.
\param[in] type The type of key to match. The type parameter is currently
ignored and therefore does not need to match the actual type of the key
that is stored.
\param[in] identifier The string with the primary identifier of the key that
you are looking for.
\param[in] secondaryIdentifier The string with the secondary identifier of
the key that you are looking for.
\param[in] secondaryIdentifierOptional Use this query parameter to indicate
if the secondary identifier has to match. When set to \a false, a
result will be returned, even if the \a secondaryIdentifer does not
match.
\param[out] key A BKey object to copy the found data to. Any existing data
in the key will be overwritten in case there is a match.
\returns
- \c B_OK in case the key was found and stored in \a key.
- \c B_BAD_VALUE in case the \a keyring does not exist.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_ENTRY_NOT_FOUND in case there is no key that matches the given
identifier(s).
- Any other error that indicates that there was a problem communicating
with the \c keystore_server.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::AddKey(const BKey& key)
\brief Undocumented
\brief Add a \a key to the Master keyring
\since Haiku R1
This is a convenience method that calls
\ref AddKey(const char *, const BKey&) for the \c Master keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::AddKey(const char* keyring, const BKey& key)
\brief Undocumented
\brief Add a \a key to a \a keyring.
\since Haiku R1
This method will send the key to the \c keystore_server and request it to
be stored in the database.
A key needs to have a unique primary and secondary identifier within the
Master keyring.
\param keyring A string that identifies the keyring you want to add the
key to.
\param key The key you want to add.
\returns
- \c B_OK in case the \a key was succesfully added.
- \c B_BAD_VALUE in case the \a keyring does not exist.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_NAME_IN_USE in case there already is another key with the same
primary and secondary identifiers.
- Any other error that indicates that there was a problem communicating
with the \c keystore_server.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::RemoveKey(const BKey& key)
\brief Undocumented
\brief Remove a \a key from the Master keyring.
\since Haiku R1
This is a convenience method that calls
\ref RemoveKey(const char *, const BKey&) for the \c Master keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::RemoveKey(const char* keyring, const BKey& key)
\brief Undocumented
\brief Remove a \a key from a \a keyring.
\since Haiku R1
This method will remove a \a key from a \a keyring. The \a key needs to
match exactly with the key that is in the database of \c keystore_server.
The easiest way to guarantee this, is to use the exact key you find using
GetKey() without making any alterations.
\param keyring A string that identifies the keyring you want to remove
the key from.
\param key The key you want to remove.
\returns
- \c B_OK in case the \a key was succesfully removed.
- \c B_BAD_VALUE in case the \a keyring does not exist.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_ENTRY_NOT_FOUND in case there is no key that matches the given
identifier(s).
- Any other error that indicates that there was a problem communicating
with the \c keystore_server.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextKey(uint32& cookie, BKey& key);
\brief Undocumented
\brief Iterate through the keys of the Master keyring.
\since Haiku R1
This convenience method that calls
\ref GetNextKey(const char*, BKeyType, BKeyPurpose, uint32&, BKey&) for the
Master keyring, with the arguments \ref BKeyType::B_KEY_TYPE_ANY for the
type and \ref BKeyPurpose::B_KEY_PURPOSE_ANY for the purpose.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextKey(BKeyType type, BKeyPurpose purpose,
uint32& cookie, BKey& key)
\brief Undocumented
\brief Iterate through the keys of the Master keyring.
\since Haiku R1
This convenience method calls
\ref GetNextKey(const char*, BKeyType, BKeyPurpose, uint32&, BKey&) for the
Master keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextKey(const char* keyring, uint32& cookie,
BKey& key)
\brief Undocumented
BKey& key)
\brief Iterate through the keys of a \a keyring.
\since Haiku R1
This convenience method calls
\ref GetNextKey(const char*, BKeyType, BKeyPurpose, uint32&, BKey&) with
the arguments \ref BKeyType::B_KEY_TYPE_ANY for the type and
\ref BKeyPurpose::B_KEY_PURPOSE_ANY for the purpose.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextKey(const char* keyring, BKeyType type,
BKeyPurpose purpose, uint32& cookie, BKey& key)
\brief Undocumented
BKeyPurpose purpose, uint32& cookie, BKey& key)
\brief Iterate through keys of a \a keyring.
\since Haiku R1
This method allows you to query through the key store, and iterate through
a list of results of keys that match your query.
\param[in] keyring An UTF-8 string that identifies the keyring
\param[in] type The BKeyType that identifies the type of key you are
looking for. This may be \ref BKeyType::B_KEY_TYPE_ANY if it may be a
key of any type.
\param[in] purpose The BKeyPurpose that indicates the purpose of the key.
This may be \ref BKeyPurpose::B_KEY_PURPOSE_ANY if it may be a key with
any purpose.
\param[out] cookie A cookie that the \c keystore_server uses to keep track
of where you are in the list of keys. When you start the query, set the
initial value to \c 0. After that, pass the cookie to each subsequent
call to progress the iterator.
\param[out] key The key that holds the data. Any existing data in the key
will be overwritten, when a key is found that matches the criteria.
\returns
- \c B_OK in case the next \a key was found.
- \c B_BAD_VALUE in case the \a keyring does not exist.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_ENTRY_NOT_FOUND in case there is no key that matches the given
identifier(s), or if you retrieved the last key.
- Any other error that indicates that there was a problem communicating
with the \c keystore_server.
\since Haiku R1
*/
@ -188,41 +356,73 @@
/*!
\fn status_t BKeyStore::AddKeyring(const char* keyring)
\brief Undocumented
\brief Create a new \a keyring.
\since Haiku R1
\param keyring An UTF-8 string that identifies the keyring you want to
create.
\returns
- \c B_OK if the keyring was succesfully added.
- \c B_NAME_IN_USE if the \a keyring already exists.
- Any other error in case there was an unknown error in the
\c keystore_server, or while communicating to it.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::RemoveKeyring(const char* keyring)
\brief Undocumented
\brief Remove a \a keyring.
\since Haiku R1
\param keyring An UTF-8 string that identifies the keyring you want to
remove.
\returns
- \c B_OK if the keyring was sucessfully removed.
- \c B_ENTRY_NOT_FOUND if the keyring does not exist
- \c B_NOT_ALLOWED when you try to remove the Master keyring.
- Any other error in case there was an unknown error in the
\c keystore_server, or while communicating to it.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextKeyring(uint32& cookie, BString& keyring)
\brief Undocumented
\brief Iterate through the keyrings.
\since Haiku R1
\param[out] cookie A cookie that the \c keystore_server uses to keep track
of where you are in the list of keyrings. When you start the query, set
the initial value to \c 0. After that, pass the cookie to each
subsequent call to progress the iterator.
\param[out] keyring A BString that holds the current name of the keyring.
For each succesful iteration, the existing contents is overwritten.
\returns
- \c B_OK if the iteration was succesful.
- \c B_ENTRY_NOT_FOUND if there are no more keyrings left to iterate
- Any other error in case there was an unknown error in the
\c keystore_server, or while communicating to it.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::SetUnlockKey(const char* keyring, const BKey& key)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
/*!
\fn status_t BKeyStore::RemoveUnlockKey(const char* keyring)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
@ -230,7 +430,7 @@
/*!
\name Master keyring
\name Master keyring (future API)
*/
@ -239,42 +439,48 @@
/*!
\fn status_t BKeyStore::SetMasterUnlockKey(const BKey& key)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
/*!
\fn status_t BKeyStore::RemoveMasterUnlockKey()
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
/*!
\fn status_t BKeyStore::AddKeyringToMaster(const char* keyring)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
\see AddKeyring(const char* keyring)
*/
/*!
\fn status_t BKeyStore::RemoveKeyringFromMaster(const char* keyring)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
\see RemoveKeyring(const char* keyring)
*/
/*!
\fn status_t BKeyStore::GetNextMasterKeyring(uint32& cookie,
BString& keyring)
\brief Undocumented
BString& keyring)
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
\see GetNextKeyring(uint32& cookie, BString& keyring)
*/
@ -282,7 +488,16 @@
/*!
\name Locking
\name Locking (future API)
In the future, locking is part of encrypting and decrypting keyrings.
\note If you are looking at this section because you assume you need to
check that users have the correct permissions, you are in the wrong
place. There is no particular way to determine whether a user has
access granted. Instead, each method of this API will return the error
code \c B_NOT_ALLOWED if the user has not granted access. Use that in
your control flow to determine if you have access.
*/
@ -291,25 +506,25 @@
/*!
\fn bool BKeyStore::IsKeyringUnlocked(const char* keyring)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
/*!
\fn status_t BKeyStore::LockKeyring(const char* keyring)
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
/*!
\fn status_t BKeyStore::LockMasterKeyring()
\brief Undocumented
\brief Not implemented.
\since Haiku R1
This feature is not available in the current release of Haiku.
*/
@ -327,35 +542,82 @@
/*!
\fn status_t BKeyStore::GetNextApplication(uint32& cookie,
BString& signature) const
\brief Undocumented
\brief Iterate through applications that currently have been granted access
to the Master keyring.
\since Haiku R1
This is a convenience method that calls
\ref GetNextApplication(const char* keyring, uint32& cookie,
BString& signature) for the Master \a keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::GetNextApplication(const char* keyring,
uint32& cookie, BString& signature) const
\brief Undocumented
\brief Iterate through applications that currently have been granted access
to the specified \a keyring.
\since Haiku R1
This method allows you to iterate through all applications that the user
has granted access to the \a keyring, whether it is temporarily, or on a
more permanent basis.
\param[in] keyring A UTF-8 string that identifies the keyring that you want
to inspect granted access to.
\param[out] cookie A cookie that the \c keystore_server uses to keep track
of where you are in the list of keys. When you start the query, set the
initial value to \c 0. After that, pass the cookie to each subsequent
call to progress the iterator.
\param[out] signature If a next application is found, the signature will be
stored in this parameter. Any existing string will be overwritten.
\returns
- \c B_OK if the next signature was found succesfully.
- \c B_BAD_VALUE if the keyring does not exist.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_ENTRY_NOT_FOUND if there are no more applications to iterate
through.
- Any other error in case there was an unknown error in the
\c keystore_server, or while communicating to it.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::RemoveApplication(const char* signature)
\brief Undocumented
\brief Remove access for an application to the Master keyring.
\since Haiku R1
This is a convenience method that calls
\ref RemoveApplication(const char *, const char*) for the Master
\a keyring.
\since Haiku R1
*/
/*!
\fn status_t BKeyStore::RemoveApplication(const char* keyring,
const char* signature)
\brief Undocumented
\brief Remove access for an application to a \a keyring.
\since Haiku R1
\param keyring A UTF-8 string that identifies the keyring that you want
to inspect granted access to.
\param signature The signature of the application that you want to revoke
permissions to access the keyring.
\returns
- \c B_OK if the application's access has been revoked.
- \c B_NOT_ALLOWED in case the user did not grant you access right to
this \a keyring.
- \c B_ENTRY_NOT_FOUND if the application did not have access to this
keyring.
- Any other error in case there was an unknown error in the
\c keystore_server, or while communicating to it.
\since Haiku R1
*/
@ -363,7 +625,9 @@
/*!
\name Service Functions
\name Service Functions (future API)
This feature is not available in the current release of Haiku.
*/
@ -373,17 +637,17 @@
/*!
\fn status_t BKeyStore::GeneratePassword(BPasswordKey& password,
size_t length, uint32 flags)
\brief Undocumented
\brief Unimplemented.
\since Haiku R1
This method is currently not implemented.
*/
/*!
\fn float BKeyStore::PasswordStrength(const char* password)
\brief Undocumented
\brief Unimplemented
\since Haiku R1
This method is currently not implemented
*/

View File

@ -0,0 +1,231 @@
/*
* Copyright 2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Niels Sascha Reedijk, niels.reedijk@gmail.com
*/
/*!
\page app_keystore Password and Key Storage API
Haiku R1 introduces the first version of a system-wide key store service,
allows you as developer to outsource some of the credential and certificate
management, as well as providing an infrastructure that enables sharing
these artifacts between applications.
\warning The implementation in Haiku R1 is limited and is a promise of more
to come. Functionality beyond storing and sharing passwords is for the
future. Also please read the security section of this document,
especially when you are working with artifacts that are more sensitive.
In many cases you will find that this system service will work just as
well as making your own implementation, but there are instances in
which you may chose not to use it.
\section app_keystore_overview 1. Highlevel Overview (components)
The implementation is based around the following concepts:
- The \b keystore is the centralized repository for your keys. It is
managed by the \b keystore_server and it contains one or more
\b keyrings.
- A \b keyring is a collection of keys. There is always a
\b master \b keyring, which cannot be removed. Access is organized
around keyrings. From a user's perspective, when an application wants
to access keys in a keyring, the user will have to grant permission to
that application to access the keyring. A keyring is identified by a
name, which needs to be unique on the user's system.
- A keyring contains \b keys. These are the smallest unit in the system.
A key can be anything that you want to safeguard in the keystore. Keys
are identified by the combination of an identifier and a secondary
identifier. These should be unique within a keyring.
- The final piece is the concept of \b permissions. In the current
implementation, an application needs to ask permission to access a
keyring. The \c keystore_server will validate the permissions, and if
necessary prompt the user to grant one-time or a permant access. If the
user only allows it once, access is granted until the application
terminates.
As a user of the API, you will mostly be working with \ref BKeyStore, as
the access point that queries and modifies keyrings and keys. An individual
key is represented by the \ref BKey object.
\section app_keystore_security 2. Security
The current implementation of this API should be considered low-security.
The most important thing to know is that there is \b no \b encryption
applied when storing the keys and keyrings to the drive. This means that
the data can be read by any malicious actor that can access the drive of
your machine.
This should also puts the current locking mechanism in perspective. While
the \c keystore_server will prompt the user to grant (or deny) access to
your application, when it wants to access a keyring, this again does not
prevent any malicious actor to bypass the \c keystore_server and directly
read from (and write to!) the file.
When considering on whether to use the current API, there are a few things
to think about:
- First, consider whether you should store the keys at all. Passwords to
services with extremely sensitive personal or financial information,
such as email passwords or credentials to financial institutions, should
not be stored at all. Prompt your user for the credentials when needed,
and don't keep them for later use.
- Secondly, if you are storing credentials for use with web services,
check if the service you are using supports using access tokens. Many
APIs have them, and often use it in combination with some form of
permission system or scoping, making it possible for you to keep access
as limited as possible. Furthermore, the user often has the ability to
revoke access to a token, in case they think it is compromised.
- When you assess that you really do need to store the credentials, make
a determination first about whether or not the credentials should have
some form of encryption. For now you should consider looking for another
solution to storing sensitive data, but contributions to improve this
API are very welcome. It is beyond the scope of this document to discuss
strategies around encryption.
- When you assess the risk is low enough not to employ encryption
strategies, you may consider using this API. It is particularly
recommended if you will be sharing the credentials with more than one
application.
\warning In the end, it is up to you as a developer to be conscious of any
choices you make when it comes to user data, and credentials are no
different. When you decide that the Password and Key API does not fit
your needs, choose a framework or library that does fit your purpose.
\section app_keystore_usage 3. Practical use of the API
Below are two distinct examples on how you may use the API.
\subsection app_keystore_usage_web The Langlaufer Web Browser
We are working on the infamous Langlaufer web browser, and we are adding
a feature where we autocomplete user names and passwords. It is decided to
use the Password and Key Storage API to do our key management. Whenever we
land on a web page with a login screen, we will try to see if we have
credentials for that web page. Part of the requirements is that we support
more than one set of credentials for a web page.
It is decided that the application will store the user credentials in it's
own keyring, as we do not want to interfere with any other keys in the
master key. Additionally, we will use both the primary and secondary
identifier fields. The primary will contain the hostname of the website,
and the secondary will contain the user name.
One final design note is that all the calls to the \c keystore_server are
synchronous, meaning they will block until there is a response back from
the keystore. In the case that a user needs to be prompted for a password,
the call will be blocked until they make a decision. That is why any calls
on \ref BKeyStore should be done on a separate worker thread, instead of
within the logic of a Window.
For clarity, the example below displays the interaction with the
\ref BKeyStore and \ref BKey classes through some utility functions. It is
up to the reader to put that in a separate working thread.
\code{.cpp}
#include <Key.h>
#include <KeyStore.h>
const char *kLanglauferKeyringName = "Langlaufer";
BObjectList<BPasswordKey>
GetKeysForWebsite(const char *baseUrl) {
// There may be more than one match, so we use the iteration methods.
BKeyStore keyStore;
uint32 cookie;
BPasswordKey currentKey;
BObjectList<BPasswordKey> list;
bool next = true;
while(next) {
status_t status = keyStore.GetNextKey(kLanglauferKeyringName,
B_KEY_TYPE_PASSWORD, B_KEY_PURPOSE_WEB, cookie, currentKey);
switch(status) {
case B_OK:
// Try to see if the key matches the website
if (currentKey.Identifier() == baseUrl) {
// Add the item to the list.
list.AddItem(new BPasswordKey(currentKey));
}
break;
case B_BAD_VALUE:
// The keyring does not exist, create it, and end the
// search
CreateKeyring();
next = false;
break;
default:
// Something else went wrong, like the user did not give
// authorization, or we are at the end of the list.
// Bail out the search at this point.
next = false;
break;
}
}
}
return list;
}
void
CreateKeyring() {
BKeyStore keyStore;
// Ignore the return value in the next line, it may fail but that won't
// interrupt the flow of our program.
keyStore.AddKeyring(kLanglauferKeyringName);
}
void
AddOrReplaceKey(const char *baseUrl, const char *user, const char *password) {
BKeyStore keyStore;
BPasswordKey key;
// Fill out the key with existing data, or create new data
if (keyStore.GetKey(kLanglauferKeyringName, B_KEY_TYPE_PASSWORD, baseUrl, user, &key) == B_OK) {
// Remove the existing key
keyStore.RemoveKey(kLanglauferKeyringName, key);
// Update the password
key.SetPassword(password);
} else {
key.SetTo(password, B_KEY_PURPOSE_WEB, user, password);
}
// Store the updated/new key in the keyring
keyStore.AddKey(kLanglauferKeyringName, key);
}
\endcode
\subsection app_keystore_usage_coolwebservice The CoolWebService Tool Suite
We are working on a set of tools that interface with a cool web service.
Instead of building one monolithic application, we make several small tools
with specific jobs for this cool web service. One of the tools does the
authentication, and stores the key in the master keyring on the system. The
other tools use this key to access the API.
Each tool requires the authentication token to be set up properly. That's
why in the \ref BApplication::ReadyToRun() hook we check for the
availability of the key. If it is not available, or it does not work, the
user will be redirected to the authentication tool. The key will be stored
as a password. It will be identified by the identifer "CoolWebService".
\code{.cpp}
void
CoolPushTool::ReadyToRun() {
BKeyStore keyStore;
BPasswordKey key;
if (keyStore.GetKey(B_KEY_TYPE_PASSWORD, "CoolWebService", key) != B_OK) {
// Terminate the application and re-authenticate
...
}
// Extract the key
BString accessToken = key.Password();
// Validate the key, and if succesful, continue
...
}
\endcode
*/

View File

@ -102,9 +102,16 @@
- BApplication
- BClipboard
- BCursor
- BLaunchRoster
- BNotification
- BPropertyInfo
- BRoster
A third special category is the \link app_keystore Password and Key storage
API:\endlink
- BKey
- BKeyStore
\defgroup game Game Kit
\brief The Game Kit provides classes for producing game sounds and