1/* 2 * Copyright 2020 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Niels Sascha Reedijk, niels.reedijk@gmail.com 7 */ 8 9/*! 10 \page app_keystore Password and Key Storage API 11 12 Haiku R1 introduces the first version of a system-wide key store service, 13 allows you as developer to outsource some of the credential and certificate 14 management, as well as providing an infrastructure that enables sharing 15 these artifacts between applications. 16 17 \warning The implementation in Haiku R1 is limited and is a promise of more 18 to come. Functionality beyond storing and sharing passwords is for the 19 future. Also please read the security section of this document, 20 especially when you are working with artifacts that are more sensitive. 21 In many cases you will find that this system service will work just as 22 well as making your own implementation, but there are instances in 23 which you may chose not to use it. 24 25 \section app_keystore_overview 1. Highlevel Overview (components) 26 27 The implementation is based around the following concepts: 28 - The \b keystore is the centralized repository for your keys. It is 29 managed by the \b keystore_server and it contains one or more 30 \b keyrings. 31 - A \b keyring is a collection of keys. There is always a 32 \b master \b keyring, which cannot be removed. Access is organized 33 around keyrings. From a user's perspective, when an application wants 34 to access keys in a keyring, the user will have to grant permission to 35 that application to access the keyring. A keyring is identified by a 36 name, which needs to be unique on the user's system. 37 - A keyring contains \b keys. These are the smallest unit in the system. 38 A key can be anything that you want to safeguard in the keystore. Keys 39 are identified by the combination of an identifier and a secondary 40 identifier. These should be unique within a keyring. 41 - The final piece is the concept of \b permissions. In the current 42 implementation, an application needs to ask permission to access a 43 keyring. The \c keystore_server will validate the permissions, and if 44 necessary prompt the user to grant one-time or a permant access. If the 45 user only allows it once, access is granted until the application 46 terminates. 47 48 As a user of the API, you will mostly be working with \ref BKeyStore, as 49 the access point that queries and modifies keyrings and keys. An individual 50 key is represented by the \ref BKey object. 51 52 \section app_keystore_security 2. Security 53 54 The current implementation of this API should be considered low-security. 55 The most important thing to know is that there is \b no \b encryption 56 applied when storing the keys and keyrings to the drive. This means that 57 the data can be read by any malicious actor that can access the drive of 58 your machine. 59 60 This should also puts the current locking mechanism in perspective. While 61 the \c keystore_server will prompt the user to grant (or deny) access to 62 your application, when it wants to access a keyring, this again does not 63 prevent any malicious actor to bypass the \c keystore_server and directly 64 read from (and write to!) the file. 65 66 When considering on whether to use the current API, there are a few things 67 to think about: 68 - First, consider whether you should store the keys at all. Passwords to 69 services with extremely sensitive personal or financial information, 70 such as email passwords or credentials to financial institutions, should 71 not be stored at all. Prompt your user for the credentials when needed, 72 and don't keep them for later use. 73 - Secondly, if you are storing credentials for use with web services, 74 check if the service you are using supports using access tokens. Many 75 APIs have them, and often use it in combination with some form of 76 permission system or scoping, making it possible for you to keep access 77 as limited as possible. Furthermore, the user often has the ability to 78 revoke access to a token, in case they think it is compromised. 79 - When you assess that you really do need to store the credentials, make 80 a determination first about whether or not the credentials should have 81 some form of encryption. For now you should consider looking for another 82 solution to storing sensitive data, but contributions to improve this 83 API are very welcome. It is beyond the scope of this document to discuss 84 strategies around encryption. 85 - When you assess the risk is low enough not to employ encryption 86 strategies, you may consider using this API. It is particularly 87 recommended if you will be sharing the credentials with more than one 88 application. 89 90 \warning In the end, it is up to you as a developer to be conscious of any 91 choices you make when it comes to user data, and credentials are no 92 different. When you decide that the Password and Key API does not fit 93 your needs, choose a framework or library that does fit your purpose. 94 95 \section app_keystore_usage 3. Practical use of the API 96 97 Below are two distinct examples on how you may use the API. 98 99 \subsection app_keystore_usage_web The Langlaufer Web Browser 100 101 We are working on the infamous Langlaufer web browser, and we are adding 102 a feature where we autocomplete user names and passwords. It is decided to 103 use the Password and Key Storage API to do our key management. Whenever we 104 land on a web page with a login screen, we will try to see if we have 105 credentials for that web page. Part of the requirements is that we support 106 more than one set of credentials for a web page. 107 108 It is decided that the application will store the user credentials in it's 109 own keyring, as we do not want to interfere with any other keys in the 110 master key. Additionally, we will use both the primary and secondary 111 identifier fields. The primary will contain the hostname of the website, 112 and the secondary will contain the user name. 113 114 One final design note is that all the calls to the \c keystore_server are 115 synchronous, meaning they will block until there is a response back from 116 the keystore. In the case that a user needs to be prompted for a password, 117 the call will be blocked until they make a decision. That is why any calls 118 on \ref BKeyStore should be done on a separate worker thread, instead of 119 within the logic of a Window. 120 121 For clarity, the example below displays the interaction with the 122 \ref BKeyStore and \ref BKey classes through some utility functions. It is 123 up to the reader to put that in a separate working thread. 124 125 \code{.cpp} 126 #include <Key.h> 127 #include <KeyStore.h> 128 129 const char *kLanglauferKeyringName = "Langlaufer"; 130 131 BObjectList<BPasswordKey> 132 GetKeysForWebsite(const char *baseUrl) { 133 // There may be more than one match, so we use the iteration methods. 134 BKeyStore keyStore; 135 uint32 cookie; 136 BPasswordKey currentKey; 137 BObjectList<BPasswordKey> list; 138 bool next = true; 139 140 while(next) { 141 status_t status = keyStore.GetNextKey(kLanglauferKeyringName, 142 B_KEY_TYPE_PASSWORD, B_KEY_PURPOSE_WEB, cookie, currentKey); 143 switch(status) { 144 case B_OK: 145 // Try to see if the key matches the website 146 if (currentKey.Identifier() == baseUrl) { 147 // Add the item to the list. 148 list.AddItem(new BPasswordKey(currentKey)); 149 } 150 break; 151 case B_BAD_VALUE: 152 // The keyring does not exist, create it, and end the 153 // search 154 CreateKeyring(); 155 next = false; 156 break; 157 default: 158 // Something else went wrong, like the user did not give 159 // authorization, or we are at the end of the list. 160 // Bail out the search at this point. 161 next = false; 162 break; 163 } 164 } 165 } 166 167 return list; 168 } 169 170 void 171 CreateKeyring() { 172 BKeyStore keyStore; 173 // Ignore the return value in the next line, it may fail but that won't 174 // interrupt the flow of our program. 175 keyStore.AddKeyring(kLanglauferKeyringName); 176 } 177 178 void 179 AddOrReplaceKey(const char *baseUrl, const char *user, const char *password) { 180 BKeyStore keyStore; 181 BPasswordKey key; 182 183 // Fill out the key with existing data, or create new data 184 if (keyStore.GetKey(kLanglauferKeyringName, B_KEY_TYPE_PASSWORD, baseUrl, user, &key) == B_OK) { 185 // Remove the existing key 186 keyStore.RemoveKey(kLanglauferKeyringName, key); 187 // Update the password 188 key.SetPassword(password); 189 } else { 190 key.SetTo(password, B_KEY_PURPOSE_WEB, user, password); 191 } 192 193 // Store the updated/new key in the keyring 194 keyStore.AddKey(kLanglauferKeyringName, key); 195 } 196 \endcode 197 198 \subsection app_keystore_usage_coolwebservice The CoolWebService Tool Suite 199 200 We are working on a set of tools that interface with a cool web service. 201 Instead of building one monolithic application, we make several small tools 202 with specific jobs for this cool web service. One of the tools does the 203 authentication, and stores the key in the master keyring on the system. The 204 other tools use this key to access the API. 205 206 Each tool requires the authentication token to be set up properly. That's 207 why in the \ref BApplication::ReadyToRun() hook we check for the 208 availability of the key. If it is not available, or it does not work, the 209 user will be redirected to the authentication tool. The key will be stored 210 as a password. It will be identified by the identifier "CoolWebService". 211 212 \code{.cpp} 213 void 214 CoolPushTool::ReadyToRun() { 215 BKeyStore keyStore; 216 BPasswordKey key; 217 218 if (keyStore.GetKey(B_KEY_TYPE_PASSWORD, "CoolWebService", key) != B_OK) { 219 // Terminate the application and re-authenticate 220 ... 221 } 222 223 // Extract the key 224 BString accessToken = key.Password(); 225 226 // Validate the key, and if succesful, continue 227 ... 228 } 229 \endcode 230 231*/ 232